[Mlir-commits] [mlir] a463ea5 - [mlir][ASM] Refactor how attribute/type aliases are specified.

River Riddle llvmlistbot at llvm.org
Fri Oct 30 00:40:10 PDT 2020


Author: River Riddle
Date: 2020-10-30T00:39:46-07:00
New Revision: a463ea50a4d6d256d91778ec0b40bc6ed6f303f7

URL: https://github.com/llvm/llvm-project/commit/a463ea50a4d6d256d91778ec0b40bc6ed6f303f7
DIFF: https://github.com/llvm/llvm-project/commit/a463ea50a4d6d256d91778ec0b40bc6ed6f303f7.diff

LOG: [mlir][ASM] Refactor how attribute/type aliases are specified.

Previously they were separated into "instance" and "kind" aliases, and also required that the dialect know ahead of time all of the instances that would have a corresponding alias. This approach was very clunky and not ergonomic to interact with. The new approach is to provide the dialect with an instance  of an attribute/type to provide an alias for, fully replacing the original split approach.

Differential Revision: https://reviews.llvm.org/D89354

Added: 
    mlir/test/IR/print-attr-type-aliases.mlir

Modified: 
    mlir/include/mlir/IR/OpImplementation.h
    mlir/lib/IR/AsmPrinter.cpp
    mlir/lib/IR/MLIRContext.cpp
    mlir/test/Dialect/Affine/affine-loop-invariant-code-motion.mlir
    mlir/test/Dialect/Affine/canonicalize.mlir
    mlir/test/Dialect/Affine/ops.mlir
    mlir/test/Dialect/SCF/for-loop-specialization.mlir
    mlir/test/Dialect/SCF/parallel-loop-tiling.mlir
    mlir/test/IR/memory-ops.mlir
    mlir/test/Transforms/loop-fusion.mlir
    mlir/test/Transforms/loop-invariant-code-motion.mlir
    mlir/test/lib/Dialect/Test/TestDialect.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index a30ffd8f75b4..a4e222257e94 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -801,21 +801,17 @@ class OpAsmDialectInterface
 public:
   OpAsmDialectInterface(Dialect *dialect) : Base(dialect) {}
 
-  /// Hooks for getting identifier aliases for symbols. The identifier is used
-  /// in place of the symbol when printing textual IR.
-  ///
-  /// 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<TypeID, StringRef>> &aliases) const {}
-  /// 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) const {}
-  /// Hook for defining Type aliases.
-  virtual void
-  getTypeAliases(SmallVectorImpl<std::pair<Type, StringRef>> &aliases) const {}
+  /// Hooks for getting an alias identifier alias for a given symbol, that is
+  /// not necessarily a part of this dialect. The identifier is used in place of
+  /// the symbol when printing textual IR. These aliases must not contain `.` or
+  /// end with a numeric digit([0-9]+). Returns success if an alias was
+  /// provided, failure otherwise.
+  virtual LogicalResult getAlias(Attribute attr, raw_ostream &os) const {
+    return failure();
+  }
+  virtual LogicalResult getAlias(Type type, raw_ostream &os) const {
+    return failure();
+  }
 
   /// Get a special name to use when printing the given operation. See
   /// OpAsmInterface.td#getAsmResultNames for usage details and documentation.

diff  --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index aa221fa37dbd..790b50cebd38 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -233,250 +233,285 @@ class AliasState {
   initialize(Operation *op,
              DialectInterfaceCollection<OpAsmDialectInterface> &interfaces);
 
-  /// Return a name used for an attribute alias, or empty if there is no alias.
-  Twine getAttributeAlias(Attribute attr) const;
+  /// Get an alias for the given attribute if it has one and print it in `os`.
+  /// Returns success if an alias was printed, failure otherwise.
+  LogicalResult getAlias(Attribute attr, raw_ostream &os) const;
 
   /// Print all of the referenced attribute aliases.
   void printAttributeAliases(raw_ostream &os, NewLineCounter &newLine) const;
 
-  /// Return a string to use as an alias for the given type, or empty if there
-  /// is no alias recorded.
-  StringRef getTypeAlias(Type ty) const;
+  /// Get an alias for the given type if it has one and print it in `os`.
+  /// Returns success if an alias was printed, failure otherwise.
+  LogicalResult getAlias(Type ty, raw_ostream &os) const;
 
   /// Print all of the referenced type aliases.
   void printTypeAliases(raw_ostream &os, NewLineCounter &newLine) const;
 
 private:
-  /// A special index constant used for non-kind attribute aliases.
-  enum { NonAttrKindAlias = -1 };
-
-  /// Record a reference to the given attribute.
-  void recordAttributeReference(Attribute attr);
-
-  /// Record a reference to the given type.
-  void recordTypeReference(Type ty);
-
-  // Visit functions.
-  void visitOperation(Operation *op);
-  void visitType(Type type);
-  void visitAttribute(Attribute attr);
-
-  /// Set of attributes known to be used within the module.
-  llvm::SetVector<Attribute> usedAttributes;
+  /// This class represents a utility that initializes the set of attribute and
+  /// type aliases, without the need to store the extra information within the
+  /// main AliasState class or pass it around via function arguments.
+  class AliasInitializer {
+  public:
+    AliasInitializer(
+        DialectInterfaceCollection<OpAsmDialectInterface> &interfaces,
+        llvm::BumpPtrAllocator &aliasAllocator)
+        : interfaces(interfaces), aliasAllocator(aliasAllocator),
+          aliasOS(aliasBuffer) {}
+
+    void
+    initialize(Operation *op,
+               llvm::MapVector<Attribute, std::pair<StringRef, Optional<int>>>
+                   &attrToAlias,
+               llvm::MapVector<Type, std::pair<StringRef, Optional<int>>>
+                   &typeToAlias);
+
+  private:
+    void visit(Attribute attr);
+    void visit(Type type);
+
+    /// Try to generate an alias for the provided symbol. If an alias is
+    /// generated, the provided alias mapping and reverse mapping are updated.
+    template <typename T>
+    void
+    generateAlias(T symbol,
+                  llvm::MapVector<StringRef, std::vector<T>> &aliasToSymbol);
+
+    /// The set of asm interfaces within the context.
+    DialectInterfaceCollection<OpAsmDialectInterface> &interfaces;
+
+    /// Mapping between an alias and the set of symbols mapped to it.
+    llvm::MapVector<StringRef, std::vector<Attribute>> aliasToAttr;
+    llvm::MapVector<StringRef, std::vector<Type>> aliasToType;
+
+    /// An allocator used for alias names.
+    llvm::BumpPtrAllocator &aliasAllocator;
+
+    /// The set of visited attributes.
+    DenseSet<Attribute> visitedAttributes;
+
+    /// The set of visited types.
+    DenseSet<Type> visitedTypes;
+
+    /// Storage and stream used when generating an alias.
+    SmallString<32> aliasBuffer;
+    llvm::raw_svector_ostream aliasOS;
+  };
 
   /// 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<TypeID, std::pair<StringRef, std::vector<Attribute>>>
-      attrKindToAlias;
-
-  /// Set of types known to be used within the module.
-  llvm::SetVector<Type> usedTypes;
+  /// count suffix. If the suffix is set to None, it is not displayed.
+  llvm::MapVector<Attribute, std::pair<StringRef, Optional<int>>> attrToAlias;
+  llvm::MapVector<Type, std::pair<StringRef, Optional<int>>> typeToAlias;
 
-  /// A mapping between a type and a given alias.
-  DenseMap<Type, StringRef> typeToAlias;
+  /// An allocator used for alias names.
+  llvm::BumpPtrAllocator aliasAllocator;
 };
 } // end anonymous namespace
 
-// Utility to generate a function to register a symbol alias.
-static bool canRegisterAlias(StringRef name, llvm::StringSet<> &usedAliases) {
-  assert(!name.empty() && "expected alias name to be non-empty");
-  // TODO: Assert that the provided alias name can be lexed as
-  // an identifier.
-
-  // 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 AliasState::initialize(
-    Operation *op,
-    DialectInterfaceCollection<OpAsmDialectInterface> &interfaces) {
-  // Track the identifiers in use for each symbol so that the same identifier
-  // isn't used twice.
-  llvm::StringSet<> usedAliases;
-
-  // Collect the set of aliases from each dialect.
-  SmallVector<std::pair<TypeID, StringRef>, 8> attributeKindAliases;
-  SmallVector<std::pair<Attribute, StringRef>, 8> attributeAliases;
-  SmallVector<std::pair<Type, StringRef>, 16> typeAliases;
+/// Sanitize the given name such that it can be used as a valid identifier. If
+/// the string needs to be modified in any way, the provided buffer is used to
+/// store the new copy,
+static StringRef sanitizeIdentifier(StringRef name, SmallString<16> &buffer,
+                                    StringRef allowedPunctChars = "$._-",
+                                    bool allowTrailingDigit = true) {
+  assert(!name.empty() && "Shouldn't have an empty name here");
 
-  // AffineMap/Integer set have specific kind aliases.
-  attributeKindAliases.emplace_back(AffineMapAttr::getTypeID(), "map");
-  attributeKindAliases.emplace_back(IntegerSetAttr::getTypeID(), "set");
+  auto copyNameToBuffer = [&] {
+    for (char ch : name) {
+      if (llvm::isAlnum(ch) || allowedPunctChars.contains(ch))
+        buffer.push_back(ch);
+      else if (ch == ' ')
+        buffer.push_back('_');
+      else
+        buffer.append(llvm::utohexstr((unsigned char)ch));
+    }
+  };
 
-  for (auto &interface : interfaces) {
-    interface.getAttributeKindAliases(attributeKindAliases);
-    interface.getAttributeAliases(attributeAliases);
-    interface.getTypeAliases(typeAliases);
+  // Check to see if this name is valid. If it starts with a digit, then it
+  // could conflict with the autogenerated numeric ID's, so add an underscore
+  // prefix to avoid problems.
+  if (isdigit(name[0])) {
+    buffer.push_back('_');
+    copyNameToBuffer();
+    return buffer;
   }
 
-  // Setup the attribute kind aliases.
-  StringRef alias;
-  TypeID 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, {}}});
+  // If the name ends with a trailing digit, add a '_' to avoid potential
+  // conflicts with autogenerated ID's.
+  if (!allowTrailingDigit && isdigit(name.back())) {
+    copyNameToBuffer();
+    buffer.push_back('_');
+    return buffer;
   }
 
-  // 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, NonAttrKindAlias}});
+  // Check to see that the name consists of only valid identifier characters.
+  for (char ch : name) {
+    if (!llvm::isAlnum(ch) && !allowedPunctChars.contains(ch)) {
+      copyNameToBuffer();
+      return buffer;
+    }
   }
 
-  // Clear the set of used identifiers as types can have the same identifiers as
-  // affine structures.
-  usedAliases.clear();
-
-  // Type aliases.
-  for (auto &typeAliasPair : typeAliases)
-    if (canRegisterAlias(typeAliasPair.second, usedAliases))
-      typeToAlias.insert(typeAliasPair);
-
-  // Traverse the given IR to generate the set of used attributes/types.
-  op->walk([&](Operation *op) { visitOperation(op); });
-}
-
-/// Return a name used for an attribute alias, or empty if there is no alias.
-Twine AliasState::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 == NonAttrKindAlias ? Twine() : Twine(kindIndex));
+  // If there are no invalid characters, return the original name.
+  return name;
 }
 
-/// Print all of the referenced attribute aliases.
-void AliasState::printAttributeAliases(raw_ostream &os,
-                                       NewLineCounter &newLine) const {
-  auto printAlias = [&](StringRef alias, Attribute attr, int index) {
-    os << '#' << alias;
-    if (index != NonAttrKindAlias)
-      os << index;
-    os << " = " << attr << newLine;
-  };
-
-  // Print all of the attribute kind aliases.
-  for (auto &kindAlias : attrKindToAlias) {
-    auto &aliasAttrsPair = kindAlias.second;
-    for (unsigned i = 0, e = aliasAttrsPair.second.size(); i != e; ++i)
-      printAlias(aliasAttrsPair.first, aliasAttrsPair.second[i], i);
-    os << newLine;
-  }
-
-  // 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 == NonAttrKindAlias)
-      printAlias(alias->second.first, attr, alias->second.second);
+/// Given a collection of aliases and symbols, initialize a mapping from a
+/// symbol to a given alias.
+template <typename T>
+static void initializeAliases(
+    llvm::MapVector<StringRef, std::vector<T>> &aliasToSymbol,
+    llvm::MapVector<T, std::pair<StringRef, Optional<int>>> &symbolToAlias) {
+  std::vector<std::pair<StringRef, std::vector<T>>> aliases =
+      aliasToSymbol.takeVector();
+  llvm::array_pod_sort(aliases.begin(), aliases.end(),
+                       [](const auto *lhs, const auto *rhs) {
+                         return lhs->first.compare(rhs->first);
+                       });
+
+  for (auto &it : aliases) {
+    // If there is only one instance for this alias, use the name directly.
+    if (it.second.size() == 1) {
+      symbolToAlias.insert({it.second.front(), {it.first, llvm::None}});
+      continue;
+    }
+    // Otherwise, add the index to the name.
+    for (auto &symbolIt : llvm::enumerate(it.second))
+      symbolToAlias.insert({symbolIt.value(), {it.first, symbolIt.index()}});
   }
 }
 
-/// Return a string to use as an alias for the given type, or empty if there
-/// is no alias recorded.
-StringRef AliasState::getTypeAlias(Type ty) const {
-  return typeToAlias.lookup(ty);
-}
+void AliasState::AliasInitializer::initialize(
+    Operation *op,
+    llvm::MapVector<Attribute, std::pair<StringRef, Optional<int>>>
+        &attrToAlias,
+    llvm::MapVector<Type, std::pair<StringRef, Optional<int>>> &typeToAlias) {
+  op->walk([&](Operation *op) {
+    // Visit all the types used in the operation.
+    for (auto type : op->getOperandTypes())
+      visit(type);
+    for (auto type : op->getResultTypes())
+      visit(type);
+    for (auto &region : op->getRegions())
+      for (auto &block : region)
+        for (auto arg : block.getArguments())
+          visit(arg.getType());
+
+    // Visit each of the attributes.
+    for (auto elt : op->getAttrs())
+      visit(elt.second);
+  });
 
-/// Print all of the referenced type aliases.
-void AliasState::printTypeAliases(raw_ostream &os,
-                                  NewLineCounter &newLine) const {
-  for (Type type : usedTypes) {
-    auto alias = typeToAlias.find(type);
-    if (alias != typeToAlias.end())
-      os << '!' << alias->second << " = type " << type << newLine;
-  }
+  // Initialize the aliases sorted by name.
+  initializeAliases(aliasToAttr, attrToAlias);
+  initializeAliases(aliasToType, typeToAlias);
 }
 
-/// Record a reference to the given attribute.
-void AliasState::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))
+void AliasState::AliasInitializer::visit(Attribute attr) {
+  if (!visitedAttributes.insert(attr).second)
     return;
 
-  // If this attribute kind has an alias, then record one for this attribute.
-  auto alias = attrKindToAlias.find(attr.getTypeID());
-  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);
-}
+  if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
+    for (Attribute element : arrayAttr.getValue())
+      visit(element);
+  } else if (auto typeAttr = attr.dyn_cast<TypeAttr>()) {
+    visit(typeAttr.getValue());
+  }
 
-/// Record a reference to the given type.
-void AliasState::recordTypeReference(Type ty) { usedTypes.insert(ty); }
+  // Try to generate an alias for this attribute.
+  generateAlias(attr, aliasToAttr);
+}
 
-// TODO: Support visiting other types/operations when implemented.
-void AliasState::visitType(Type type) {
-  recordTypeReference(type);
+void AliasState::AliasInitializer::visit(Type type) {
+  if (!visitedTypes.insert(type).second)
+    return;
 
+  // Visit several subtypes that contain types or atttributes.
   if (auto funcType = type.dyn_cast<FunctionType>()) {
     // Visit input and result types for functions.
     for (auto input : funcType.getInputs())
-      visitType(input);
+      visit(input);
     for (auto result : funcType.getResults())
-      visitType(result);
+      visit(result);
   } else if (auto shapedType = type.dyn_cast<ShapedType>()) {
-    visitType(shapedType.getElementType());
+    visit(shapedType.getElementType());
 
     // Visit affine maps in memref type.
     if (auto memref = type.dyn_cast<MemRefType>())
       for (auto map : memref.getAffineMaps())
-        recordAttributeReference(AffineMapAttr::get(map));
+        visit(AffineMapAttr::get(map));
   }
+
+  // Try to generate an alias for this type.
+  generateAlias(type, aliasToType);
 }
 
-void AliasState::visitAttribute(Attribute attr) {
-  recordAttributeReference(attr);
+template <typename T>
+void AliasState::AliasInitializer::generateAlias(
+    T symbol, llvm::MapVector<StringRef, std::vector<T>> &aliasToSymbol) {
+  SmallString<16> tempBuffer;
+  for (const auto &interface : interfaces) {
+    interface.getAlias(symbol, aliasOS);
+    StringRef name = aliasOS.str();
+    if (name.empty())
+      continue;
+    name = sanitizeIdentifier(name, tempBuffer, /*allowedPunctChars=*/"$_-",
+                              /*allowTrailingDigit=*/false);
+    name = name.copy(aliasAllocator);
 
-  if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
-    for (auto elt : arrayAttr.getValue())
-      visitAttribute(elt);
-  } else if (auto typeAttr = attr.dyn_cast<TypeAttr>()) {
-    visitType(typeAttr.getValue());
+    aliasToSymbol[name].push_back(symbol);
+    aliasBuffer.clear();
+    break;
   }
 }
 
-void AliasState::visitOperation(Operation *op) {
-  // Visit all the types used in the operation.
-  for (auto type : op->getOperandTypes())
-    visitType(type);
-  for (auto type : op->getResultTypes())
-    visitType(type);
-  for (auto &region : op->getRegions())
-    for (auto &block : region)
-      for (auto arg : block.getArguments())
-        visitType(arg.getType());
+void AliasState::initialize(
+    Operation *op,
+    DialectInterfaceCollection<OpAsmDialectInterface> &interfaces) {
+  AliasInitializer initializer(interfaces, aliasAllocator);
+  initializer.initialize(op, attrToAlias, typeToAlias);
+}
+
+static void printAlias(raw_ostream &os,
+                       const std::pair<StringRef, Optional<int>> &alias,
+                       char prefix) {
+  os << prefix << alias.first;
+  if (alias.second)
+    os << *alias.second;
+}
+
+LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {
+  auto it = attrToAlias.find(attr);
+  if (it == attrToAlias.end())
+    return failure();
 
-  // Visit each of the attributes.
-  for (auto elt : op->getAttrs())
-    visitAttribute(elt.second);
+  printAlias(os, it->second, '#');
+  return success();
+}
+
+void AliasState::printAttributeAliases(raw_ostream &os,
+                                       NewLineCounter &newLine) const {
+  for (const auto &it : attrToAlias) {
+    printAlias(os, it.second, '#');
+    os << " = " << it.first << newLine;
+  }
+}
+
+LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {
+  auto it = typeToAlias.find(ty);
+  if (it == typeToAlias.end())
+    return failure();
+
+  printAlias(os, it->second, '!');
+  return success();
+}
+
+void AliasState::printTypeAliases(raw_ostream &os,
+                                  NewLineCounter &newLine) const {
+  for (const auto &it : typeToAlias) {
+    printAlias(os, it.second, '!');
+    os << " = " << it.first << newLine;
+  }
 }
 
 //===----------------------------------------------------------------------===//
@@ -798,42 +833,9 @@ void SSANameState::setValueName(Value value, StringRef name) {
   valueNames[value] = uniqueValueName(name);
 }
 
-/// Returns true if 'c' is an allowable punctuation character: [$._-]
-/// Returns false otherwise.
-static bool isPunct(char c) {
-  return c == '$' || c == '.' || c == '_' || c == '-';
-}
-
 StringRef SSANameState::uniqueValueName(StringRef name) {
-  assert(!name.empty() && "Shouldn't have an empty name here");
-
-  // Check to see if this name is valid.  If it starts with a digit, then it
-  // could conflict with the autogenerated numeric ID's (we unique them in a
-  // 
diff erent map), so add an underscore prefix to avoid problems.
-  if (isdigit(name[0])) {
-    SmallString<16> tmpName("_");
-    tmpName += name;
-    return uniqueValueName(tmpName);
-  }
-
-  // Check to see if the name consists of all-valid identifiers.  If not, we
-  // need to escape them.
-  for (char ch : name) {
-    if (isalpha(ch) || isPunct(ch) || isdigit(ch))
-      continue;
-
-    SmallString<16> tmpName;
-    for (char ch : name) {
-      if (isalpha(ch) || isPunct(ch) || isdigit(ch))
-        tmpName += ch;
-      else if (ch == ' ')
-        tmpName += '_';
-      else {
-        tmpName += llvm::utohexstr((unsigned char)ch);
-      }
-    }
-    return uniqueValueName(tmpName);
-  }
+  SmallString<16> tmpBuffer;
+  name = sanitizeIdentifier(name, tmpBuffer);
 
   // Check to see if this name is already unique.
   if (!usedNames.count(name)) {
@@ -845,12 +847,12 @@ StringRef SSANameState::uniqueValueName(StringRef name) {
     SmallString<64> probeName(name);
     probeName.push_back('_');
     while (true) {
-      probeName.resize(name.size() + 1);
       probeName += llvm::utostr(nextConflictID++);
       if (!usedNames.count(probeName)) {
         name = StringRef(probeName).copy(usedNameAllocator);
         break;
       }
+      probeName.resize(name.size() + 1);
     }
   }
 
@@ -1287,14 +1289,9 @@ void ModulePrinter::printAttribute(Attribute attr,
     return;
   }
 
-  // Check for an alias for this attribute.
-  if (state) {
-    Twine alias = state->getAliasState().getAttributeAlias(attr);
-    if (!alias.isTriviallyEmpty()) {
-      os << '#' << alias;
-      return;
-    }
-  }
+  // Try to print an alias for this attribute.
+  if (state && succeeded(state->getAliasState().getAlias(attr, os)))
+    return;
 
   auto attrType = attr.getType();
   if (auto opaqueAttr = attr.dyn_cast<OpaqueAttr>()) {
@@ -1581,14 +1578,9 @@ void ModulePrinter::printType(Type type) {
     return;
   }
 
-  // Check for an alias for this type.
-  if (state) {
-    StringRef alias = state->getAliasState().getTypeAlias(type);
-    if (!alias.empty()) {
-      os << '!' << alias;
-      return;
-    }
-  }
+  // Try to print an alias for this type.
+  if (state && succeeded(state->getAliasState().getAlias(type, os)))
+    return;
 
   TypeSwitch<Type>(type)
       .Case<OpaqueType>([&](OpaqueType opaqueTy) {

diff  --git a/mlir/lib/IR/MLIRContext.cpp b/mlir/lib/IR/MLIRContext.cpp
index 90c43154f27b..cea9d471796b 100644
--- a/mlir/lib/IR/MLIRContext.cpp
+++ b/mlir/lib/IR/MLIRContext.cpp
@@ -23,6 +23,7 @@
 #include "mlir/IR/IntegerSet.h"
 #include "mlir/IR/Location.h"
 #include "mlir/IR/Module.h"
+#include "mlir/IR/OpImplementation.h"
 #include "mlir/IR/Types.h"
 #include "mlir/Support/ThreadLocalCache.h"
 #include "llvm/ADT/DenseMap.h"
@@ -86,6 +87,22 @@ void mlir::registerMLIRContextCLOptions() {
 //===----------------------------------------------------------------------===//
 
 namespace {
+struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
+  using OpAsmDialectInterface::OpAsmDialectInterface;
+
+  LogicalResult getAlias(Attribute attr, raw_ostream &os) const override {
+    if (attr.isa<AffineMapAttr>()) {
+      os << "map";
+      return success();
+    }
+    if (attr.isa<IntegerSetAttr>()) {
+      os << "set";
+      return success();
+    }
+    return failure();
+  }
+};
+
 /// A builtin dialect to define types/etc that are necessary for the validity of
 /// the IR.
 struct BuiltinDialect : public Dialect {
@@ -102,6 +119,7 @@ struct BuiltinDialect : public Dialect {
                   UnitAttr>();
     addAttributes<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
                   UnknownLoc>();
+    addInterfaces<BuiltinOpAsmDialectInterface>();
 
     // TODO: These operations should be moved to a 
diff erent dialect when they
     // have been fully decoupled from the core.

diff  --git a/mlir/test/Dialect/Affine/affine-loop-invariant-code-motion.mlir b/mlir/test/Dialect/Affine/affine-loop-invariant-code-motion.mlir
index 4256dcc0614b..18255fe891ae 100644
--- a/mlir/test/Dialect/Affine/affine-loop-invariant-code-motion.mlir
+++ b/mlir/test/Dialect/Affine/affine-loop-invariant-code-motion.mlir
@@ -107,7 +107,7 @@ func @invariant_code_inside_affine_if() {
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
   // CHECK-NEXT: %1 = affine.apply #map{{[0-9]+}}(%arg0)
-  // CHECK-NEXT: affine.if #set0(%arg0, %1) {
+  // CHECK-NEXT: affine.if #set(%arg0, %1) {
   // CHECK-NEXT: %2 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %2, %0[%arg0] : memref<10xf32>
   // CHECK-NEXT: }
@@ -252,7 +252,7 @@ func @invariant_affine_if() {
   // CHECK: %0 = alloc() : memref<10xf32>
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %1 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %1, %0[%arg0] : memref<10xf32>
   // CHECK-NEXT: }
@@ -280,7 +280,7 @@ func @invariant_affine_if2() {
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
   // CHECK-NEXT: affine.for %arg1 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %1 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %1, %0[%arg1] : memref<10xf32>
   // CHECK-NEXT: }
@@ -311,10 +311,10 @@ func @invariant_affine_nested_if() {
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
   // CHECK-NEXT: affine.for %arg1 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %1 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %1, %0[%arg0] : memref<10xf32>
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: affine.store %1, %0[%arg1] : memref<10xf32>
   // CHECK-NEXT: }
   // CHECK-NEXT: }
@@ -347,10 +347,10 @@ func @invariant_affine_nested_if_else() {
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
   // CHECK-NEXT: affine.for %arg1 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %1 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %1, %0[%arg0] : memref<10xf32>
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: affine.store %1, %0[%arg0] : memref<10xf32>
   // CHECK-NEXT: } else {
   // CHECK-NEXT: affine.store %1, %0[%arg1] : memref<10xf32>
@@ -386,10 +386,10 @@ func @invariant_affine_nested_if_else2() {
   // CHECK-NEXT: %1 = alloc() : memref<10xf32>
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %2 = addf %cst, %cst : f32
   // CHECK-NEXT: %3 = affine.load %0[%arg0] : memref<10xf32>
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: affine.store %2, %1[%arg0] : memref<10xf32>
   // CHECK-NEXT: } else {
   // CHECK-NEXT: %4 = affine.load %0[%arg0] : memref<10xf32>
@@ -420,10 +420,10 @@ func @invariant_affine_nested_if2() {
   // CHECK: %0 = alloc() : memref<10xf32>
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %1 = addf %cst, %cst : f32
   // CHECK-NEXT: %2 = affine.load %0[%arg0] : memref<10xf32>
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %3 = affine.load %0[%arg0] : memref<10xf32>
   // CHECK-NEXT: }
   // CHECK-NEXT: }
@@ -453,7 +453,7 @@ func @invariant_affine_for_inside_affine_if() {
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
   // CHECK-NEXT: affine.for %arg1 = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%arg0, %arg0) {
+  // CHECK-NEXT: affine.if #set(%arg0, %arg0) {
   // CHECK-NEXT: %1 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %1, %0[%arg0] : memref<10xf32>
   // CHECK-NEXT: affine.for %arg2 = 0 to 10 {

diff  --git a/mlir/test/Dialect/Affine/canonicalize.mlir b/mlir/test/Dialect/Affine/canonicalize.mlir
index aa2dbd746c8b..e7794547eaa8 100644
--- a/mlir/test/Dialect/Affine/canonicalize.mlir
+++ b/mlir/test/Dialect/Affine/canonicalize.mlir
@@ -423,7 +423,7 @@ func @fold_empty_loop() {
 
 // -----
 
-// CHECK-DAG: [[$SET:#set[0-9]+]] = affine_set<(d0, d1)[s0] : (d0 >= 0, -d0 + 1022 >= 0, d1 >= 0, -d1 + s0 - 2 >= 0)>
+// CHECK-DAG: [[$SET:#set[0-9]*]] = affine_set<(d0, d1)[s0] : (d0 >= 0, -d0 + 1022 >= 0, d1 >= 0, -d1 + s0 - 2 >= 0)>
 
 // CHECK-LABEL: func @canonicalize_affine_if
 // CHECK-SAME: [[M:%.*]]: index,

diff  --git a/mlir/test/Dialect/Affine/ops.mlir b/mlir/test/Dialect/Affine/ops.mlir
index 627104bae976..ad2fb5fd6a59 100644
--- a/mlir/test/Dialect/Affine/ops.mlir
+++ b/mlir/test/Dialect/Affine/ops.mlir
@@ -208,7 +208,7 @@ func @yield_loop(%buffer: memref<1024xf32>) -> f32 {
 }
 // CHECK:      %[[const_0:.*]] = constant 0.000000e+00 : f32
 // CHECK-NEXT: %[[output:.*]] = affine.for %{{.*}} = 0 to 10 step 2 iter_args(%{{.*}} = %[[const_0]]) -> (f32) {
-// CHECK:        affine.if #set0(%{{.*}}) -> f32 {
+// CHECK:        affine.if #set(%{{.*}}) -> f32 {
 // CHECK:          affine.yield %{{.*}} : f32
 // CHECK-NEXT:   } else {
 // CHECK-NEXT:     affine.yield %{{.*}} : f32

diff  --git a/mlir/test/Dialect/SCF/for-loop-specialization.mlir b/mlir/test/Dialect/SCF/for-loop-specialization.mlir
index f7b501e0c95c..1be3f48dc549 100644
--- a/mlir/test/Dialect/SCF/for-loop-specialization.mlir
+++ b/mlir/test/Dialect/SCF/for-loop-specialization.mlir
@@ -23,7 +23,7 @@ func @for(%outer: index, %A: memref<?xf32>, %B: memref<?xf32>,
 // CHECK:           [[CST_0:%.*]] = constant 0 : index
 // CHECK:           [[CST_1:%.*]] = constant 1 : index
 // CHECK:           [[DIM_0:%.*]] = dim [[ARG1]], [[CST_0]] : memref<?xf32>
-// CHECK:           [[MIN:%.*]] = affine.min #map0(){{\[}}[[DIM_0]], [[ARG0]]]
+// CHECK:           [[MIN:%.*]] = affine.min #map(){{\[}}[[DIM_0]], [[ARG0]]]
 // CHECK:           [[CST_1024:%.*]] = constant 1024 : index
 // CHECK:           [[PRED:%.*]] = cmpi "eq", [[MIN]], [[CST_1024]] : index
 // CHECK:           scf.if [[PRED]] {

diff  --git a/mlir/test/Dialect/SCF/parallel-loop-tiling.mlir b/mlir/test/Dialect/SCF/parallel-loop-tiling.mlir
index 6dff4eeda9e7..e0dc8344f14d 100644
--- a/mlir/test/Dialect/SCF/parallel-loop-tiling.mlir
+++ b/mlir/test/Dialect/SCF/parallel-loop-tiling.mlir
@@ -13,7 +13,7 @@ func @parallel_loop(%arg0 : index, %arg1 : index, %arg2 : index,
   return
 }
 
-// CHECK:       #map0 = affine_map<(d0, d1, d2) -> (d0, d1 - d2)>
+// CHECK:       #map = affine_map<(d0, d1, d2) -> (d0, d1 - d2)>
 // CHECK-LABEL:   func @parallel_loop(
 // CHECK-SAME:                        [[ARG1:%.*]]: index, [[ARG2:%.*]]: index, [[ARG3:%.*]]: index, [[ARG4:%.*]]: index, [[ARG5:%.*]]: index, [[ARG6:%.*]]: index, [[ARG7:%.*]]: memref<?x?xf32>, [[ARG8:%.*]]: memref<?x?xf32>, [[ARG9:%.*]]: memref<?x?xf32>, [[ARG10:%.*]]: memref<?x?xf32>) {
 // CHECK:           [[C0:%.*]] = constant 0 : index
@@ -22,8 +22,8 @@ func @parallel_loop(%arg0 : index, %arg1 : index, %arg2 : index,
 // CHECK:           [[V1:%.*]] = muli [[ARG5]], [[C1]] : index
 // CHECK:           [[V2:%.*]] = muli [[ARG6]], [[C4]] : index
 // CHECK:           scf.parallel ([[V3:%.*]], [[V4:%.*]]) = ([[ARG1]], [[ARG2]]) to ([[ARG3]], [[ARG4]]) step ([[V1]], [[V2]]) {
-// CHECK:             [[V5:%.*]] = affine.min #map0([[V1]], [[ARG3]], [[V3]])
-// CHECK:             [[V6:%.*]] = affine.min #map0([[V2]], [[ARG4]], [[V4]])
+// CHECK:             [[V5:%.*]] = affine.min #map([[V1]], [[ARG3]], [[V3]])
+// CHECK:             [[V6:%.*]] = affine.min #map([[V2]], [[ARG4]], [[V4]])
 // CHECK:             scf.parallel ([[V7:%.*]], [[V8:%.*]]) = ([[C0]], [[C0]]) to ([[V5]], [[V6]]) step ([[ARG5]], [[ARG6]]) {
 // CHECK:               [[V9:%.*]] = addi [[V7]], [[V3]] : index
 // CHECK:               [[V10:%.*]] = addi [[V8]], [[V4]] : index
@@ -91,7 +91,7 @@ func @tile_nested_innermost() {
 // CHECK:             [[V3:%.*]] = muli [[C1]], [[C1_1]] : index
 // CHECK:             [[V4:%.*]] = muli [[C1]], [[C4]] : index
 // CHECK:             scf.parallel ([[V5:%.*]], [[V6:%.*]]) = ([[C0]], [[C0]]) to ([[C2]], [[C2]]) step ([[V3]], [[V4]]) {
-// CHECK:               [[V7:%.*]] = affine.min #map0([[V4]], [[C2]], [[V6]])
+// CHECK:               [[V7:%.*]] = affine.min #map([[V4]], [[C2]], [[V6]])
 // CHECK:               scf.parallel ([[V8:%.*]], [[V9:%.*]]) = ([[C0_1]], [[C0_1]]) to ([[V3]], [[V7]]) step ([[C1]], [[C1]]) {
 // CHECK:                 = addi [[V8]], [[V5]] : index
 // CHECK:                 = addi [[V9]], [[V6]] : index
@@ -104,7 +104,7 @@ func @tile_nested_innermost() {
 // CHECK:           [[V10:%.*]] = muli [[C1]], [[C1_2]] : index
 // CHECK:           [[V11:%.*]] = muli [[C1]], [[C4_1]] : index
 // CHECK:           scf.parallel ([[V12:%.*]], [[V13:%.*]]) = ([[C0]], [[C0]]) to ([[C2]], [[C2]]) step ([[V10]], [[V11]]) {
-// CHECK:             [[V14:%.*]] = affine.min #map0([[V11]], [[C2]], [[V13]])
+// CHECK:             [[V14:%.*]] = affine.min #map([[V11]], [[C2]], [[V13]])
 // CHECK:             scf.parallel ([[V15:%.*]], [[V16:%.*]]) = ([[C0_2]], [[C0_2]]) to ([[V10]], [[V14]]) step ([[C1]], [[C1]]) {
 // CHECK:               = addi [[V15]], [[V12]] : index
 // CHECK:               = addi [[V16]], [[V13]] : index

diff  --git a/mlir/test/IR/memory-ops.mlir b/mlir/test/IR/memory-ops.mlir
index f44ab1c873be..d1860acb5076 100644
--- a/mlir/test/IR/memory-ops.mlir
+++ b/mlir/test/IR/memory-ops.mlir
@@ -1,6 +1,6 @@
 // RUN: mlir-opt %s | FileCheck %s
 
-// CHECK: #map0 = affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>
+// CHECK: #map = affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>
 
 // CHECK-LABEL: func @alloc() {
 func @alloc() {
@@ -17,11 +17,11 @@ func @alloc() {
   %1 = alloc(%c0, %c1) : memref<?x?xf32, affine_map<(d0, d1) -> (d0, d1)>, 1>
 
   // Test alloc with no dynamic dimensions and one symbol.
-  // CHECK: %2 = alloc()[%c0] : memref<2x4xf32, #map0, 1>
+  // CHECK: %2 = alloc()[%c0] : memref<2x4xf32, #map, 1>
   %2 = alloc()[%c0] : memref<2x4xf32, affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
 
   // Test alloc with dynamic dimensions and one symbol.
-  // CHECK: %3 = alloc(%c1)[%c0] : memref<2x?xf32, #map0, 1>
+  // CHECK: %3 = alloc(%c1)[%c0] : memref<2x?xf32, #map, 1>
   %3 = alloc(%c1)[%c0] : memref<2x?xf32, affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>, 1>
 
   // Alloc with no mappings.
@@ -48,11 +48,11 @@ func @alloca() {
   %1 = alloca(%c0, %c1) : memref<?x?xf32, affine_map<(d0, d1) -> (d0, d1)>, 1>
 
   // Test alloca with no dynamic dimensions and one symbol.
-  // CHECK: %2 = alloca()[%c0] : memref<2x4xf32, #map0, 1>
+  // CHECK: %2 = alloca()[%c0] : memref<2x4xf32, #map, 1>
   %2 = alloca()[%c0] : memref<2x4xf32, affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
 
   // Test alloca with dynamic dimensions and one symbol.
-  // CHECK: %3 = alloca(%c1)[%c0] : memref<2x?xf32, #map0, 1>
+  // CHECK: %3 = alloca(%c1)[%c0] : memref<2x?xf32, #map, 1>
   %3 = alloca(%c1)[%c0] : memref<2x?xf32, affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>, 1>
 
   // Alloca with no mappings, but with alignment.

diff  --git a/mlir/test/IR/print-attr-type-aliases.mlir b/mlir/test/IR/print-attr-type-aliases.mlir
new file mode 100644
index 000000000000..b8c22cc26c23
--- /dev/null
+++ b/mlir/test/IR/print-attr-type-aliases.mlir
@@ -0,0 +1,15 @@
+// RUN: mlir-opt %s | FileCheck %s
+
+
+// CHECK-DAG: #test2Ealias = "alias_test:dot_in_name"
+"test.op"() {alias_test = "alias_test:dot_in_name"} : () -> ()
+
+// CHECK-DAG: #test_alias0_ = "alias_test:trailing_digit"
+"test.op"() {alias_test = "alias_test:trailing_digit"} : () -> ()
+
+// CHECK-DAG: #_0_test_alias = "alias_test:prefixed_digit"
+"test.op"() {alias_test = "alias_test:prefixed_digit"} : () -> ()
+
+// CHECK-DAG: #test_alias_conflict0_0 = "alias_test:sanitize_conflict_a"
+// CHECK-DAG: #test_alias_conflict0_1 = "alias_test:sanitize_conflict_b"
+"test.op"() {alias_test = ["alias_test:sanitize_conflict_a", "alias_test:sanitize_conflict_b"]} : () -> ()

diff  --git a/mlir/test/Transforms/loop-fusion.mlir b/mlir/test/Transforms/loop-fusion.mlir
index b4eea34b41f1..1da4ae056674 100644
--- a/mlir/test/Transforms/loop-fusion.mlir
+++ b/mlir/test/Transforms/loop-fusion.mlir
@@ -462,7 +462,7 @@ func @should_not_fuse_if_inst_in_loop_nest() {
   // CHECK-NEXT:   affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>
   // CHECK-NEXT: }
   // CHECK:      affine.for %{{.*}} = 0 to 10 {
-  // CHECK-NEXT:   affine.if #set0(%{{.*}}) {
+  // CHECK-NEXT:   affine.if #set(%{{.*}}) {
   // CHECK-NEXT:   }
   // CHECK-NEXT:   affine.load %{{.*}}[%{{.*}}] : memref<10xf32>
   // CHECK-NEXT: }

diff  --git a/mlir/test/Transforms/loop-invariant-code-motion.mlir b/mlir/test/Transforms/loop-invariant-code-motion.mlir
index d6af573d4e97..6cf4eb4e6a7d 100644
--- a/mlir/test/Transforms/loop-invariant-code-motion.mlir
+++ b/mlir/test/Transforms/loop-invariant-code-motion.mlir
@@ -88,7 +88,7 @@ func @invariant_code_inside_affine_if() {
   // CHECK-NEXT: %cst = constant 8.000000e+00 : f32
   // CHECK-NEXT: affine.for %arg0 = 0 to 10 {
   // CHECK-NEXT: %1 = affine.apply #map0(%arg0)
-  // CHECK-NEXT: affine.if #set0(%arg0, %1) {
+  // CHECK-NEXT: affine.if #set(%arg0, %1) {
   // CHECK-NEXT: %2 = addf %cst, %cst : f32
   // CHECK-NEXT: affine.store %2, %0[%arg0] : memref<10xf32>
   // CHECK-NEXT: }
@@ -115,7 +115,7 @@ func @invariant_affine_if() {
   // CHECK-NEXT: affine.for %[[ARG:.*]] = 0 to 10 {
   // CHECK-NEXT: }
   // CHECK-NEXT: affine.for %[[ARG:.*]] = 0 to 10 {
-  // CHECK-NEXT: affine.if #set0(%[[ARG]], %[[ARG]]) {
+  // CHECK-NEXT: affine.if #set(%[[ARG]], %[[ARG]]) {
   // CHECK-NEXT: addf %[[CST]], %[[CST]] : f32
   // CHECK-NEXT: }
 

diff  --git a/mlir/test/lib/Dialect/Test/TestDialect.cpp b/mlir/test/lib/Dialect/Test/TestDialect.cpp
index e7c10c01b11b..ffc59aad7d18 100644
--- a/mlir/test/lib/Dialect/Test/TestDialect.cpp
+++ b/mlir/test/lib/Dialect/Test/TestDialect.cpp
@@ -35,6 +35,30 @@ namespace {
 struct TestOpAsmInterface : public OpAsmDialectInterface {
   using OpAsmDialectInterface::OpAsmDialectInterface;
 
+  LogicalResult getAlias(Attribute attr, raw_ostream &os) const final {
+    StringAttr strAttr = attr.dyn_cast<StringAttr>();
+    if (!strAttr)
+      return failure();
+
+    // Check the contents of the string attribute to see what the test alias
+    // should be named.
+    Optional<StringRef> aliasName =
+        StringSwitch<Optional<StringRef>>(strAttr.getValue())
+            .Case("alias_test:dot_in_name", StringRef("test.alias"))
+            .Case("alias_test:trailing_digit", StringRef("test_alias0"))
+            .Case("alias_test:prefixed_digit", StringRef("0_test_alias"))
+            .Case("alias_test:sanitize_conflict_a",
+                  StringRef("test_alias_conflict0"))
+            .Case("alias_test:sanitize_conflict_b",
+                  StringRef("test_alias_conflict0_"))
+            .Default(llvm::None);
+    if (!aliasName)
+      return failure();
+
+    os << *aliasName;
+    return success();
+  }
+
   void getAsmResultNames(Operation *op,
                          OpAsmSetValueNameFn setNameFn) const final {
     if (auto asmOp = dyn_cast<AsmDialectInterfaceOp>(op))


        


More information about the Mlir-commits mailing list