[mlir] Cleanup lingering problems surrounding attribute/type aliases
authorRiver Riddle <riddleriver@gmail.com>
Tue, 29 Nov 2022 02:35:00 +0000 (18:35 -0800)
committerRiver Riddle <riddleriver@gmail.com>
Thu, 1 Dec 2022 01:02:54 +0000 (17:02 -0800)
This commit refactors attribute/type alias generation to be similar to how
we do it for operations, i.e. we generate aliases determined on what is
actually necessary when printing the IR (using a dummy printer for alias
collection). This allows for generating aliases only when necessary, and
also allows for proper propagation of when a nested alias can be deferred.
This also necessitated a fix for location parsing to actually parse aliases
instead of ignoring them.

Fixes #59041

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

mlir/include/mlir/IR/OpImplementation.h
mlir/lib/AsmParser/LocationParser.cpp
mlir/lib/IR/AsmPrinter.cpp
mlir/test/Dialect/DLTI/roundtrip.mlir
mlir/test/Dialect/SparseTensor/sparse_vector_chain.mlir
mlir/test/Dialect/SparseTensor/sparse_vector_index.mlir
mlir/test/IR/pretty-locations.mlir
mlir/test/IR/print-attr-type-aliases.mlir
mlir/test/Target/LLVMIR/Import/debug-info.ll

index c6e5abd..e517794 100644 (file)
@@ -181,7 +181,7 @@ public:
   virtual void printSymbolName(StringRef symbolRef);
 
   /// Print a handle to the given dialect resource.
-  void printResourceHandle(const AsmDialectResourceHandle &resource);
+  virtual void printResourceHandle(const AsmDialectResourceHandle &resource);
 
   /// Print an optional arrow followed by a type list.
   template <typename TypeRange>
index cf1e8af..02cb3ed 100644 (file)
@@ -149,6 +149,16 @@ ParseResult Parser::parseNameOrFileLineColLocation(LocationAttr &loc) {
 }
 
 ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
+  // Handle aliases.
+  if (getToken().is(Token::hash_identifier)) {
+    Attribute locAttr = parseExtendedAttr(Type());
+    if (!locAttr)
+      return failure();
+    if (!(loc = dyn_cast<LocationAttr>(locAttr)))
+      return emitError("expected location attribute, but got") << locAttr;
+    return success();
+  }
+
   // Handle either name or filelinecol locations.
   if (getToken().is(Token::string))
     return parseNameOrFileLineColLocation(loc);
index c06e96d..f1d5b7b 100644 (file)
@@ -389,7 +389,8 @@ protected:
                              bool withKeyword = false);
   void printNamedAttribute(NamedAttribute attr);
   void printTrailingLocation(Location loc, bool allowAlias = true);
-  void printLocationInternal(LocationAttr loc, bool pretty = false);
+  void printLocationInternal(LocationAttr loc, bool pretty = false,
+                             bool isTopLevel = false);
 
   /// Print a dense elements attribute. If 'allowHex' is true, a hex string is
   /// used instead of individual elements when the elements attr is large.
@@ -495,14 +496,21 @@ public:
   /// Visit the given attribute to see if it has an alias. `canBeDeferred` is
   /// set to true if the originator of this attribute can resolve the alias
   /// after parsing has completed (e.g. in the case of operation locations).
-  /// Returns the maximum alias depth of the attribute.
-  size_t visit(Attribute attr, bool canBeDeferred = false) {
-    return visitImpl(attr, aliases, canBeDeferred);
+  /// `elideType` indicates if the type of the attribute should be skipped when
+  /// looking for nested aliases. Returns the maximum alias depth of the
+  /// attribute, and the alias index of this attribute.
+  std::pair<size_t, size_t> visit(Attribute attr, bool canBeDeferred = false,
+                                  bool elideType = false) {
+    return visitImpl(attr, aliases, canBeDeferred, elideType);
   }
 
-  /// Visit the given type to see if it has an alias. Returns the maximum alias
-  /// depth of the type.
-  size_t visit(Type type) { return visitImpl(type, aliases); }
+  /// Visit the given type to see if it has an alias. `canBeDeferred` is
+  /// set to true if the originator of this attribute can resolve the alias
+  /// after parsing has completed. Returns the maximum alias depth of the type,
+  /// and the alias index of this type.
+  std::pair<size_t, size_t> visit(Type type, bool canBeDeferred = false) {
+    return visitImpl(type, aliases, canBeDeferred);
+  }
 
 private:
   struct InProgressAliasInfo {
@@ -530,16 +538,23 @@ private:
     bool isType : 1;
     /// If this alias can be deferred or not.
     bool canBeDeferred : 1;
+    /// Indices for child aliases.
+    SmallVector<size_t> childIndices;
   };
 
   /// Visit the given attribute or type to see if it has an alias.
   /// `canBeDeferred` is set to true if the originator of this value can resolve
   /// the alias after parsing has completed (e.g. in the case of operation
-  /// locations). Returns the maximum alias depth of the value.
-  template <typename T>
-  size_t visitImpl(T value,
-                   llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
-                   bool canBeDeferred = false);
+  /// locations). Returns the maximum alias depth of the value, and its alias
+  /// index.
+  template <typename T, typename... PrintArgs>
+  std::pair<size_t, size_t>
+  visitImpl(T value,
+            llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
+            bool canBeDeferred, PrintArgs &&...printArgs);
+
+  /// Mark the given alias as non-deferrable.
+  void markAliasNonDeferrable(size_t aliasIndex);
 
   /// Try to generate an alias for the provided symbol. If an alias is
   /// generated, the provided alias mapping and reverse mapping are updated.
@@ -722,7 +737,7 @@ private:
 
   /// The following are hooks of `OpAsmPrinter` that are not necessary for
   /// determining potential aliases.
-  void printFloat(const APFloat &value) override {}
+  void printFloat(const APFloat &) override {}
   void printAffineMapOfSSAIds(AffineMapAttr, ValueRange) override {}
   void printAffineExprOfSSAIds(AffineExpr, ValueRange, ValueRange) override {}
   void printNewline() override {}
@@ -736,6 +751,7 @@ private:
     os << "%";
   }
   void printKeywordOrString(StringRef) override {}
+  void printResourceHandle(const AsmDialectResourceHandle &) override {}
   void printSymbolName(StringRef) override {}
   void printSuccessor(Block *) override {}
   void printSuccessorAndUseList(Block *, ValueRange) override {}
@@ -750,6 +766,149 @@ private:
   /// A dummy output stream.
   mutable llvm::raw_null_ostream os;
 };
+
+class DummyAliasDialectAsmPrinter : public DialectAsmPrinter {
+public:
+  explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
+                                       bool canBeDeferred,
+                                       SmallVectorImpl<size_t> &childIndices)
+      : initializer(initializer), canBeDeferred(canBeDeferred),
+        childIndices(childIndices) {}
+
+  /// Print the given attribute/type, visiting any nested aliases that would be
+  /// generated as part of printing. Returns the maximum alias depth found while
+  /// printing the given value.
+  template <typename T, typename... PrintArgs>
+  size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
+    printAndVisitNestedAliasesImpl(value, printArgs...);
+    return maxAliasDepth;
+  }
+
+private:
+  /// Print the given attribute/type, visiting any nested aliases that would be
+  /// generated as part of printing.
+  void printAndVisitNestedAliasesImpl(Attribute attr, bool elideType) {
+    if (!isa<BuiltinDialect>(attr.getDialect()))
+      return attr.getDialect().printAttribute(attr, *this);
+
+    // Process the builtin attributes.
+    if (attr.isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
+                 IntegerSetAttr, UnitAttr>())
+      return;
+    if (auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
+      for (const NamedAttribute &nestedAttr : dictAttr.getValue()) {
+        printAttribute(nestedAttr.getName());
+        printAttribute(nestedAttr.getValue());
+      }
+    } else if (auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
+      for (Attribute nestedAttr : arrayAttr.getValue())
+        printAttribute(nestedAttr);
+    } else if (auto typeAttr = dyn_cast<TypeAttr>(attr)) {
+      printType(typeAttr.getValue());
+    } else if (auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
+      printAttribute(locAttr.getFallbackLocation());
+    } else if (auto locAttr = dyn_cast<NameLoc>(attr)) {
+      if (!isa<UnknownLoc>(locAttr.getChildLoc()))
+        printAttribute(locAttr.getChildLoc());
+    } else if (auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
+      printAttribute(locAttr.getCallee());
+      printAttribute(locAttr.getCaller());
+    } else if (auto locAttr = dyn_cast<FusedLoc>(attr)) {
+      if (Attribute metadata = locAttr.getMetadata())
+        printAttribute(metadata);
+      for (Location nestedLoc : locAttr.getLocations())
+        printAttribute(nestedLoc);
+    }
+
+    // Don't print the type if we must elide it, or if it is a None type.
+    if (!elideType) {
+      if (auto typedAttr = attr.dyn_cast<TypedAttr>()) {
+        Type attrType = typedAttr.getType();
+        if (!attrType.isa<NoneType>())
+          printType(attrType);
+      }
+    }
+  }
+  void printAndVisitNestedAliasesImpl(Type type) {
+    if (!isa<BuiltinDialect>(type.getDialect()))
+      return type.getDialect().printType(type, *this);
+
+    // Only visit the layout of memref if it isn't the identity.
+    if (auto memrefTy = type.dyn_cast<MemRefType>()) {
+      printType(memrefTy.getElementType());
+      MemRefLayoutAttrInterface layout = memrefTy.getLayout();
+      if (!layout.isa<AffineMapAttr>() || !layout.isIdentity())
+        printAttribute(memrefTy.getLayout());
+      if (memrefTy.getMemorySpace())
+        printAttribute(memrefTy.getMemorySpace());
+      return;
+    }
+
+    // For most builtin types, we can simply walk the sub elements.
+    if (auto subElementInterface = dyn_cast<SubElementTypeInterface>(type)) {
+      auto visitFn = [&](auto element) {
+        if (element)
+          (void)printAlias(element);
+      };
+      subElementInterface.walkImmediateSubElements(visitFn, visitFn);
+    }
+  }
+
+  /// Consider the given type to be printed for an alias.
+  void printType(Type type) override {
+    recordAliasResult(initializer.visit(type, canBeDeferred));
+  }
+
+  /// Consider the given attribute to be printed for an alias.
+  void printAttribute(Attribute attr) override {
+    recordAliasResult(initializer.visit(attr, canBeDeferred));
+  }
+  void printAttributeWithoutType(Attribute attr) override {
+    recordAliasResult(
+        initializer.visit(attr, canBeDeferred, /*elideType=*/true));
+  }
+  LogicalResult printAlias(Attribute attr) override {
+    printAttribute(attr);
+    return success();
+  }
+  LogicalResult printAlias(Type type) override {
+    printType(type);
+    return success();
+  }
+
+  /// Record the alias result of a child element.
+  void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
+    childIndices.push_back(aliasDepthAndIndex.second);
+    if (aliasDepthAndIndex.first > maxAliasDepth)
+      maxAliasDepth = aliasDepthAndIndex.first;
+  }
+
+  /// Return a null stream as the output stream, this will ignore any data fed
+  /// to it.
+  raw_ostream &getStream() const override { return os; }
+
+  /// The following are hooks of `DialectAsmPrinter` that are not necessary for
+  /// determining potential aliases.
+  void printFloat(const APFloat &) override {}
+  void printKeywordOrString(StringRef) override {}
+  void printSymbolName(StringRef) override {}
+  void printResourceHandle(const AsmDialectResourceHandle &) override {}
+
+  /// The initializer to use when identifying aliases.
+  AliasInitializer &initializer;
+
+  /// If the aliases visited by this printer can be deferred.
+  bool canBeDeferred;
+
+  /// The indices of child aliases.
+  SmallVectorImpl<size_t> &childIndices;
+
+  /// The maximum alias depth found by the printer.
+  size_t maxAliasDepth = 0;
+
+  /// A dummy output stream.
+  mutable llvm::raw_null_ostream os;
+};
 } // namespace
 
 /// Sanitize the given name such that it can be used as a valid identifier. If
@@ -836,48 +995,48 @@ void AliasInitializer::initialize(
   initializeAliases(aliases, attrTypeToAlias);
 }
 
-template <typename T>
-size_t AliasInitializer::visitImpl(
+template <typename T, typename... PrintArgs>
+std::pair<size_t, size_t> AliasInitializer::visitImpl(
     T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
-    bool canBeDeferred) {
+    bool canBeDeferred, PrintArgs &&...printArgs) {
   auto [it, inserted] =
       aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
+  size_t aliasIndex = std::distance(aliases.begin(), it);
   if (!inserted) {
     // Make sure that the alias isn't deferred if we don't permit it.
     if (!canBeDeferred)
-      it->second.canBeDeferred = false;
-    return it->second.aliasDepth;
+      markAliasNonDeferrable(aliasIndex);
+    return {static_cast<size_t>(it->second.aliasDepth), aliasIndex};
   }
 
-  // Try to generate an alias for this attribute.
+  // Try to generate an alias for this value.
   generateAlias(value, it->second, canBeDeferred);
-  size_t aliasIndex = std::distance(aliases.begin(), it);
 
-  // Check for any sub elements.
-  using SubElementInterfaceT =
-      std::conditional_t<std::is_same_v<T, Type>, SubElementTypeInterface,
-                         SubElementAttrInterface>;
-  if (auto subElementInterface = dyn_cast<SubElementInterfaceT>(value)) {
-    size_t maxAliasDepth = 0;
-    auto visitSubElement = [&](auto element) {
-      if (!element)
-        return;
-      if (size_t depth = visit(element))
-        maxAliasDepth = std::max(maxAliasDepth, depth + 1);
-    };
-    subElementInterface.walkImmediateSubElements(visitSubElement,
-                                                 visitSubElement);
+  // Print the value, capturing any nested elements that require aliases.
+  SmallVector<size_t> childAliases;
+  DummyAliasDialectAsmPrinter printer(*this, canBeDeferred, childAliases);
+  size_t maxAliasDepth =
+      printer.printAndVisitNestedAliases(value, printArgs...);
 
-    // Make sure to recompute `it` in case the map was reallocated.
-    it = std::next(aliases.begin(), aliasIndex);
+  // Make sure to recompute `it` in case the map was reallocated.
+  it = std::next(aliases.begin(), aliasIndex);
 
-    // If we had sub elements, update to account for the depth.
-    if (maxAliasDepth)
-      it->second.aliasDepth = maxAliasDepth;
-  }
+  // If we had sub elements, update to account for the depth.
+  it->second.childIndices = std::move(childAliases);
+  if (maxAliasDepth)
+    it->second.aliasDepth = maxAliasDepth + 1;
 
   // Propagate the alias depth of the value.
-  return it->second.aliasDepth;
+  return {(size_t)it->second.aliasDepth, aliasIndex};
+}
+
+void AliasInitializer::markAliasNonDeferrable(size_t aliasIndex) {
+  auto it = std::next(aliases.begin(), aliasIndex);
+  it->second.canBeDeferred = false;
+
+  // Propagate the non-deferrable flag to any child aliases.
+  for (size_t childIndex : it->second.childIndices)
+    markAliasNonDeferrable(childIndex);
 }
 
 template <typename T>
@@ -1681,7 +1840,12 @@ void AsmPrinter::Impl::printTrailingLocation(Location loc, bool allowAlias) {
   printLocation(loc, /*allowAlias=*/allowAlias);
 }
 
-void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty) {
+void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty,
+                                             bool isTopLevel) {
+  // If this isn't a top-level location, check for an alias.
+  if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
+    return;
+
   TypeSwitch<LocationAttr>(loc)
       .Case<OpaqueLoc>([&](OpaqueLoc loc) {
         printLocationInternal(loc.getFallbackLocation(), pretty);
@@ -1802,11 +1966,11 @@ static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
 
 void AsmPrinter::Impl::printLocation(LocationAttr loc, bool allowAlias) {
   if (printerFlags.shouldPrintDebugInfoPrettyForm())
-    return printLocationInternal(loc, /*pretty=*/true);
+    return printLocationInternal(loc, /*pretty=*/true, /*isTopLevel=*/true);
 
   os << "loc(";
   if (!allowAlias || failed(printAlias(loc)))
-    printLocationInternal(loc);
+    printLocationInternal(loc, /*pretty=*/false, /*isTopLevel=*/true);
   os << ')';
 }
 
index ec66bae..613dc35 100644 (file)
@@ -2,10 +2,12 @@
 
 // Round-tripping the syntax.
 
+// CHECK: #[[MAP:.*]] = affine_map<(d0) -> (d0)>
+
 "test.unknown_op"() {
   // CHECK: #dlti.dl_entry<"test.identifier", 42 : i64>
   test.unknown_attr_1 = #dlti.dl_entry<"test.identifier", 42 : i64>,
-  // CHECK: #dlti.dl_entry<"test.identifier", affine_map<(d0) -> (d0)>>
+  // CHECK: #dlti.dl_entry<"test.identifier", #[[MAP]]>
   test.unknown_attr_2 = #dlti.dl_entry<"test.identifier", affine_map<(d0) -> (d0)>>,
   // CHECK: #dlti.dl_entry<i32, 32 : index>
   test.unknown_attr_3 = #dlti.dl_entry<i32, 32 : index>,
index 612927c..824fd40 100644 (file)
@@ -84,7 +84,7 @@
 // CHECK:             } attributes {"Emitted from" = "linalg.generic"}
 // CHECK:             %[[VAL_59:.*]] = vector.insertelement %[[VAL_60:.*]]#2, %[[VAL_4]]{{\[}}%[[VAL_6]] : index] : vector<8xf64>
 // CHECK:             %[[VAL_61:.*]] = scf.for %[[VAL_62:.*]] = %[[VAL_60]]#0 to %[[VAL_21]] step %[[VAL_3]] iter_args(%[[VAL_63:.*]] = %[[VAL_59]]) -> (vector<8xf64>) {
-// CHECK:               %[[VAL_64:.*]] = affine.min #map2(%[[VAL_21]], %[[VAL_62]]){{\[}}%[[VAL_3]]]
+// CHECK:               %[[VAL_64:.*]] = affine.min #map(%[[VAL_21]], %[[VAL_62]]){{\[}}%[[VAL_3]]]
 // CHECK:               %[[VAL_65:.*]] = vector.create_mask %[[VAL_64]] : vector<8xi1>
 // CHECK:               %[[VAL_66:.*]] = vector.maskedload %[[VAL_10]]{{\[}}%[[VAL_62]]], %[[VAL_65]], %[[VAL_4]] : memref<?xf64>, vector<8xi1>, vector<8xf64> into vector<8xf64>
 // CHECK:               %[[VAL_67:.*]] = arith.addf %[[VAL_63]], %[[VAL_66]] : vector<8xf64>
@@ -92,7 +92,7 @@
 // CHECK:               scf.yield %[[VAL_68]] : vector<8xf64>
 // CHECK:             } {"Emitted from" = "linalg.generic"}
 // CHECK:             %[[VAL_69:.*]] = scf.for %[[VAL_70:.*]] = %[[VAL_60]]#1 to %[[VAL_23]] step %[[VAL_3]] iter_args(%[[VAL_71:.*]] = %[[VAL_61]]) -> (vector<8xf64>) {
-// CHECK:               %[[VAL_73:.*]] = affine.min #map2(%[[VAL_23]], %[[VAL_70]]){{\[}}%[[VAL_3]]]
+// CHECK:               %[[VAL_73:.*]] = affine.min #map(%[[VAL_23]], %[[VAL_70]]){{\[}}%[[VAL_3]]]
 // CHECK:               %[[VAL_74:.*]] = vector.create_mask %[[VAL_73]] : vector<8xi1>
 // CHECK:               %[[VAL_75:.*]] = vector.maskedload %[[VAL_13]]{{\[}}%[[VAL_70]]], %[[VAL_74]], %[[VAL_4]] : memref<?xf64>, vector<8xi1>, vector<8xf64> into vector<8xf64>
 // CHECK:               %[[VAL_76:.*]] = arith.addf %[[VAL_71]], %[[VAL_75]] : vector<8xf64>
index 37d5b80..7bb8254 100644 (file)
@@ -33,7 +33,7 @@
 // CHECK:           %[[VAL_12:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_5]]] : memref<?xindex>
 // CHECK:           %[[VAL_13:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_6]]] : memref<?xindex>
 // CHECK:           scf.for %[[VAL_14:.*]] = %[[VAL_12]] to %[[VAL_13]] step %[[VAL_1]] {
-// CHECK:             %[[VAL_15:.*]] = affine.min #map1(%[[VAL_13]], %[[VAL_14]]){{\[}}%[[VAL_1]]]
+// CHECK:             %[[VAL_15:.*]] = affine.min #map(%[[VAL_13]], %[[VAL_14]]){{\[}}%[[VAL_1]]]
 // CHECK:             %[[VAL_16:.*]] = vector.create_mask %[[VAL_15]] : vector<8xi1>
 // CHECK:             %[[VAL_17:.*]] = vector.maskedload %[[VAL_9]]{{\[}}%[[VAL_14]]], %[[VAL_16]], %[[VAL_3]] : memref<?xindex>, vector<8xi1>, vector<8xindex> into vector<8xindex>
 // CHECK:             %[[VAL_18:.*]] = vector.maskedload %[[VAL_10]]{{\[}}%[[VAL_14]]], %[[VAL_16]], %[[VAL_2]] : memref<?xi64>, vector<8xi1>, vector<8xi64> into vector<8xi64>
@@ -99,7 +99,7 @@ func.func @sparse_index_1d_conj(%arga: tensor<8xi64, #SparseVector>) -> tensor<8
 // CHECK:             scf.yield %[[VAL_27]], %[[VAL_28]] : index, index
 // CHECK:           } attributes {"Emitted from" = "linalg.generic"}
 // CHECK:           scf.for %[[VAL_29:.*]] = %[[VAL_30:.*]]#1 to %[[VAL_1]] step %[[VAL_1]] {
-// CHECK:             %[[VAL_31:.*]] = affine.min #map1(%[[VAL_1]], %[[VAL_29]]){{\[}}%[[VAL_1]]]
+// CHECK:             %[[VAL_31:.*]] = affine.min #map(%[[VAL_1]], %[[VAL_29]]){{\[}}%[[VAL_1]]]
 // CHECK:             %[[VAL_32:.*]] = vector.create_mask %[[VAL_31]] : vector<8xi1>
 // CHECK:             %[[VAL_33:.*]] = vector.broadcast %[[VAL_29]] : index to vector<8xindex>
 // CHECK:             %[[VAL_34:.*]] = arith.addi %[[VAL_33]], %[[VAL_2]] : vector<8xindex>
index f3feb60..e9337b5 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: mlir-opt -allow-unregistered-dialect %s -mlir-print-debuginfo -mlir-pretty-debuginfo | FileCheck %s
+// RUN: mlir-opt -allow-unregistered-dialect %s -mlir-print-debuginfo -mlir-pretty-debuginfo -mlir-print-local-scope | FileCheck %s
 
 #set0 = affine_set<(d0) : (1 == 0)>
 
index b9893f2..b1631b2 100644 (file)
@@ -29,8 +29,9 @@
 // CHECK-DAG: tensor<32x!test_ui8_>
 "test.op"() : () -> tensor<32x!test.int<unsigned, 8>>
 
-// CHECK-DAG: #loc2 = loc("nested")
-// CHECK-DAG: #loc3 = loc(fused<#loc2>["test.mlir":10:8])
+// CHECK-DAG: #loc = loc("nested")
+// CHECK-DAG: #loc1 = loc("test.mlir":10:8)
+// CHECK-DAG: #loc2 = loc(fused<#loc>[#loc1])
 "test.op"() {alias_test = loc(fused<loc("nested")>["test.mlir":10:8])} : () -> ()
 
 // -----
 // CHECK: !tuple = tuple<
 // CHECK: #loc1 = loc(fused<!tuple
 "test.op"() {alias_test = loc(fused<tuple<i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32>>["test.mlir":10:8])} : () -> ()
+
+// -----
+
+// Check that we don't print aliases for things that aren't printed.
+// CHECK: #loc1 = loc(fused<memref<1xi32>
+// CHECK-NOT: #map
+"test.op"() {alias_test = loc(fused<memref<1xi32, affine_map<(d0) -> (d0)>>>["test.mlir":10:8])} : () -> ()
index 415b40c..f7513d5 100644 (file)
@@ -1,6 +1,5 @@
 ; RUN: mlir-translate -import-llvm -mlir-print-debuginfo -split-input-file %s | FileCheck %s
 
-; CHECK: #[[$UNKNOWNLOC:.+]] = loc(unknown)
 ; CHECK-LABEL: @unknown(
 define i32 @unknown(i32 %0) {
 entry:
@@ -10,28 +9,35 @@ end:
   %1 = phi i32 [ %2, %next ]
   ret i32 %1
 next:
-  ; CHECK: = llvm.mul %{{.+}}, %{{.+}} : i32 loc(#[[$UNKNOWNLOC:.+]])
+  ; CHECK: = llvm.mul %{{.+}}, %{{.+}} : i32 loc(#[[UNKNOWNLOC:.+]])
   %2 = mul i32 %0, %0
   br label %end
 }
 
-; // -----
+; CHECK: #[[UNKNOWNLOC:.+]] = loc(unknown)
 
-; CHECK: #[[$SP:.+]] =  #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
-; CHECK: #[[$CALLEE:.+]] =  #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
+; // -----
 
 ; CHECK-LABEL: @instruction_loc
 define i32 @instruction_loc(i32 %arg1) {
-  ; CHECK llvm.add {{.*}} loc(#[[FILE_LOC:.*]])
+  ; CHECK: llvm.add {{.*}} loc(#[[FILE_LOC:.*]])
   %1 = add i32 %arg1, %arg1, !dbg !5
 
-  ; CHECK llvm.mul {{.*}} loc(#[[CALLSITE_LOC:.*]])
+  ; CHECK: llvm.mul {{.*}} loc(#[[CALLSITE_LOC:.*]])
   %2 = mul i32 %1, %1, !dbg !7
 
   ret i32 %2
 }
-; CHECK #[[FILE_LOC]] = loc(fused<#[[$SP]]>["debug-info.ll":1:2])
-; CHECK #[[CALLSITE_LOC]] = loc(fused<#[[$CALLEE]]>[callsite("debug-info.ll":7:4 at fused<#[[$SP]]>["debug-info.ll":2:2])])
+
+; CHECK-DAG: #[[RAW_FILE_LOC:.+]] = loc("debug-info.ll":1:2)
+; CHECK-DAG: #[[SP:.+]] =  #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
+; CHECK-DAG: #[[CALLEE:.+]] =  #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
+; CHECK-DAG: #[[FILE_LOC]] = loc(fused<#[[SP]]>[#[[RAW_FILE_LOC]]])
+; CHECK-DAG: #[[CALLEE_LOC:.+]] = loc("debug-info.ll":7:4)
+; CHECK-DAG: #[[RAW_CALLER_LOC:.+]] = loc("debug-info.ll":2:2)
+; CHECK-DAG: #[[CALLER_LOC:.+]] = loc(fused<#[[SP]]>[#[[RAW_CALLER_LOC]]])
+; CHECK-DAG: #[[RAW_CALLSITE_LOC:.+]] = loc(callsite(#[[CALLEE_LOC]] at #[[CALLER_LOC]]))
+; CHECK-DAG: #[[CALLSITE_LOC]] = loc(fused<#[[CALLEE]]>[#[[RAW_CALLSITE_LOC]]])
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -46,23 +52,22 @@ define i32 @instruction_loc(i32 %arg1) {
 
 ; // -----
 
-; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
-; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
-; CHECK: #[[$LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]]>
-; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
-
 ; CHECK-LABEL: @lexical_block
 define i32 @lexical_block(i32 %arg1) {
-  ; CHECK llvm.add {{.*}} loc(#[[LOC0:.*]])
+  ; CHECK: llvm.add {{.*}} loc(#[[LOC0:.*]])
   %1 = add i32 %arg1, %arg1, !dbg !6
 
-  ; CHECK llvm.mul {{.*}} loc(#[[LOC1:.*]])
+  ; CHECK: llvm.mul {{.*}} loc(#[[LOC1:.*]])
   %2 = mul i32 %arg1, %arg1, !dbg !7
 
   ret i32 %2
 }
-; CHECK #[[LOC0]] = loc(fused<#[[$LB0]]>["debug-info.ll":1:2])
-; CHECK #[[LOC1]] = loc(fused<#[[$LB1]]>["debug-info.ll":1:2])
+; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
+; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
+; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]]>
+; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
+; CHECK: #[[LOC0]] = loc(fused<#[[LB0]]>[{{.*}}])
+; CHECK: #[[LOC1]] = loc(fused<#[[LB1]]>[{{.*}}])
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -77,23 +82,22 @@ define i32 @lexical_block(i32 %arg1) {
 
 ; // -----
 
-; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
-; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
-; CHECK: #[[$LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
-; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
-
 ; CHECK-LABEL: @lexical_block_file
 define i32 @lexical_block_file(i32 %arg1) {
-  ; CHECK llvm.add {{.*}} loc(#[[LOC0:.*]])
+  ; CHECK: llvm.add {{.*}} loc(#[[LOC0:.*]])
   %1 = add i32 %arg1, %arg1, !dbg !6
 
-  ; CHECK llvm.mul {{.*}} loc(#[[LOC1:.*]])
+  ; CHECK: llvm.mul {{.*}} loc(#[[LOC1:.*]])
   %2 = mul i32 %arg1, %arg1, !dbg !7
 
   ret i32 %2
 }
-; CHECK #[[LOC0]] = loc(fused<#[[$LB0]]>["debug-info.ll":1:2]))
-; CHECK #[[LOC1]] = loc(fused<#[[$LB1]]>["debug-info.ll":2:2]))
+; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
+; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
+; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
+; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
+; CHECK: #[[LOC0]] = loc(fused<#[[LB0]]>[
+; CHECK: #[[LOC1]] = loc(fused<#[[LB1]]>[
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -206,13 +210,12 @@ define void @subprogram() !dbg !3 {
 
 ; // -----
 
-; CHECK: #[[$SP:.+]] =  #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, subprogramFlags = Definition>
-
 ; CHECK-LABEL: @func_loc
 define void @func_loc() !dbg !3 {
   ret void
 }
-; CHECK: loc(fused<#[[$SP]]>["func_loc"])
+; CHECK: #[[SP:.+]] =  #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, subprogramFlags = Definition>
+; CHECK: loc(fused<#[[SP]]>[
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -246,9 +249,9 @@ define void @intrinsic(i64 %0, ptr %1) {
   ret void
 }
 
-; CHECK: #[[LOC0]] = loc(fused<#[[$SP]]>["debug-info.ll":1:2])
-; CHECK: #[[LOC1]] = loc(fused<#[[$SP]]>["debug-info.ll":2:2])
-; CHECK: #[[LOC2]] = loc(fused<#[[$SP]]>["debug-info.ll":3:2])
+; CHECK: #[[LOC0]] = loc(fused<#[[$SP]]>[{{.*}}])
+; CHECK: #[[LOC1]] = loc(fused<#[[$SP]]>[{{.*}}])
+; CHECK: #[[LOC2]] = loc(fused<#[[$SP]]>[{{.*}}])
 
 declare void @llvm.dbg.value(metadata, metadata, metadata)
 declare void @llvm.dbg.addr(metadata, metadata, metadata)