Refactor the support for AffineMap and IntegerSet aliases in the parser into...
authorRiver Riddle <riverriddle@google.com>
Mon, 6 May 2019 17:36:32 +0000 (10:36 -0700)
committerMehdi Amini <joker.eph@gmail.com>
Sat, 11 May 2019 02:22:32 +0000 (19:22 -0700)
      `#` alias `=` attribute-value

    This also allows for dialects to define aliases for attributes in the AsmPrinter. The printer supports two types of attribute aliases, 'direct' and 'kind'.

    * Direct aliases are synonymous with the current support for type aliases, i.e. this maps an alias to a specific instance of an attribute.

    // A direct alias ("foo_str") for the string attribute "foo".
    #foo_str = "foo"

    * Kind aliases generates unique names for all instances of a given attribute kind. The generated aliases are of the form: `alias[0-9]+`.

    // A kind alias ("strattr") for all string attributes could generate.
    #strattr0 = "foo"
    #strattr1 = "bar"
    ...
    #strattrN = "baz"

--

PiperOrigin-RevId: 246851916

mlir/include/mlir/IR/Dialect.h
mlir/lib/IR/AsmPrinter.cpp
mlir/lib/IR/AttributeDetail.h
mlir/lib/Parser/Lexer.cpp
mlir/lib/Parser/Parser.cpp
mlir/test/IR/invalid-affinemap.mlir
mlir/test/IR/invalid.mlir

index f562bb8..6a4fdf7 100644 (file)
@@ -95,15 +95,18 @@ public:
   /// Registered hooks for getting identifier aliases for symbols. The
   /// identifier is used in place of the symbol when printing textual IR.
   ///
-  /// Hook for defining AffineMap aliases.
-  virtual void getAffineMapAliases(
-      SmallVectorImpl<std::pair<StringRef, AffineMap>> &aliases) {}
-  /// Hook for defining IntegerSet aliases.
-  virtual void getIntegerSetAliases(
-      SmallVectorImpl<std::pair<StringRef, IntegerSet>> &aliases) {}
+  /// Hook for defining Attribute kind aliases. This will generate an alias for
+  /// all attributes of the given kind in the form : <alias>[0-9]+. These
+  /// aliases must not contain `.`.
+  virtual void getAttributeKindAliases(
+      SmallVectorImpl<std::pair<unsigned, StringRef>> &aliases) {}
+  /// Hook for defining Attribute aliases. These aliases must not contain `.` or
+  /// end with a numeric digit([0-9]+).
+  virtual void getAttributeAliases(
+      SmallVectorImpl<std::pair<Attribute, StringRef>> &aliases) {}
   /// Hook for defining Type aliases.
   virtual void
-  getTypeAliases(SmallVectorImpl<std::pair<StringRef, Type>> &aliases) {}
+  getTypeAliases(SmallVectorImpl<std::pair<Type, StringRef>> &aliases) {}
 
   /// Verify an attribute from this dialect on the given function. Returns
   /// failure if the verification failed, success otherwise.
index d97b2fc..aeec1ab 100644 (file)
@@ -35,6 +35,7 @@
 #include "mlir/Support/STLExtras.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallString.h"
@@ -79,6 +80,9 @@ static llvm::cl::opt<bool>
 
 namespace {
 class ModuleState {
+  /// A special index constant used for non-kind attribute aliases.
+  static constexpr int kNonAttrKindAlias = -1;
+
 public:
   /// This is the current context if it is knowable, otherwise this is null.
   MLIRContext *const context;
@@ -88,51 +92,68 @@ public:
   // Initializes module state, populating affine map state.
   void initialize(Module *module);
 
-  StringRef getAffineMapAlias(AffineMap affineMap) const {
-    return affineMapToAlias.lookup(affineMap);
-  }
-
-  int getAffineMapId(AffineMap affineMap) const {
-    auto it = affineMapIds.find(affineMap);
-    if (it == affineMapIds.end()) {
-      return -1;
+  Twine getAttributeAlias(Attribute attr) const {
+    auto alias = attrToAlias.find(attr);
+    if (alias == attrToAlias.end())
+      return Twine();
+
+    // Return the alias for this attribute, along with the index if this was
+    // generated by a kind alias.
+    int kindIndex = alias->second.second;
+    return alias->second.first +
+           (kindIndex == kNonAttrKindAlias ? Twine() : Twine(kindIndex));
+  }
+
+  void printAttributeAliases(raw_ostream &os) const {
+    auto printAlias = [&](StringRef alias, Attribute attr, int index) {
+      os << '#' << alias;
+      if (index != kNonAttrKindAlias)
+        os << index;
+      os << " = " << attr << '\n';
+    };
+
+    // Print all of the attribute kind aliases.
+    for (auto &kindAlias : attrKindToAlias) {
+      for (unsigned i = 0, e = kindAlias.second.second.size(); i != e; ++i)
+        printAlias(kindAlias.second.first, kindAlias.second.second[i], i);
+      os << "\n";
     }
-    return it->second;
-  }
-
-  ArrayRef<AffineMap> getAffineMapIds() const { return affineMapsById; }
 
-  StringRef getIntegerSetAlias(IntegerSet integerSet) const {
-    return integerSetToAlias.lookup(integerSet);
-  }
-
-  int getIntegerSetId(IntegerSet integerSet) const {
-    auto it = integerSetIds.find(integerSet);
-    if (it == integerSetIds.end()) {
-      return -1;
+    // In a second pass print all of the remaining attribute aliases that aren't
+    // kind aliases.
+    for (Attribute attr : usedAttributes) {
+      auto alias = attrToAlias.find(attr);
+      if (alias != attrToAlias.end() &&
+          alias->second.second == kNonAttrKindAlias)
+        printAlias(alias->second.first, attr, alias->second.second);
     }
-    return it->second;
   }
 
-  ArrayRef<IntegerSet> getIntegerSetIds() const { return integerSetsById; }
-
   StringRef getTypeAlias(Type ty) const { return typeToAlias.lookup(ty); }
 
-  ArrayRef<Type> getTypeIds() const { return usedTypes.getArrayRef(); }
-
-private:
-  void recordAffineMapReference(AffineMap affineMap) {
-    if (affineMapIds.count(affineMap) == 0) {
-      affineMapIds[affineMap] = affineMapsById.size();
-      affineMapsById.push_back(affineMap);
+  void printTypeAliases(raw_ostream &os) const {
+    for (Type type : usedTypes) {
+      auto alias = typeToAlias.find(type);
+      if (alias != typeToAlias.end())
+        os << '!' << alias->second << " = type " << type << '\n';
     }
   }
 
-  void recordIntegerSetReference(IntegerSet integerSet) {
-    if (integerSetIds.count(integerSet) == 0) {
-      integerSetIds[integerSet] = integerSetsById.size();
-      integerSetsById.push_back(integerSet);
-    }
+private:
+  void recordAttributeReference(Attribute attr) {
+    // Don't recheck attributes that have already been seen or those that
+    // already have an alias.
+    if (!usedAttributes.insert(attr) || attrToAlias.count(attr))
+      return;
+
+    // If this attribute kind has an alias, then record one for this attribute.
+    auto alias = attrKindToAlias.find(static_cast<unsigned>(attr.getKind()));
+    if (alias == attrKindToAlias.end())
+      return;
+    std::pair<StringRef, int> attrAlias(alias->second.first,
+                                        alias->second.second.size());
+    attrToAlias.insert({attr, attrAlias});
+    alias->second.second.push_back(attr);
   }
 
   void recordTypeReference(Type ty) { usedTypes.insert(ty); }
@@ -145,15 +166,23 @@ private:
   // Initialize symbol aliases.
   void initializeSymbolAliases();
 
-  DenseMap<AffineMap, int> affineMapIds;
-  std::vector<AffineMap> affineMapsById;
-  DenseMap<AffineMap, StringRef> affineMapToAlias;
+  /// Set of attributes known to be used within the module.
+  llvm::SetVector<Attribute> usedAttributes;
 
-  DenseMap<IntegerSet, int> integerSetIds;
-  std::vector<IntegerSet> integerSetsById;
-  DenseMap<IntegerSet, StringRef> integerSetToAlias;
+  /// Mapping between attribute and a pair comprised of a base alias name and a
+  /// count suffix. If the suffix is set to -1, it is not displayed.
+  llvm::MapVector<Attribute, std::pair<StringRef, int>> attrToAlias;
 
+  /// Mapping between attribute kind and a pair comprised of a base alias name
+  /// and a unique list of attributes belonging to this kind sorted by location
+  /// seen in the module.
+  llvm::MapVector<unsigned, std::pair<StringRef, std::vector<Attribute>>>
+      attrKindToAlias;
+
+  /// Set of types known to be used within the module.
   llvm::SetVector<Type> usedTypes;
+
+  /// A mapping between a type and a given alias.
   DenseMap<Type, StringRef> typeToAlias;
 };
 } // end anonymous namespace
@@ -169,24 +198,18 @@ void ModuleState::visitType(Type type) {
       visitType(result);
   } else if (auto memref = type.dyn_cast<MemRefType>()) {
     // Visit affine maps in memref type.
-    for (auto map : memref.getAffineMaps()) {
-      recordAffineMapReference(map);
-    }
+    for (auto map : memref.getAffineMaps())
+      recordAttributeReference(AffineMapAttr::get(map));
   } else if (auto vecOrTensor = type.dyn_cast<VectorOrTensorType>()) {
     visitType(vecOrTensor.getElementType());
   }
 }
 
 void ModuleState::visitAttribute(Attribute attr) {
-  if (auto mapAttr = attr.dyn_cast<AffineMapAttr>()) {
-    recordAffineMapReference(mapAttr.getValue());
-  } else if (auto setAttr = attr.dyn_cast<IntegerSetAttr>()) {
-    recordIntegerSetReference(setAttr.getValue());
-  } else if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
-    for (auto elt : arrayAttr.getValue()) {
+  recordAttributeReference(attr);
+  if (auto arrayAttr = attr.dyn_cast<ArrayAttr>())
+    for (auto elt : arrayAttr.getValue())
       visitAttribute(elt);
-    }
-  }
 }
 
 void ModuleState::visitOperation(Operation *op) {
@@ -202,21 +225,14 @@ void ModuleState::visitOperation(Operation *op) {
 }
 
 // Utility to generate a function to register a symbol alias.
-template <typename SymbolsInModuleSetTy, typename SymbolTy>
-static void registerSymbolAlias(StringRef name, SymbolTy sym,
-                                SymbolsInModuleSetTy &symbolsInModuleSet,
-                                llvm::StringSet<> &usedAliases,
-                                DenseMap<SymbolTy, StringRef> &symToAlias) {
+static bool canRegisterAlias(StringRef name, llvm::StringSet<> &usedAliases) {
   assert(!name.empty() && "expected alias name to be non-empty");
-  assert(sym && "expected alias symbol to be non-null");
   // TODO(riverriddle) Assert that the provided alias name can be lexed as
   // an identifier.
 
-  // Check if the symbol is not referenced by the module or the name is
-  // already used by another alias.
-  if (!symbolsInModuleSet.count(sym) || !usedAliases.insert(name).second)
-    return;
-  symToAlias.try_emplace(sym, name);
+  // Check that the alias doesn't contain a '.' character and the name is not
+  // already in use.
+  return !name.contains('.') && usedAliases.insert(name).second;
 }
 
 void ModuleState::initializeSymbolAliases() {
@@ -228,53 +244,76 @@ void ModuleState::initializeSymbolAliases() {
   auto dialects = context->getRegisteredDialects();
 
   // Collect the set of aliases from each dialect.
-  SmallVector<std::pair<StringRef, AffineMap>, 8> affineMapAliases;
-  SmallVector<std::pair<StringRef, IntegerSet>, 8> integerSetAliases;
-  SmallVector<std::pair<StringRef, Type>, 16> typeAliases;
+  SmallVector<std::pair<unsigned, StringRef>, 8> attributeKindAliases;
+  SmallVector<std::pair<Attribute, StringRef>, 8> attributeAliases;
+  SmallVector<std::pair<Type, StringRef>, 16> typeAliases;
+
+  // AffineMap/Integer set have specific kind aliases.
+  attributeKindAliases.emplace_back(
+      static_cast<unsigned>(Attribute::Kind::AffineMap), "map");
+  attributeKindAliases.emplace_back(
+      static_cast<unsigned>(Attribute::Kind::IntegerSet), "set");
+
   for (auto *dialect : dialects) {
-    dialect->getAffineMapAliases(affineMapAliases);
-    dialect->getIntegerSetAliases(integerSetAliases);
+    dialect->getAttributeKindAliases(attributeKindAliases);
+    dialect->getAttributeAliases(attributeAliases);
     dialect->getTypeAliases(typeAliases);
   }
 
-  // Register the affine aliases.
-  // Create a regex for the non-alias names of sets and maps, so that an alias
-  // is not registered with a conflicting name.
-  llvm::Regex reservedAffineNames("(set|map)[0-9]+");
-
-  // AffineMap aliases
-  for (auto &affineAliasPair : affineMapAliases) {
-    if (!reservedAffineNames.match(affineAliasPair.first))
-      registerSymbolAlias(affineAliasPair.first, affineAliasPair.second,
-                          affineMapIds, usedAliases, affineMapToAlias);
+  // Setup the attribute kind aliases.
+  StringRef alias;
+  unsigned attrKind;
+  for (auto &attrAliasPair : attributeKindAliases) {
+    std::tie(attrKind, alias) = attrAliasPair;
+    assert(!alias.empty() && "expected non-empty alias string");
+    if (!usedAliases.count(alias) && !alias.contains('.'))
+      attrKindToAlias.insert({attrKind, {alias, {}}});
   }
 
-  // IntegerSet aliases
-  for (auto &integerSetAliasPair : integerSetAliases) {
-    if (!reservedAffineNames.match(integerSetAliasPair.first))
-      registerSymbolAlias(integerSetAliasPair.first, integerSetAliasPair.second,
-                          integerSetIds, usedAliases, integerSetToAlias);
+  // Clear the set of used identifiers so that the attribute kind aliases are
+  // just a prefix and not the full alias, i.e. there may be some overlap.
+  usedAliases.clear();
+
+  // Register the attribute aliases.
+  // Create a regex for the attribute kind alias names, these have a prefix with
+  // a counter appended to the end. We prevent normal aliases from having these
+  // names to avoid collisions.
+  llvm::Regex reservedAttrNames("[0-9]+$");
+
+  // Attribute value aliases.
+  Attribute attr;
+  for (auto &attrAliasPair : attributeAliases) {
+    std::tie(attr, alias) = attrAliasPair;
+    if (!reservedAttrNames.match(alias) && canRegisterAlias(alias, usedAliases))
+      attrToAlias.insert({attr, {alias, kNonAttrKindAlias}});
   }
 
   // Clear the set of used identifiers as types can have the same identifiers as
   // affine structures.
   usedAliases.clear();
 
+  // Type aliases.
   for (auto &typeAliasPair : typeAliases)
-    registerSymbolAlias(typeAliasPair.first, typeAliasPair.second, usedTypes,
-                        usedAliases, typeToAlias);
+    if (canRegisterAlias(typeAliasPair.second, usedAliases))
+      typeToAlias.insert(typeAliasPair);
 }
 
 // Initializes module state, populating affine map and integer set state.
 void ModuleState::initialize(Module *module) {
+  // Initialize the symbol aliases.
+  initializeSymbolAliases();
+
+  // Walk the module and visit each operation.
   for (auto &fn : *module) {
     visitType(fn.getType());
+    for (auto attr : fn.getAttrs())
+      ModuleState::visitAttribute(attr.second);
+    for (auto attrList : fn.getAllArgAttrs())
+      for (auto attr : attrList.getAttrs())
+        ModuleState::visitAttribute(attr.second);
 
     fn.walk([&](Operation *op) { ModuleState::visitOperation(op); });
   }
-
-  // Initialize the symbol aliases.
-  initializeSymbolAliases();
 }
 
 //===----------------------------------------------------------------------===//
@@ -318,12 +357,6 @@ protected:
   void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
                              ArrayRef<StringRef> elidedAttrs = {});
   void printAttributeOptionalType(Attribute attr, bool includeType);
-  void printAffineMapId(int affineMapId) const;
-  void printAffineMapReference(AffineMap affineMap);
-  void printAffineMapAlias(StringRef alias) const;
-  void printIntegerSetId(int integerSetId) const;
-  void printIntegerSetReference(IntegerSet integerSet);
-  void printIntegerSetAlias(StringRef alias) const;
   void printTrailingLocation(Location loc);
   void printLocationInternal(Location loc, bool pretty = false);
   void printDenseElementsAttr(DenseElementsAttr attr);
@@ -340,58 +373,6 @@ protected:
 };
 } // end anonymous namespace
 
-// Prints affine map identifier.
-void ModulePrinter::printAffineMapId(int affineMapId) const {
-  os << "#map" << affineMapId;
-}
-
-void ModulePrinter::printAffineMapAlias(StringRef alias) const {
-  os << '#' << alias;
-}
-
-void ModulePrinter::printAffineMapReference(AffineMap affineMap) {
-  // Check for an affine map alias.
-  auto alias = state.getAffineMapAlias(affineMap);
-  if (!alias.empty())
-    return printAffineMapAlias(alias);
-
-  int mapId = state.getAffineMapId(affineMap);
-  if (mapId >= 0) {
-    // Map will be printed at top of module so print reference to its id.
-    printAffineMapId(mapId);
-  } else {
-    // Map not in module state so print inline.
-    affineMap.print(os);
-  }
-}
-
-// Prints integer set identifier.
-void ModulePrinter::printIntegerSetId(int integerSetId) const {
-  os << "#set" << integerSetId;
-}
-
-void ModulePrinter::printIntegerSetAlias(StringRef alias) const {
-  os << '#' << alias;
-}
-
-void ModulePrinter::printIntegerSetReference(IntegerSet integerSet) {
-  // Check for an integer set alias.
-  auto alias = state.getIntegerSetAlias(integerSet);
-  if (!alias.empty()) {
-    printIntegerSetAlias(alias);
-    return;
-  }
-
-  int setId;
-  if ((setId = state.getIntegerSetId(integerSet)) >= 0) {
-    // The set will be printed at top of module; so print reference to its id.
-    printIntegerSetId(setId);
-  } else {
-    // Set not in module state so print inline.
-    integerSet.print(os);
-  }
-}
-
 void ModulePrinter::printTrailingLocation(Location loc) {
   // Check to see if we are printing debug information.
   if (!shouldPrintDebugInfoOpt)
@@ -463,31 +444,11 @@ void ModulePrinter::printLocationInternal(Location loc, bool pretty) {
 }
 
 void ModulePrinter::print(Module *module) {
-  for (const auto &map : state.getAffineMapIds()) {
-    StringRef alias = state.getAffineMapAlias(map);
-    if (!alias.empty())
-      printAffineMapAlias(alias);
-    else
-      printAffineMapId(state.getAffineMapId(map));
-    os << " = ";
-    map.print(os);
-    os << '\n';
-  }
-  for (const auto &set : state.getIntegerSetIds()) {
-    StringRef alias = state.getIntegerSetAlias(set);
-    if (!alias.empty())
-      printIntegerSetAlias(alias);
-    else
-      printIntegerSetId(state.getIntegerSetId(set));
-    os << " = ";
-    set.print(os);
-    os << '\n';
-  }
-  for (const auto &type : state.getTypeIds()) {
-    StringRef alias = state.getTypeAlias(type);
-    if (!alias.empty())
-      os << '!' << alias << " = type " << type << '\n';
-  }
+  // Output the aliases at the top level.
+  state.printAttributeAliases(os);
+  state.printTypeAliases(os);
+
+  // Print the module.
   for (auto &fn : *module)
     print(&fn);
 }
@@ -545,6 +506,13 @@ void ModulePrinter::printAttributeOptionalType(Attribute attr,
     return;
   }
 
+  // Check for an alias for this attribute.
+  Twine alias = state.getAttributeAlias(attr);
+  if (!alias.isTriviallyEmpty()) {
+    os << '#' << alias;
+    return;
+  }
+
   switch (attr.getKind()) {
   case Attribute::Kind::Unit:
     os << "unit";
@@ -587,10 +555,10 @@ void ModulePrinter::printAttributeOptionalType(Attribute attr,
     os << ']';
     break;
   case Attribute::Kind::AffineMap:
-    printAffineMapReference(attr.cast<AffineMapAttr>().getValue());
+    attr.cast<AffineMapAttr>().getValue().print(os);
     break;
   case Attribute::Kind::IntegerSet:
-    printIntegerSetReference(attr.cast<IntegerSetAttr>().getValue());
+    attr.cast<IntegerSetAttr>().getValue().print(os);
     break;
   case Attribute::Kind::Type:
     printType(attr.cast<TypeAttr>().getValue());
@@ -889,7 +857,7 @@ void ModulePrinter::printType(Type type) {
     printType(v.getElementType());
     for (auto map : v.getAffineMaps()) {
       os << ", ";
-      printAffineMapReference(map);
+      printAttribute(AffineMapAttr::get(map));
     }
     // Only print the memory space if it is the non-default one.
     if (v.getMemorySpace())
@@ -1303,12 +1271,12 @@ void FunctionPrinter::numberValueID(Value *value) {
       Type type = op->getResult(0)->getType();
       if (auto intCst = cst.dyn_cast<IntegerAttr>()) {
         if (type.isIndex()) {
-          specialName << 'c' << intCst;
+          specialName << 'c' << intCst.getInt();
         } else if (type.cast<IntegerType>().isInteger(1)) {
           // i1 constants get special names.
           specialName << (intCst.getInt() ? "true" : "false");
         } else {
-          specialName << 'c' << intCst << '_' << type;
+          specialName << 'c' << intCst.getInt() << '_' << type;
         }
       } else if (cst.isa<FunctionAttr>()) {
         specialName << 'f';
@@ -1638,7 +1606,7 @@ void ModulePrinter::print(Function *fn) { FunctionPrinter(fn, *this).print(); }
 
 void Attribute::print(raw_ostream &os) const {
   ModuleState state(/*no context is known*/ nullptr);
-  ModulePrinter(os, state).printAttribute(*this);
+  ModulePrinter(os, state).printAttributeAndType(*this);
 }
 
 void Attribute::dump() const {
index 990008b..d1802f4 100644 (file)
@@ -200,7 +200,8 @@ struct ArrayAttributeStorage : public AttributeStorage {
 struct AffineMapAttributeStorage : public AttributeStorage {
   using KeyTy = AffineMap;
 
-  AffineMapAttributeStorage(AffineMap value) : value(value) {}
+  AffineMapAttributeStorage(AffineMap value)
+      : AttributeStorage(IndexType::get(value.getContext())), value(value) {}
 
   /// Key equality function.
   bool operator==(const KeyTy &key) const { return key == value; }
index 59a435e..0c76cca 100644 (file)
@@ -244,7 +244,7 @@ Token Lexer::lexPrefixedIdentifier(const char *tokStart) {
   switch (*tokStart) {
   case '#':
     kind = Token::hash_identifier;
-    errorKind = "invalid affine map name";
+    errorKind = "invalid attribute name";
     break;
   case '%':
     kind = Token::percent_identifier;
index 15807f6..9229236 100644 (file)
@@ -68,11 +68,8 @@ public:
     functionForwardRefs.clear();
   }
 
-  // A map from affine map identifier to AffineMap.
-  llvm::StringMap<AffineMap> affineMapDefinitions;
-
-  // A map from integer set identifier to IntegerSet.
-  llvm::StringMap<IntegerSet> integerSetDefinitions;
+  // A map from attribute alias identifier to Attribute.
+  llvm::StringMap<Attribute> attributeAliasDefinitions;
 
   // A map from type alias identifier to Type.
   llvm::StringMap<Type> typeAliasDefinitions;
@@ -204,8 +201,6 @@ public:
   ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
 
   // Polyhedral structures.
-  AffineMap parseAffineMapReference();
-  IntegerSet parseIntegerSetReference();
   ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map,
                                                   IntegerSet &set);
   DenseElementsAttr parseDenseElementsAttr(VectorOrTensorType type);
@@ -761,10 +756,15 @@ Type Parser::parseMemRefType() {
       // Parse affine map.
       if (parsedMemorySpace)
         return emitError("affine map after memory space in memref type");
-      auto affineMap = parseAffineMapReference();
+      auto affineMap = parseAttribute();
       if (!affineMap)
         return ParseFailure;
-      affineMapComposition.push_back(affineMap);
+
+      // Verify that the parsed attribute is an affine map.
+      if (auto affineMapAttr = affineMap.dyn_cast<AffineMapAttr>())
+        affineMapComposition.push_back(affineMapAttr.getValue());
+      else
+        return emitError("expected affine map in memref type");
     }
     return ParseSuccess;
   };
@@ -1033,6 +1033,25 @@ Function *Parser::resolveFunctionReference(StringRef nameStr, SMLoc nameLoc,
 ///                      (tensor-type | vector-type) `,` hex-string-literal `>`
 ///
 Attribute Parser::parseAttribute(Type type) {
+  // If this is a hash_identifier, we are parsing an attribute alias.
+  if (getToken().is(Token::hash_identifier)) {
+    StringRef id = getTokenSpelling().drop_front();
+    consumeToken(Token::hash_identifier);
+
+    // Check for an alias for this attribute.
+    auto aliasIt = state.attributeAliasDefinitions.find(id);
+    if (aliasIt == state.attributeAliasDefinitions.end())
+      return (emitError("undefined attribute alias id '" + id + "'"), nullptr);
+
+    // Ensure that the attribute alias has the same type as requested.
+    if (type && aliasIt->second.getType() != type) {
+      emitError("requested attribute type different then alias attribute type");
+      return nullptr;
+    }
+
+    return aliasIt->second;
+  }
+
   switch (getToken().getKind()) {
   case Token::kw_unit:
     consumeToken(Token::kw_unit);
@@ -1162,7 +1181,6 @@ Attribute Parser::parseAttribute(Type type) {
       return nullptr;
     return builder.getArrayAttr(elements);
   }
-  case Token::hash_identifier:
   case Token::l_paren: {
     // Try to parse an affine map or an integer set reference.
     AffineMap map;
@@ -2071,8 +2089,8 @@ AffineParser::parseDimAndOptionalSymbolIdList(unsigned &numDims,
 
 /// Parses an affine map definition inline.
 ///
-///  affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
-///                        (`size` `(` dim-size (`,` dim-size)* `)`)?
+///  affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
+///                 (`size` `(` dim-size (`,` dim-size)* `)`)?
 ///  dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
 ///
 ///  multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
@@ -2095,9 +2113,7 @@ AffineMap AffineParser::parseAffineMapInline() {
 
 /// Parses an integer set definition inline.
 ///
-///  integer-set-inline
-///                ::= dim-and-symbol-id-lists `:`
-///                affine-constraint-conjunction
+///  integer-set ::= dim-and-symbol-id-lists `:` affine-constraint-conjunction
 ///  affine-constraint-conjunction ::= /*empty*/
 ///                                 | affine-constraint (`,`
 ///                                 affine-constraint)*
@@ -2149,8 +2165,8 @@ ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map,
 
 /// Parse the range and sizes affine map definition inline.
 ///
-///  affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
-///                        (`size` `(` dim-size (`,` dim-size)* `)`)?
+///  affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
+///                 (`size` `(` dim-size (`,` dim-size)* `)`)?
 ///  dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
 ///
 ///  multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
@@ -2212,77 +2228,10 @@ AffineMap AffineParser::parseAffineMapRange(unsigned numDims,
   return builder.getAffineMap(numDims, numSymbols, exprs, rangeSizes);
 }
 
-/// Parse a reference to an integer set.
-///  integer-set ::= integer-set-id | integer-set-inline
-///  integer-set-id ::= `#` suffix-id
-///
-IntegerSet Parser::parseIntegerSetReference() {
-  if (getToken().isNot(Token::hash_identifier)) {
-    // Try to parse inline integer set.
-    return AffineParser(state).parseIntegerSetInline();
-  }
-
-  // Parse integer set identifier and verify that it exists.
-  StringRef id = getTokenSpelling().drop_front();
-  if (getState().integerSetDefinitions.count(id) > 0) {
-    consumeToken(Token::hash_identifier);
-    return getState().integerSetDefinitions[id];
-  }
-
-  // The id isn't among any of the recorded definitions.
-  emitError("undefined integer set id '" + id + "'");
-  return IntegerSet();
-}
-
-/// Parse a reference to an affine map.
-///  affine-map ::= affine-map-id | affine-map-inline
-///  affine-map-id ::= `#` suffix-id
-///
-AffineMap Parser::parseAffineMapReference() {
-  if (getToken().isNot(Token::hash_identifier)) {
-    // Try to parse inline affine map.
-    return AffineParser(state).parseAffineMapInline();
-  }
-
-  // Parse affine map identifier and verify that it exists.
-  StringRef id = getTokenSpelling().drop_front();
-  if (getState().affineMapDefinitions.count(id) > 0) {
-    consumeToken(Token::hash_identifier);
-    return getState().affineMapDefinitions[id];
-  }
-
-  // The id isn't among any of the recorded definitions.
-  emitError("undefined affine map id '" + id + "'");
-  return AffineMap();
-}
-
 /// Parse an ambiguous reference to either and affine map or an integer set.
 ParseResult Parser::parseAffineMapOrIntegerSetReference(AffineMap &map,
                                                         IntegerSet &set) {
-  if (getToken().isNot(Token::hash_identifier)) {
-    // Try to parse inline affine map.
-    return AffineParser(state).parseAffineMapOrIntegerSetInline(map, set);
-  }
-
-  // Parse affine map / integer set identifier and verify that it exists.
-  // Note that an id can't be in both affineMapDefinitions and
-  // integerSetDefinitions since they use the same sigil '#'.
-  StringRef id = getTokenSpelling().drop_front();
-  if (getState().affineMapDefinitions.count(id) > 0) {
-    consumeToken(Token::hash_identifier);
-    map = getState().affineMapDefinitions[id];
-    return ParseSuccess;
-  }
-  if (getState().integerSetDefinitions.count(id) > 0) {
-    consumeToken(Token::hash_identifier);
-    set = getState().integerSetDefinitions[id];
-    return ParseSuccess;
-  }
-
-  // The id isn't among any of the recorded definitions.
-  emitError("undefined affine map or integer set id '" + id + "'");
-
-  return ParseFailure;
+  return AffineParser(state).parseAffineMapOrIntegerSetInline(map, set);
 }
 
 //===----------------------------------------------------------------------===//
@@ -3601,7 +3550,7 @@ public:
 private:
   ParseResult finalizeModule();
 
-  ParseResult parseAffineStructureDef();
+  ParseResult parseAttributeAliasDef();
 
   ParseResult parseTypeAliasDef();
 
@@ -3617,48 +3566,31 @@ private:
 };
 } // end anonymous namespace
 
-/// Parses either an affine map declaration or an integer set declaration.
-///
-/// Affine map declaration.
+/// Parses an attribute alias declaration.
 ///
-///   affine-map-def ::= affine-map-id `=` affine-map-inline
+///   attribute-alias-def ::= '#' alias-name `=` attribute-value
 ///
-/// Integer set declaration.
-///
-///  integer-set-decl ::= integer-set-id `=` integer-set-inline
-///
-ParseResult ModuleParser::parseAffineStructureDef() {
+ParseResult ModuleParser::parseAttributeAliasDef() {
   assert(getToken().is(Token::hash_identifier));
 
-  StringRef affineStructureId = getTokenSpelling().drop_front();
+  StringRef attrId = getTokenSpelling().drop_front();
 
   // Check for redefinitions.
-  if (getState().affineMapDefinitions.count(affineStructureId) > 0)
-    return emitError("redefinition of affine map id '" + affineStructureId +
-                     "'");
-  if (getState().integerSetDefinitions.count(affineStructureId) > 0)
-    return emitError("redefinition of integer set id '" + affineStructureId +
-                     "'");
+  if (getState().attributeAliasDefinitions.count(attrId) > 0)
+    return emitError("redefinition of attribute alias id '" + attrId + "'");
 
   consumeToken(Token::hash_identifier);
 
   // Parse the '='
-  if (parseToken(Token::equal,
-                 "expected '=' in affine map outlined definition"))
+  if (parseToken(Token::equal, "expected '=' in attribute alias definition"))
     return ParseFailure;
 
-  AffineMap map;
-  IntegerSet set;
-  if (AffineParser(getState()).parseAffineMapOrIntegerSetInline(map, set))
+  // Parse the attribute value.
+  Attribute attr = parseAttribute();
+  if (!attr)
     return ParseFailure;
 
-  if (map) {
-    getState().affineMapDefinitions[affineStructureId] = map;
-    return ParseSuccess;
-  }
-
-  assert(set);
-  getState().integerSetDefinitions[affineStructureId] = set;
+  getState().attributeAliasDefinitions[attrId] = attr;
   return ParseSuccess;
 }
 
@@ -3853,7 +3785,6 @@ ParseResult ModuleParser::parseFunc() {
 /// Finish the end of module parsing - when the result is valid, do final
 /// checking.
 ParseResult ModuleParser::finalizeModule() {
-
   // Resolve all forward references, building a remapping table of attributes.
   DenseMap<Attribute, FunctionAttr> remappingTable;
   for (auto forwardRef : getState().functionForwardRefs) {
@@ -3906,7 +3837,7 @@ ParseResult ModuleParser::parseModule() {
       return ParseFailure;
 
     case Token::hash_identifier:
-      if (parseAffineStructureDef())
+      if (parseAttributeAliasDef())
         return ParseFailure;
       break;
 
index b70bb7a..f48ec3a 100644 (file)
@@ -14,7 +14,7 @@
 #hello_world = (i, j) -> (, j) // expected-error {{expected affine expression}}
 
 // -----
-#hello_world (i, j) [s0] -> (i, j) // expected-error {{expected '=' in affine map outlined definition}}
+#hello_world (i, j) [s0] -> (i, j) // expected-error {{expected '=' in attribute alias definition}}
 
 // -----
 #hello_world = (i, j) [s0] -> (2*i*, 3*j*i*2 + 5) // expected-error {{missing right operand of binary op}}
 
 // -----
 #ABC = (i,j) -> (i+j)
-#ABC = (i,j) -> (i+j)  // expected-error {{redefinition of affine map id 'ABC'}}
+#ABC = (i,j) -> (i+j)  // expected-error {{redefinition of attribute alias id 'ABC'}}
index efb5217..1288fe0 100644 (file)
@@ -34,17 +34,17 @@ func @memrefs(memref<2x4xi8, >) // expected-error {{expected list element}}
 
 // -----
 // Test non-existent map in memref type.
-func @memrefs(memref<2x4xi8, #map7>) // expected-error {{undefined affine map id 'map7'}}
+func @memrefs(memref<2x4xi8, #map7>) // expected-error {{undefined attribute alias id 'map7'}}
 
 // -----
-// Test non hash identifier in memref type.
-func @memrefs(memref<2x4xi8, %map7>) // expected-error {{expected '(' at start of dimensional identifiers list}}
+// Test non affine map in memref type.
+func @memrefs(memref<2x4xi8, i8>) // expected-error {{expected affine map in memref type}}
 
 // -----
 // Test non-existent map in map composition of memref type.
 #map0 = (d0, d1) -> (d0, d1)
 
-func @memrefs(memref<2x4xi8, #map0, #map8>) // expected-error {{undefined affine map id 'map8'}}
+func @memrefs(memref<2x4xi8, #map0, #map8>) // expected-error {{undefined attribute alias id 'map8'}}
 
 // -----
 // Test multiple memory space error.