diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h --- a/mlir/include/mlir/IR/OpImplementation.h +++ b/mlir/include/mlir/IR/OpImplementation.h @@ -801,21 +801,17 @@ 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 : [0-9]+. These - /// aliases must not contain `.`. - virtual void getAttributeKindAliases( - SmallVectorImpl> &aliases) const {} - /// Hook for defining Attribute aliases. These aliases must not contain `.` or - /// end with a numeric digit([0-9]+). - virtual void getAttributeAliases( - SmallVectorImpl> &aliases) const {} - /// Hook for defining Type aliases. - virtual void - getTypeAliases(SmallVectorImpl> &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 --- a/mlir/lib/IR/AsmPrinter.cpp +++ b/mlir/lib/IR/AsmPrinter.cpp @@ -233,250 +233,285 @@ initialize(Operation *op, DialectInterfaceCollection &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 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 &interfaces, + llvm::BumpPtrAllocator &aliasAllocator) + : interfaces(interfaces), aliasAllocator(aliasAllocator), + aliasOS(aliasBuffer) {} + + void + initialize(Operation *op, + llvm::MapVector>> + &attrToAlias, + llvm::MapVector>> + &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 + void + generateAlias(T symbol, + llvm::MapVector> &aliasToSymbol); + + /// The set of asm interfaces within the context. + DialectInterfaceCollection &interfaces; + + /// Mapping between an alias and the set of symbols mapped to it. + llvm::MapVector> aliasToAttr; + llvm::MapVector> aliasToType; + + /// An allocator used for alias names. + llvm::BumpPtrAllocator &aliasAllocator; + + /// The set of visited attributes. + DenseSet visitedAttributes; + + /// The set of visited types. + DenseSet 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> 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>> - attrKindToAlias; - - /// Set of types known to be used within the module. - llvm::SetVector usedTypes; + /// count suffix. If the suffix is set to None, it is not displayed. + llvm::MapVector>> attrToAlias; + llvm::MapVector>> typeToAlias; - /// A mapping between a type and a given alias. - DenseMap 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 &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, 8> attributeKindAliases; - SmallVector, 8> attributeAliases; - SmallVector, 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 +static void initializeAliases( + llvm::MapVector> &aliasToSymbol, + llvm::MapVector>> &symbolToAlias) { + std::vector>> 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>> + &attrToAlias, + llvm::MapVector>> &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 ®ion : 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 attrAlias(alias->second.first, - alias->second.second.size()); - attrToAlias.insert({attr, attrAlias}); - alias->second.second.push_back(attr); -} + if (auto arrayAttr = attr.dyn_cast()) { + for (Attribute element : arrayAttr.getValue()) + visit(element); + } else if (auto typeAttr = attr.dyn_cast()) { + 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()) { // 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()) { - visitType(shapedType.getElementType()); + visit(shapedType.getElementType()); // Visit affine maps in memref type. if (auto memref = type.dyn_cast()) 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 +void AliasState::AliasInitializer::generateAlias( + T symbol, llvm::MapVector> &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()) { - for (auto elt : arrayAttr.getValue()) - visitAttribute(elt); - } else if (auto typeAttr = attr.dyn_cast()) { - 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 ®ion : op->getRegions()) - for (auto &block : region) - for (auto arg : block.getArguments()) - visitType(arg.getType()); +void AliasState::initialize( + Operation *op, + DialectInterfaceCollection &interfaces) { + AliasInitializer initializer(interfaces, aliasAllocator); + initializer.initialize(op, attrToAlias, typeToAlias); +} + +static void printAlias(raw_ostream &os, + const std::pair> &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 @@ 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 - // different 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 @@ 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 @@ 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()) { @@ -1581,14 +1578,9 @@ 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) .Case([&](OpaqueType opaqueTy) { diff --git a/mlir/lib/IR/MLIRContext.cpp b/mlir/lib/IR/MLIRContext.cpp --- 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 @@ //===----------------------------------------------------------------------===// namespace { +struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface { + using OpAsmDialectInterface::OpAsmDialectInterface; + + LogicalResult getAlias(Attribute attr, raw_ostream &os) const override { + if (attr.isa()) { + os << "map"; + return success(); + } + if (attr.isa()) { + 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 @@ UnitAttr>(); addAttributes(); + addInterfaces(); // TODO: These operations should be moved to a different 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 --- 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 --- a/mlir/test/Dialect/Affine/canonicalize.mlir +++ b/mlir/test/Dialect/Affine/canonicalize.mlir @@ -423,7 +423,7 @@ // ----- -// 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 --- a/mlir/test/Dialect/Affine/ops.mlir +++ b/mlir/test/Dialect/Affine/ops.mlir @@ -208,7 +208,7 @@ } // 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 --- a/mlir/test/Dialect/SCF/for-loop-specialization.mlir +++ b/mlir/test/Dialect/SCF/for-loop-specialization.mlir @@ -23,7 +23,7 @@ // CHECK: [[CST_0:%.*]] = constant 0 : index // CHECK: [[CST_1:%.*]] = constant 1 : index // CHECK: [[DIM_0:%.*]] = dim [[ARG1]], [[CST_0]] : memref -// 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 --- a/mlir/test/Dialect/SCF/parallel-loop-tiling.mlir +++ b/mlir/test/Dialect/SCF/parallel-loop-tiling.mlir @@ -13,7 +13,7 @@ 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, [[ARG8:%.*]]: memref, [[ARG9:%.*]]: memref, [[ARG10:%.*]]: memref) { // CHECK: [[C0:%.*]] = constant 0 : index @@ -22,8 +22,8 @@ // 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 @@ // 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 @@ // 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 --- 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 @@ %1 = alloc(%c0, %c1) : memref (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 @@ %1 = alloca(%c0, %c1) : memref (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 --- /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 --- a/mlir/test/Transforms/loop-fusion.mlir +++ b/mlir/test/Transforms/loop-fusion.mlir @@ -462,7 +462,7 @@ // 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 --- a/mlir/test/Transforms/loop-invariant-code-motion.mlir +++ b/mlir/test/Transforms/loop-invariant-code-motion.mlir @@ -88,7 +88,7 @@ // 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 @@ // 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 --- a/mlir/test/lib/Dialect/Test/TestDialect.cpp +++ b/mlir/test/lib/Dialect/Test/TestDialect.cpp @@ -35,6 +35,30 @@ struct TestOpAsmInterface : public OpAsmDialectInterface { using OpAsmDialectInterface::OpAsmDialectInterface; + LogicalResult getAlias(Attribute attr, raw_ostream &os) const final { + StringAttr strAttr = attr.dyn_cast(); + if (!strAttr) + return failure(); + + // Check the contents of the string attribute to see what the test alias + // should be named. + Optional aliasName = + StringSwitch>(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(op))