[Mlir-commits] [mlir] 1784573 - [mlir][LLVMIR] Fix loop follow-up metadata import and export (#223376)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sun Sep 20 23:58:37 PDT 2026


Author: ArdenYang
Date: 2026-09-21T08:58:31+02:00
New Revision: 1784573db1506040f89bc476fc490ce104206380

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

LOG: [mlir][LLVMIR] Fix loop follow-up metadata import and export (#223376)

## Problem

MLIR currently exports loop follow-up metadata by wrapping its
properties in an additional self-referencing loop ID:

```llvm
!1 = !{!"llvm.loop.unroll.followup_unrolled", !2}
!2 = distinct !{!2, !3}
!3 = !{!"llvm.loop.mustprogress"}
```

LLVM expects the properties directly after the follow-up name:

```llvm
!1 = !{!"llvm.loop.unroll.followup_unrolled", !3}
!3 = !{!"llvm.loop.mustprogress"}
```

`makeFollowupLoopID` copies the follow-up operands without unwrapping a
nested loop ID. Consequently, properties such as
`llvm.loop.mustprogress` inside the extra wrapper are not recognized as
properties of the resulting loop.

## Changes

- Export follow-up properties directly, excluding the temporary loop
ID's self-reference.
- Update import to read direct property lists.
- Preserve explicitly empty follow-ups, multiple properties, nested
follow-ups, and debug locations.
- Diagnose malformed follow-up metadata and detect cycles to prevent
infinite recursion.

An explicitly empty follow-up is different from an absent follow-up: it
specifies an empty configuration instead of leaving the transformation
to use its default follow-up attributes. Import therefore preserves it
as a non-null, empty `LoopAnnotationAttr`.

This patch corrects MLIR's representation of existing LLVM follow-up
metadata. It does not change LLVM's transformation policies or introduce
automatic attribute inheritance.

## Testing

Built `mlir-translate`, `FileCheck`, `count`, and `not` on Linux using a
Release build with assertions enabled.

All three targeted regression tests passed:

- `mlir/test/Target/LLVMIR/loop-metadata.mlir`
- `mlir/test/Target/LLVMIR/Import/metadata-loop.ll`
- `mlir/test/Target/LLVMIR/Import/import-failure.ll`

`git diff --check` also passed. The full MLIR test suite was not run.

Assisted-by: OpenAI Codex

---------

Co-authored-by: yangzihan <yangzihan at sunmmio.com>

Added: 
    

Modified: 
    mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
    mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
    mlir/test/Target/LLVMIR/Import/import-failure.ll
    mlir/test/Target/LLVMIR/Import/metadata-loop.ll
    mlir/test/Target/LLVMIR/loop-metadata.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
index 6658b4a920e37..d540f211e9599 100644
--- a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "LoopAnnotationImporter.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/IR/Constants.h"
 
 using namespace mlir;
@@ -16,12 +18,23 @@ using namespace mlir::LLVM::detail;
 namespace {
 /// Helper class that keeps the state of one metadata to attribute conversion.
 struct LoopMetadataConversion {
-  LoopMetadataConversion(const llvm::MDNode *node, Location loc,
-                         LoopAnnotationImporter &loopAnnotationImporter)
+  /// Converts a loop ID, owning the recursion state for its follow-ups.
+  static LoopAnnotationAttr convert(const llvm::MDNode *node, Location loc,
+                                    LoopAnnotationImporter &importer);
+
+private:
+  LoopMetadataConversion(
+      const llvm::MDNode *node, Location loc,
+      LoopAnnotationImporter &loopAnnotationImporter,
+      llvm::SmallPtrSetImpl<const llvm::MDNode *> &activeNodes)
       : node(node), loc(loc), loopAnnotationImporter(loopAnnotationImporter),
-        ctx(loc->getContext()){};
-  /// Converts this structs loop metadata node into a LoopAnnotationAttr.
-  LoopAnnotationAttr convert();
+        ctx(loc->getContext()), activeNodes(activeNodes) {}
+
+  /// Converts a follow-up using the current recursion state.
+  LoopAnnotationAttr convertFollowup(const llvm::MDNode *followup);
+
+  /// Converts the properties after the validated loop ID or follow-up header.
+  LoopAnnotationAttr convertProperties();
 
   /// Initializes the shared state for the conversion member functions.
   LogicalResult initConversionState();
@@ -36,7 +49,6 @@ struct LoopMetadataConversion {
   FailureOr<BoolAttr> lookupBoolNode(StringRef name, bool negated = false);
   FailureOr<BoolAttr> lookupIntNodeAsBoolAttr(StringRef name);
   FailureOr<IntegerAttr> lookupIntNode(StringRef name);
-  FailureOr<llvm::MDNode *> lookupMDNode(StringRef name);
   FailureOr<SmallVector<llvm::MDNode *>> lookupMDNodes(StringRef name);
   FailureOr<LoopAnnotationAttr> lookupFollowupNode(StringRef name);
   FailureOr<BoolAttr> lookupBooleanUnitNode(StringRef enableName,
@@ -63,15 +75,11 @@ struct LoopMetadataConversion {
   Location loc;
   LoopAnnotationImporter &loopAnnotationImporter;
   MLIRContext *ctx;
+  llvm::SmallPtrSetImpl<const llvm::MDNode *> &activeNodes;
 };
 } // namespace
 
 LogicalResult LoopMetadataConversion::initConversionState() {
-  // Check if it's a valid node.
-  if (node->getNumOperands() == 0 ||
-      dyn_cast<llvm::MDNode>(node->getOperand(0)) != node)
-    return emitWarning(loc) << "invalid loop node";
-
   for (const llvm::MDOperand &operand : llvm::drop_begin(node->operands())) {
     if (auto *diLoc = dyn_cast<llvm::DILocation>(operand)) {
       locations.push_back(diLoc);
@@ -206,26 +214,6 @@ FailureOr<IntegerAttr> LoopMetadataConversion::lookupIntNode(StringRef name) {
                           val->getValue().getLimitedValue());
 }
 
-FailureOr<llvm::MDNode *> LoopMetadataConversion::lookupMDNode(StringRef name) {
-  const llvm::MDNode *property = lookupAndEraseProperty(name);
-  if (!property)
-    return nullptr;
-
-  auto emitNodeWarning = [&]() {
-    return emitWarning(loc)
-           << "expected metadata node " << name << " to hold an MDNode";
-  };
-
-  if (property->getNumOperands() != 2)
-    return emitNodeWarning();
-
-  auto *node = dyn_cast<llvm::MDNode>(property->getOperand(1));
-  if (!node)
-    return emitNodeWarning();
-
-  return node;
-}
-
 FailureOr<SmallVector<llvm::MDNode *>>
 LoopMetadataConversion::lookupMDNodes(StringRef name) {
   const llvm::MDNode *property = lookupAndEraseProperty(name);
@@ -253,13 +241,14 @@ LoopMetadataConversion::lookupMDNodes(StringRef name) {
 
 FailureOr<LoopAnnotationAttr>
 LoopMetadataConversion::lookupFollowupNode(StringRef name) {
-  auto node = lookupMDNode(name);
-  if (failed(node))
-    return failure();
-  if (*node == nullptr)
+  const llvm::MDNode *followup = lookupAndEraseProperty(name);
+  if (!followup)
     return LoopAnnotationAttr(nullptr);
 
-  return loopAnnotationImporter.translateLoopAnnotation(*node, loc);
+  LoopAnnotationAttr attr = convertFollowup(followup);
+  if (!attr)
+    return failure();
+  return attr;
 }
 
 static bool isEmptyOrNull(const Attribute attr) { return !attr; }
@@ -431,7 +420,45 @@ FailureOr<FusedLoc> LoopMetadataConversion::convertEndLoc() {
       loopAnnotationImporter.moduleImport.translateLoc(locations[1]));
 }
 
-LoopAnnotationAttr LoopMetadataConversion::convert() {
+LoopAnnotationAttr
+LoopMetadataConversion::convert(const llvm::MDNode *node, Location loc,
+                                LoopAnnotationImporter &importer) {
+  if (node->getNumOperands() == 0 ||
+      dyn_cast<llvm::MDNode>(node->getOperand(0)) != node) {
+    emitWarning(loc) << "invalid loop node";
+    return {};
+  }
+
+  llvm::SmallPtrSet<const llvm::MDNode *, 4> activeNodes;
+  return LoopMetadataConversion(node, loc, importer, activeNodes)
+      .convertProperties();
+}
+
+LoopAnnotationAttr
+LoopMetadataConversion::convertFollowup(const llvm::MDNode *followup) {
+  if (followup->getNumOperands() == 0 ||
+      !isa<llvm::MDString>(followup->getOperand(0))) {
+    emitWarning(loc) << "invalid loop followup node";
+    return {};
+  }
+
+  // An explicit empty follow-up is 
diff erent from an absent follow-up.
+  if (followup->getNumOperands() == 1)
+    return LoopAnnotationAttr::get(ctx, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
+                                   {}, {}, {}, {}, {});
+
+  return LoopMetadataConversion(followup, loc, loopAnnotationImporter,
+                                activeNodes)
+      .convertProperties();
+}
+
+LoopAnnotationAttr LoopMetadataConversion::convertProperties() {
+  if (!activeNodes.insert(node).second) {
+    emitWarning(loc) << "cannot import cyclic loop annotation";
+    return {};
+  }
+  llvm::scope_exit guard([&] { activeNodes.erase(node); });
+
   if (failed(initConversionState()))
     return {};
 
@@ -481,7 +508,7 @@ LoopAnnotationImporter::translateLoopAnnotation(const llvm::MDNode *node,
   if (it != loopMetadataMapping.end())
     return it->getSecond();
 
-  LoopAnnotationAttr attr = LoopMetadataConversion(node, loc, *this).convert();
+  LoopAnnotationAttr attr = LoopMetadataConversion::convert(node, loc, *this);
 
   mapLoopMetadata(node, attr);
   return attr;

diff  --git a/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp b/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
index 475799e7fdbfd..b4975cb1a8ea9 100644
--- a/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
@@ -110,11 +110,15 @@ void LoopAnnotationConversion::convertFollowupNode(StringRef name,
   if (!attr)
     return;
 
-  llvm::MDNode *node =
+  llvm::MDNode *loopID =
       loopAnnotationTranslation.translateLoopAnnotation(attr, op);
 
-  metadataNodes.push_back(
-      llvm::MDNode::get(ctx, {llvm::MDString::get(ctx, name), node}));
+  // Follow-ups contain properties directly, without the LoopID self-reference.
+  SmallVector<llvm::Metadata *> operands;
+  operands.push_back(llvm::MDString::get(ctx, name));
+  for (const llvm::MDOperand &operand : llvm::drop_begin(loopID->operands()))
+    operands.push_back(operand.get());
+  metadataNodes.push_back(llvm::MDNode::get(ctx, operands));
 }
 
 void LoopAnnotationConversion::convertLoopOptions(LoopVectorizeAttr options) {

diff  --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 5bf45ccfbec55..7dca9a3ed2be6 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -175,7 +175,7 @@ end:
 ; // -----
 
 ; CHECK:      <unknown>
-; CHECK-SAME: warning: expected metadata node llvm.loop.vectorize.followup_all to hold an MDNode
+; CHECK-SAME: warning: expected all loop properties to be either debug locations or metadata nodes
 ; CHECK:      <unknown>
 ; CHECK-SAME: warning: unhandled metadata: ![[FOLLOWUP_LOOP:[0-9]+]] = distinct !{![[FOLLOWUP_LOOP]], ![[FOLLOWUP_PROP:[0-9]+]]}
 define void @unsupported_loop_annotation(i64 %n, ptr %A) {
@@ -190,6 +190,42 @@ end:
 
 ; // -----
 
+; A whole LoopID is not a named property in a followup's direct attribute list.
+; CHECK:      <unknown>
+; CHECK-SAME: warning: cannot import loop property without a name
+; CHECK:      <unknown>
+; CHECK-SAME: warning: unhandled metadata: ![[WRAPPED_LOOP:[0-9]+]] = distinct !{![[WRAPPED_LOOP]], ![[WRAPPED_PROP:[0-9]+]]}
+define void @followup_with_loop_id() {
+entry:
+  br label %end, !llvm.loop !0
+end:
+  ret void
+}
+
+!0 = distinct !{!0, !1}
+!1 = !{!"llvm.loop.unroll.followup_unrolled", !2}
+!2 = distinct !{!2, !3}
+!3 = !{!"llvm.loop.mustprogress"}
+
+; // -----
+
+; Reject recursive followup metadata instead of recursing indefinitely.
+; CHECK:      <unknown>
+; CHECK-SAME: warning: cannot import cyclic loop annotation
+; CHECK:      <unknown>
+; CHECK-SAME: warning: unhandled metadata: ![[CYCLIC_LOOP:[0-9]+]] = distinct !{![[CYCLIC_LOOP]], ![[CYCLIC_PROP:[0-9]+]]}
+define void @cyclic_followup() {
+entry:
+  br label %end, !llvm.loop !0
+end:
+  ret void
+}
+
+!0 = distinct !{!0, !1}
+!1 = distinct !{!"llvm.loop.unroll.followup_unrolled", !1}
+
+; // -----
+
 ; CHECK:      <unknown>
 ; CHECK-SAME: warning: expected metadata node llvm.loop.parallel_accesses to hold one or multiple MDNodes
 ; CHECK:      <unknown>

diff  --git a/mlir/test/Target/LLVMIR/Import/metadata-loop.ll b/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
index 89357186409e3..ba601fedecb29 100644
--- a/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
+++ b/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
@@ -1,4 +1,5 @@
 ; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+; RUN: mlir-translate -import-llvm -mlir-to-llvmir -split-input-file %s | FileCheck %s --check-prefix=ROUNDTRIP
 
 ; CHECK-DAG: #[[$GROUP0:.*]] = #llvm.access_group<id = {{.*}}>
 ; CHECK-DAG: #[[$GROUP1:.*]] = #llvm.access_group<id = {{.*}}>
@@ -94,8 +95,7 @@ end:
 !7 = !{!"llvm.loop.vectorize.followup_epilogue", !9}
 !8 = !{!"llvm.loop.vectorize.followup_all", !9}
 
-!9 = distinct !{!9, !10}
-!10 = !{!"llvm.loop.disable_nonforced"}
+!9 = !{!"llvm.loop.disable_nonforced"}
 
 ; // -----
 
@@ -138,8 +138,7 @@ end:
 !7 = !{!"llvm.loop.unroll.followup_remainder", !9}
 !8 = !{!"llvm.loop.unroll.followup_all", !9}
 
-!9 = distinct !{!9, !10}
-!10 = !{!"llvm.loop.disable_nonforced"}
+!9 = !{!"llvm.loop.disable_nonforced"}
 
 ; // -----
 
@@ -160,6 +159,69 @@ end:
 
 ; // -----
 
+; An explicitly empty followup must survive import and export, rather than
+; disappear or acquire a self-referential LoopID wrapper.
+; CHECK-DAG: #[[EMPTY:.*]] = #llvm.loop_annotation<>
+; CHECK-DAG: #[[UNROLL_ATTR:.*]] = #llvm.loop_unroll<count = 8 : i32, followupUnrolled = #[[EMPTY]]>
+; CHECK-DAG: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<unroll = #[[UNROLL_ATTR]]>
+; CHECK-LABEL: @unroll_empty_followup
+; ROUNDTRIP-LABEL: @unroll_empty_followup(
+define void @unroll_empty_followup() {
+entry:
+; CHECK: llvm.br ^{{.*}} loop_annotation = #[[$ANNOT_ATTR]]
+; ROUNDTRIP: br label {{.*}}, !llvm.loop ![[EMPTY_LOOP:[0-9]+]]
+  br label %end, !llvm.loop !0
+end:
+  ret void
+}
+
+!0 = distinct !{!0, !1, !2}
+!1 = !{!"llvm.loop.unroll.count", i32 8}
+!2 = !{!"llvm.loop.unroll.followup_unrolled"}
+
+; ROUNDTRIP: ![[EMPTY_LOOP]] = distinct !{![[EMPTY_LOOP]], ![[COUNT:[0-9]+]], ![[EMPTY_FOLLOWUP:[0-9]+]]}
+; ROUNDTRIP-DAG: ![[COUNT]] = !{!"llvm.loop.unroll.count", i32 8}
+; ROUNDTRIP-DAG: ![[EMPTY_FOLLOWUP]] = !{!"llvm.loop.unroll.followup_unrolled"}
+
+; // -----
+
+; Keep multiple direct properties and a later followup as separate properties.
+; In particular, do not recursively flatten the nested empty followup.
+; CHECK-DAG: #[[EMPTY:.*]] = #llvm.loop_annotation<>
+; CHECK-DAG: #[[VECTORIZE_ATTR:.*]] = #llvm.loop_vectorize<disable = true>
+; CHECK-DAG: #[[INNER_UNROLL:.*]] = #llvm.loop_unroll<count = 2 : i32, followupUnrolled = #[[EMPTY]]>
+; CHECK-DAG: #[[FOLLOWUP:.*]] = #llvm.loop_annotation<vectorize = #[[VECTORIZE_ATTR]], unroll = #[[INNER_UNROLL]], mustProgress = true>
+; CHECK-DAG: #[[UNROLL_ATTR:.*]] = #llvm.loop_unroll<count = 8 : i32, followupUnrolled = #[[FOLLOWUP]]>
+; CHECK-DAG: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<unroll = #[[UNROLL_ATTR]]>
+; CHECK-LABEL: @unroll_nested_followup
+; ROUNDTRIP-LABEL: @unroll_nested_followup(
+define void @unroll_nested_followup() {
+entry:
+; CHECK: llvm.br ^{{.*}} loop_annotation = #[[$ANNOT_ATTR]]
+; ROUNDTRIP: br label {{.*}}, !llvm.loop ![[NESTED_LOOP:[0-9]+]]
+  br label %end, !llvm.loop !0
+end:
+  ret void
+}
+
+!0 = distinct !{!0, !1, !2}
+!1 = !{!"llvm.loop.unroll.count", i32 8}
+!2 = !{!"llvm.loop.unroll.followup_unrolled", !3, !4, !5, !6}
+!3 = !{!"llvm.loop.mustprogress"}
+!4 = !{!"llvm.loop.vectorize.disable"}
+!5 = !{!"llvm.loop.unroll.count", i32 2}
+!6 = !{!"llvm.loop.unroll.followup_unrolled"}
+
+; ROUNDTRIP: ![[NESTED_LOOP]] = distinct !{![[NESTED_LOOP]], ![[COUNT:[0-9]+]], ![[FOLLOWUP:[0-9]+]]}
+; ROUNDTRIP: ![[COUNT]] = !{!"llvm.loop.unroll.count", i32 8}
+; ROUNDTRIP: ![[FOLLOWUP]] = !{!"llvm.loop.unroll.followup_unrolled", ![[PROGRESS:[0-9]+]], ![[VECTORIZE:[0-9]+]], ![[INNER_COUNT:[0-9]+]], ![[INNER_FOLLOWUP:[0-9]+]]}
+; ROUNDTRIP-DAG: ![[PROGRESS]] = !{!"llvm.loop.mustprogress"}
+; ROUNDTRIP-DAG: ![[VECTORIZE]] = !{!"llvm.loop.vectorize.disable"}
+; ROUNDTRIP-DAG: ![[INNER_COUNT]] = !{!"llvm.loop.unroll.count", i32 2}
+; ROUNDTRIP-DAG: ![[INNER_FOLLOWUP]] = !{!"llvm.loop.unroll.followup_unrolled"}
+
+; // -----
+
 ; CHECK-DAG: #[[FOLLOWUP:.*]] = #llvm.loop_annotation<disableNonforced = true>
 ; CHECK-DAG: #[[UNROLL_AND_JAM_ATTR:.*]] = #llvm.loop_unroll_and_jam<disable = false, count = 32 : i32, followupOuter = #[[FOLLOWUP]], followupInner = #[[FOLLOWUP]], followupRemainderOuter = #[[FOLLOWUP]], followupRemainderInner = #[[FOLLOWUP]], followupAll = #[[FOLLOWUP]]>
 ; CHECK-DAG: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<unrollAndJam = #[[UNROLL_AND_JAM_ATTR]]>
@@ -182,8 +244,7 @@ end:
 !7 = !{!"llvm.loop.unroll_and_jam.followup_remainder_inner", !9}
 !8 = !{!"llvm.loop.unroll_and_jam.followup_all", !9}
 
-!9 = distinct !{!9, !10}
-!10 = !{!"llvm.loop.disable_nonforced"}
+!9 = !{!"llvm.loop.disable_nonforced"}
 
 ; // -----
 
@@ -225,8 +286,7 @@ end:
 !5 = !{!"llvm.loop.distribute.followup_fallback", !9}
 !6 = !{!"llvm.loop.distribute.followup_all", !9}
 
-!9 = distinct !{!9, !10}
-!10 = !{!"llvm.loop.disable_nonforced"}
+!9 = !{!"llvm.loop.disable_nonforced"}
 
 ; // -----
 
@@ -347,15 +407,20 @@ end:
 ; CHECK: #[[SUBPROGRAM:.*]] = #llvm.di_subprogram<
 ; CHECK: #[[start_loc_fused:.*]] = loc(fused<#[[SUBPROGRAM]]>[#[[start_loc]]])
 ; CHECK: #[[end_loc_fused:.*]] = loc(fused<#[[SUBPROGRAM]]>[#[[end_loc]]])
+; CHECK: #[[FOLLOWUP:.*]] = #llvm.loop_annotation<mustProgress = true, startLoc = #[[start_loc_fused]], endLoc = #[[end_loc_fused]]>
+; CHECK: #[[UNROLL_ATTR:.*]] = #llvm.loop_unroll<followupUnrolled = #[[FOLLOWUP]]>
 ; CHECK: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<
+; CHECK-SAME: unroll = #[[UNROLL_ATTR]]
 ; CHECK-SAME: mustProgress = true
 ; CHECK-SAME: startLoc = #[[start_loc_fused]]
 ; CHECK-SAME: endLoc = #[[end_loc_fused]]
 
 ; CHECK-LABEL: @loop_locs
+; ROUNDTRIP-LABEL: @loop_locs(
 define void @loop_locs(i64 %n, ptr %A) {
 entry:
 ; CHECK: llvm.br ^{{.*}} loop_annotation = #[[$ANNOT_ATTR]]
+; ROUNDTRIP: br label {{.*}}, !llvm.loop ![[LOC_LOOP:[0-9]+]]
   br label %end, !llvm.loop !6
 end:
   ret void
@@ -370,7 +435,16 @@ end:
 !4 = !DILocation(line: 1, column: 2, scope: !3)
 !5 = !DILocation(line: 2, column: 2, scope: !3)
 
-!6 = distinct !{!6, !4, !5, !7}
+!6 = distinct !{!6, !4, !5, !7, !8}
 !7 = !{!"llvm.loop.mustprogress"}
+!8 = !{!"llvm.loop.unroll.followup_unrolled", !4, !5, !7}
 !999 = !DISubroutineType(types: !1000)
 !1000 = !{null}
+
+; Debug locations are direct followup operands too, not named properties to
+; filter out when removing a LoopID wrapper.
+; ROUNDTRIP: ![[LOC_LOOP]] = distinct !{![[LOC_LOOP]], ![[START:[0-9]+]], ![[END:[0-9]+]], ![[PROGRESS:[0-9]+]], ![[FOLLOWUP:[0-9]+]]}
+; ROUNDTRIP-DAG: ![[START]] = !DILocation(line: 1, column: 2, scope:
+; ROUNDTRIP-DAG: ![[END]] = !DILocation(line: 2, column: 2, scope:
+; ROUNDTRIP-DAG: ![[PROGRESS]] = !{!"llvm.loop.mustprogress"}
+; ROUNDTRIP-DAG: ![[FOLLOWUP]] = !{!"llvm.loop.unroll.followup_unrolled", ![[START]], ![[END]], ![[PROGRESS]]}

diff  --git a/mlir/test/Target/LLVMIR/loop-metadata.mlir b/mlir/test/Target/LLVMIR/loop-metadata.mlir
index 12daaf6d5d282..bb8a87ac33082 100644
--- a/mlir/test/Target/LLVMIR/loop-metadata.mlir
+++ b/mlir/test/Target/LLVMIR/loop-metadata.mlir
@@ -53,15 +53,14 @@ llvm.func @vectorizeOptions() {
 }
 
 // CHECK-DAG: ![[NON_FORCED:[0-9]+]] = !{!"llvm.loop.disable_nonforced"}
-// CHECK-DAG: ![[FOLLOWUP:[0-9]+]] = distinct !{![[FOLLOWUP]], ![[NON_FORCED]]}
 // CHECK-DAG: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.enable"}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.predicate.enable"}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.scalable.disable"}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.width", i32 16}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.followup_vectorized", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.followup_epilogue", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.followup_all", ![[FOLLOWUP]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.followup_vectorized", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.followup_epilogue", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.vectorize.followup_all", ![[NON_FORCED]]}
 
 // -----
 
@@ -92,14 +91,13 @@ llvm.func @unrollOptions() {
 }
 
 // CHECK-DAG: ![[NON_FORCED:[0-9]+]] = !{!"llvm.loop.disable_nonforced"}
-// CHECK-DAG: ![[FOLLOWUP:[0-9]+]] = distinct !{![[FOLLOWUP]], ![[NON_FORCED]]}
 // CHECK-DAG: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.disable"}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.count", i32 64}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.runtime.disable", i1 false}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.followup_unrolled", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.followup_remainder", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.followup_all", ![[FOLLOWUP]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.followup_unrolled", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.followup_remainder", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll.followup_all", ![[NON_FORCED]]}
 
 // -----
 
@@ -131,15 +129,14 @@ llvm.func @unrollAndJamOptions() {
 }
 
 // CHECK-DAG: ![[NON_FORCED:[0-9]+]] = !{!"llvm.loop.disable_nonforced"}
-// CHECK-DAG: ![[FOLLOWUP:[0-9]+]] = distinct !{![[FOLLOWUP]], ![[NON_FORCED]]}
 // CHECK-DAG: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.enable"}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.count", i32 8}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_outer", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_inner", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_remainder_outer", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_remainder_inner", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_all", ![[FOLLOWUP]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_outer", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_inner", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_remainder_outer", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_remainder_inner", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.unroll_and_jam.followup_all", ![[NON_FORCED]]}
 
 // -----
 
@@ -183,13 +180,12 @@ llvm.func @distributeOptions() {
 }
 
 // CHECK-DAG: ![[NON_FORCED:[0-9]+]] = !{!"llvm.loop.disable_nonforced"}
-// CHECK-DAG: ![[FOLLOWUP:[0-9]+]] = distinct !{![[FOLLOWUP]], ![[NON_FORCED]]}
 // CHECK-DAG: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
 // CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.disable"}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_coincident", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_sequential", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_fallback", ![[FOLLOWUP]]}
-// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_all", ![[FOLLOWUP]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_coincident", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_sequential", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_fallback", ![[NON_FORCED]]}
+// CHECK-DAG: !{{[0-9]+}} = !{!"llvm.loop.distribute.followup_all", ![[NON_FORCED]]}
 
 // -----
 


        


More information about the Mlir-commits mailing list