[clang] [llvm] [mlir] Enforce single-operand form for llvm.loop.distribute metadata (PR #201077)
Madhur Amilkanthwar via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 7 09:49:11 PDT 2026
https://github.com/madhur13490 updated https://github.com/llvm/llvm-project/pull/201077
>From f4a850b7455781116f95bcb5421fc0ed81ea725d Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Wed, 15 Apr 2026 01:00:40 -0700
Subject: [PATCH 1/3] Enforce single-operand form for llvm.loop.distribute
metadata
This patch implements Phase 1 of the RFC "Enforce Single-Operand Format for All
.enable Metadata Nodes". The two-operand boolean form
!{!"llvm.loop.distribute.enable", i1 0/1} is replaced by a
single-operand enable/disable pair:
!{!"llvm.loop.distribute.enable"} ; force distribution
!{!"llvm.loop.distribute.disable"} ; suppress distribution
---
clang/lib/CodeGen/CGLoopInfo.cpp | 22 ++++-----
.../test/CodeGenCXX/pragma-followup_inner.cpp | 2 +-
.../test/CodeGenCXX/pragma-followup_outer.cpp | 2 +-
.../CodeGenCXX/pragma-loop-distribute.cpp | 2 +-
clang/test/CodeGenCXX/pragma-loop.cpp | 2 +-
llvm/docs/LangRef.rst | 15 +++---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 11 ++---
llvm/lib/IR/Verifier.cpp | 8 +++
llvm/lib/Transforms/Scalar/LoopDistribute.cpp | 13 ++---
llvm/lib/Transforms/Utils/LoopConstrainer.cpp | 3 +-
llvm/lib/Transforms/Utils/LoopUtils.cpp | 3 ++
.../Analysis/LoopAccessAnalysis/pr64637.ll | 2 +-
.../Other/optimization-remarks-lazy-bfi.ll | 2 +-
.../IRCE/add-metadata-pre-post-loops.ll | 2 +-
.../test/Transforms/IRCE/correct-loop-info.ll | 2 +-
.../Transforms/IRCE/loop-guarded-bounds.ll | 2 +-
llvm/test/Transforms/IRCE/pre_post_loops.ll | 2 +-
.../IRCE/range_intersect_miscompile.ll | 2 +-
.../IRCE/unsigned_comparisons_ugt.ll | 2 +-
.../IRCE/unsigned_comparisons_ult.ll | 2 +-
.../Inline/dilocation-loop-metadata-update.ll | 4 +-
.../LoopDistribute/basic-with-memchecks.ll | 2 +-
.../diagnostics-with-hotness.ll | 2 +-
.../Transforms/LoopDistribute/diagnostics.ll | 2 +-
.../disable_nonforced_enable.ll | 2 +-
.../Transforms/LoopDistribute/early-exit.ll | 2 +-
.../Transforms/LoopDistribute/followup.ll | 2 +-
.../Transforms/LoopDistribute/metadata.ll | 4 +-
.../preserve-llvm-loop-metadata.ll | 4 +-
.../preserve-llvm-loop-metadata.ll | 4 +-
llvm/test/Verifier/llvm.loop.distribute.ll | 49 +++++++++++++++++++
llvm/unittests/Analysis/LoopInfoTest.cpp | 8 +--
.../Target/LLVMIR/LoopAnnotationImporter.cpp | 6 ++-
.../LLVMIR/LoopAnnotationTranslation.cpp | 7 ++-
.../Target/LLVMIR/Import/metadata-loop.ll | 2 +-
mlir/test/Target/LLVMIR/loop-metadata.mlir | 2 +-
36 files changed, 131 insertions(+), 72 deletions(-)
create mode 100644 llvm/test/Verifier/llvm.loop.distribute.ll
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index 6b0b1b55213e1..1ae6bbe0ff595 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -331,11 +331,12 @@ clang::CodeGen::LoopInfo::createLoopDistributeMetadata(
if (Enabled != true) {
SmallVector<Metadata *, 4> NewLoopProperties;
if (Enabled == false) {
- NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
- NewLoopProperties.push_back(
- MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.distribute.enable"),
- ConstantAsMetadata::get(ConstantInt::get(
- llvm::Type::getInt1Ty(Ctx), 0))}));
+ NewLoopProperties.append(
+ LoopProperties.begin(), LoopProperties.end());
+ NewLoopProperties.push_back(MDNode::get(
+ Ctx,
+ {MDString::get(
+ Ctx, "llvm.loop.distribute.disable")}));
LoopProperties = NewLoopProperties;
}
return createLoopVectorizeMetadata(Attrs, LoopProperties,
@@ -344,16 +345,15 @@ clang::CodeGen::LoopInfo::createLoopDistributeMetadata(
bool FollowupHasTransforms = false;
SmallVector<Metadata *, 4> Followup =
- createLoopVectorizeMetadata(Attrs, LoopProperties, FollowupHasTransforms);
+ createLoopVectorizeMetadata(
+ Attrs, LoopProperties, FollowupHasTransforms);
SmallVector<Metadata *, 4> Args;
Args.append(LoopProperties.begin(), LoopProperties.end());
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"),
- ConstantAsMetadata::get(ConstantInt::get(
- llvm::Type::getInt1Ty(Ctx),
- (Attrs.DistributeEnable == LoopAttributes::Enable)))};
- Args.push_back(MDNode::get(Ctx, Vals));
+ Args.push_back(MDNode::get(
+ Ctx,
+ {MDString::get(Ctx, "llvm.loop.distribute.enable")}));
if (FollowupHasTransforms)
Args.push_back(
diff --git a/clang/test/CodeGenCXX/pragma-followup_inner.cpp b/clang/test/CodeGenCXX/pragma-followup_inner.cpp
index 04f5656dcd638..2cf2dba5b913d 100644
--- a/clang/test/CodeGenCXX/pragma-followup_inner.cpp
+++ b/clang/test/CodeGenCXX/pragma-followup_inner.cpp
@@ -22,7 +22,7 @@ extern "C" void followup_inner(int n, int *x) {
// CHECK-DAG: ![[INNERLOOP_3]] = distinct !{![[INNERLOOP_3]], ![[PARALLEL_ACCESSES_4:[0-9]+]], ![[DISTRIBUTE_5:[0-9]+]], ![[DISTRIBUTE_FOLLOWUP_6:[0-9]+]]}
// CHECK-DAG: ![[PARALLEL_ACCESSES_4]] = !{!"llvm.loop.parallel_accesses", ![[ACCESSGROUP_2]]}
-// CHECK-DAG: ![[DISTRIBUTE_5]] = !{!"llvm.loop.distribute.enable", i1 true}
+// CHECK-DAG: ![[DISTRIBUTE_5]] = !{!"llvm.loop.distribute.enable"}
// CHECK-DAG: ![[DISTRIBUTE_FOLLOWUP_6]] = !{!"llvm.loop.distribute.followup_all", ![[PARALLEL_ACCESSES_4]], ![[VECTORIZE_8:[0-9]+]]}
// CHECK-DAG: ![[VECTORIZE_8]] = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/clang/test/CodeGenCXX/pragma-followup_outer.cpp b/clang/test/CodeGenCXX/pragma-followup_outer.cpp
index fdd5a07d00857..2e907fb814b3d 100644
--- a/clang/test/CodeGenCXX/pragma-followup_outer.cpp
+++ b/clang/test/CodeGenCXX/pragma-followup_outer.cpp
@@ -19,7 +19,7 @@ extern "C" void followup_outer(int n, int *x) {
// CHECK-DAG: ![[LOOP_3:[0-9]+]] = distinct !{![[LOOP_3:[0-9]+]], [[MP:![0-9]+]], ![[PARALLEL_ACCESSES_4:[0-9]+]], ![[DISTRIBUTE_5:[0-9]+]], ![[DISTRIBUTE_FOLLOWUP_6:[0-9]+]]}
// CHECK-DAG: ![[PARALLEL_ACCESSES_4:[0-9]+]] = !{!"llvm.loop.parallel_accesses", ![[ACCESSGROUP_2]]}
-// CHECK-DAG: ![[DISTRIBUTE_5:[0-9]+]] = !{!"llvm.loop.distribute.enable", i1 true}
+// CHECK-DAG: ![[DISTRIBUTE_5:[0-9]+]] = !{!"llvm.loop.distribute.enable"}
// CHECK-DAG: ![[DISTRIBUTE_FOLLOWUP_6:[0-9]+]] = !{!"llvm.loop.distribute.followup_all", [[MP]], ![[PARALLEL_ACCESSES_4:[0-9]+]], ![[VECTORIZE_8:[0-9]+]], ![[VECTORIZE_FOLLOWUP_9:[0-9]+]]}
// CHECK-DAG: ![[VECTORIZE_8:[0-9]+]] = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/clang/test/CodeGenCXX/pragma-loop-distribute.cpp b/clang/test/CodeGenCXX/pragma-loop-distribute.cpp
index 98aef21da2acd..66f0fb07b51fb 100644
--- a/clang/test/CodeGenCXX/pragma-loop-distribute.cpp
+++ b/clang/test/CodeGenCXX/pragma-loop-distribute.cpp
@@ -20,5 +20,5 @@ void while_test(int *List, int Length, int *List2, int Length2) {
}
// CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], [[MP:![0-9]+]], ![[DISTRIBUTE_ENABLE:.*]]}
-// CHECK: ![[DISTRIBUTE_ENABLE]] = !{!"llvm.loop.distribute.enable", i1 true}
+// CHECK: ![[DISTRIBUTE_ENABLE]] = !{!"llvm.loop.distribute.enable"}
// CHECK: [[LOOP_2]] = distinct !{[[LOOP_2]], [[MP]]}
diff --git a/clang/test/CodeGenCXX/pragma-loop.cpp b/clang/test/CodeGenCXX/pragma-loop.cpp
index 8cb3346247daf..f9106725ad99d 100644
--- a/clang/test/CodeGenCXX/pragma-loop.cpp
+++ b/clang/test/CodeGenCXX/pragma-loop.cpp
@@ -248,7 +248,7 @@ void for_test_interleave_vectorize_disable_unroll(int *List, int Length) {
// CHECK-DAG: ![[UNROLL_32:[0-9]+]] = !{!"llvm.loop.unroll.count", i32 32}
// CHECK-DAG: ![[UNROLL_FULL:[0-9]+]] = !{!"llvm.loop.unroll.full"}
-// CHECK-DAG: ![[DISTRIBUTE_DISABLE:[0-9]+]] = !{!"llvm.loop.distribute.enable", i1 false}
+// CHECK-DAG: ![[DISTRIBUTE_DISABLE:[0-9]+]] = !{!"llvm.loop.distribute.disable"}
// CHECK-DAG: ![[INTERLEAVE_2:[0-9]+]] = !{!"llvm.loop.interleave.count", i32 2}
// CHECK-DAG: ![[INTERLEAVE_4:[0-9]+]] = !{!"llvm.loop.interleave.count", i32 4}
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 6e7f63ed7fb69..9d37207753686 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8385,18 +8385,17 @@ this is only performed if the entire loop cannot be vectorized due to unsafe
memory dependencies. The transformation will attempt to isolate the unsafe
dependencies into their own loop.
-This metadata can be used to selectively enable or disable distribution of the
-loop. The first operand is the string ``llvm.loop.distribute.enable`` and the
-second operand is a bit. If the bit operand value is 1 distribution is
-enabled. A value of 0 disables distribution:
+This metadata can be used to selectively enable or disable
+distribution of the loop. Each node has a single operand
+containing the name string:
.. code-block:: llvm
- !0 = !{!"llvm.loop.distribute.enable", i1 0}
- !1 = !{!"llvm.loop.distribute.enable", i1 1}
+ !0 = !{!"llvm.loop.distribute.enable"}
+ !1 = !{!"llvm.loop.distribute.disable"}
-This metadata should be used in conjunction with ``llvm.loop`` loop
-identification metadata.
+This metadata should be used in conjunction with ``llvm.loop``
+loop identification metadata.
'``llvm.loop.distribute.followup_coincident``' Metadata
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index f28b570d6191b..d63208e2fe5d3 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -2929,14 +2929,9 @@ void LoopAccessInfo::emitUnsafeDependenceRemark() {
LLVM_DEBUG(dbgs() << "LAA: unsafe dependent memory operations in loop\n");
// Emit remark for first unsafe dependence
- bool HasForcedDistribution = false;
- std::optional<const MDOperand *> Value =
- findStringMetadataForLoop(TheLoop, "llvm.loop.distribute.enable");
- if (Value) {
- const MDOperand *Op = *Value;
- assert(Op && mdconst::hasa<ConstantInt>(*Op) && "invalid metadata");
- HasForcedDistribution = mdconst::extract<ConstantInt>(*Op)->getZExtValue();
- }
+ bool HasForcedDistribution =
+ getBooleanLoopAttribute(
+ TheLoop, "llvm.loop.distribute.enable");
const std::string Info =
HasForcedDistribution
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 198ff055f9721..857fa1200c590 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -995,6 +995,14 @@ void Verifier::visitMDNode(const MDNode &BaseMD,
CurrentMD);
}
+ // Enforce the single-operand form of llvm.loop.distribute metadata.
+ if (CurrentMD->getNumOperands() > 0 &&
+ (CurrentMD->getOperand(0).equalsStr("llvm.loop.distribute.enable") ||
+ CurrentMD->getOperand(0).equalsStr("llvm.loop.distribute.disable")))
+ Check(CurrentMD->getNumOperands() == 1,
+ "Expected one operand for llvm.loop.distribute metadata",
+ CurrentMD);
+
// Check these last, so we diagnose problems in operands first.
Check(!CurrentMD->isTemporary(), "Expected no forward declarations!",
CurrentMD);
diff --git a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
index 2d0b08fed859b..07cfd8628a4f6 100644
--- a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
@@ -941,14 +941,11 @@ class LoopDistributeForLoop {
/// Check whether the loop metadata is forcing distribution to be
/// enabled/disabled.
void setForced() {
- std::optional<const MDOperand *> Value =
- findStringMetadataForLoop(L, "llvm.loop.distribute.enable");
- if (!Value)
- return;
-
- const MDOperand *Op = *Value;
- assert(Op && mdconst::hasa<ConstantInt>(*Op) && "invalid metadata");
- IsForced = mdconst::extract<ConstantInt>(*Op)->getZExtValue();
+ if (getBooleanLoopAttribute(L, "llvm.loop.distribute.enable"))
+ IsForced = true;
+ else if (getBooleanLoopAttribute(
+ L, "llvm.loop.distribute.disable"))
+ IsForced = false;
}
Loop *L;
diff --git a/llvm/lib/Transforms/Utils/LoopConstrainer.cpp b/llvm/lib/Transforms/Utils/LoopConstrainer.cpp
index 72fae62e56e88..74cd2a729d285 100644
--- a/llvm/lib/Transforms/Utils/LoopConstrainer.cpp
+++ b/llvm/lib/Transforms/Utils/LoopConstrainer.cpp
@@ -453,7 +453,8 @@ static void DisableAllLoopOptsOnLoop(Loop &L) {
Context, {MDString::get(Context, "llvm.loop.licm_versioning.disable")});
MDNode *DisableDistribution = MDNode::get(
Context,
- {MDString::get(Context, "llvm.loop.distribute.enable"), FalseVal});
+ {MDString::get(
+ Context, "llvm.loop.distribute.disable")});
MDNode *NewLoopID =
MDNode::get(Context, {Dummy, DisableUnroll, DisableVectorize,
DisableLICMVersioning, DisableDistribution});
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index a2630c481a72e..3133bf2804034 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -441,6 +441,9 @@ TransformationMode llvm::hasVectorizeTransformation(const Loop *L) {
}
TransformationMode llvm::hasDistributeTransformation(const Loop *L) {
+ if (getBooleanLoopAttribute(L, "llvm.loop.distribute.disable"))
+ return TM_SuppressedByUser;
+
if (getBooleanLoopAttribute(L, "llvm.loop.distribute.enable"))
return TM_ForcedByUser;
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/pr64637.ll b/llvm/test/Analysis/LoopAccessAnalysis/pr64637.ll
index d3e589cf99cf3..7b25d1fffcbba 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/pr64637.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/pr64637.ll
@@ -76,4 +76,4 @@ for.body: ; preds = %for.body, %for.body
}
!0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!1 = !{!"llvm.loop.distribute.enable"}
diff --git a/llvm/test/Other/optimization-remarks-lazy-bfi.ll b/llvm/test/Other/optimization-remarks-lazy-bfi.ll
index c5099bb2179e4..5fc34cc14bdc8 100644
--- a/llvm/test/Other/optimization-remarks-lazy-bfi.ll
+++ b/llvm/test/Other/optimization-remarks-lazy-bfi.ll
@@ -75,7 +75,7 @@ for.cond.cleanup:
!18 = !DILocation(line: 4, column: 5, scope: !7)
!19 = !DILocation(line: 4, column: 10, scope: !7)
!20 = distinct !{!20, !21}
-!21 = !{!"llvm.loop.distribute.enable", i1 true}
+!21 = !{!"llvm.loop.distribute.enable"}
!22 = !{!"function_entry_count", i64 3}
!23 = !{!"branch_weights", i32 99, i32 1}
!24 = !{!"branch_weights", i32 1, i32 99}
diff --git a/llvm/test/Transforms/IRCE/add-metadata-pre-post-loops.ll b/llvm/test/Transforms/IRCE/add-metadata-pre-post-loops.ll
index eb72907730c6d..3a360814e361e 100644
--- a/llvm/test/Transforms/IRCE/add-metadata-pre-post-loops.ll
+++ b/llvm/test/Transforms/IRCE/add-metadata-pre-post-loops.ll
@@ -76,7 +76,7 @@ attributes #0 = { alwaysinline }
!3 = !{!"llvm.loop.unroll.disable"}
!4 = !{!"llvm.loop.vectorize.enable", i1 false}
!5 = !{!"llvm.loop.licm_versioning.disable"}
-!6 = !{!"llvm.loop.distribute.enable", i1 false}
+!6 = !{!"llvm.loop.distribute.disable"}
!7 = !{}
!8 = distinct !{!8, !3, !4, !5}
!9 = distinct !{!9, !3, !4, !5}
diff --git a/llvm/test/Transforms/IRCE/correct-loop-info.ll b/llvm/test/Transforms/IRCE/correct-loop-info.ll
index 7ea445718289a..bc5987ebba2e4 100644
--- a/llvm/test/Transforms/IRCE/correct-loop-info.ll
+++ b/llvm/test/Transforms/IRCE/correct-loop-info.ll
@@ -178,6 +178,6 @@ declare void @pluto()
!1 = !{!"llvm.loop.unroll.disable"}
!2 = !{!"llvm.loop.vectorize.enable", i1 false}
!3 = !{!"llvm.loop.licm_versioning.disable"}
-!4 = !{!"llvm.loop.distribute.enable", i1 false}
+!4 = !{!"llvm.loop.distribute.disable"}
!5 = !{}
!6 = distinct !{!6, !1, !2, !3, !4}
diff --git a/llvm/test/Transforms/IRCE/loop-guarded-bounds.ll b/llvm/test/Transforms/IRCE/loop-guarded-bounds.ll
index ea169987cf2fc..61cfef6f1492a 100644
--- a/llvm/test/Transforms/IRCE/loop-guarded-bounds.ll
+++ b/llvm/test/Transforms/IRCE/loop-guarded-bounds.ll
@@ -130,7 +130,7 @@ exit: ; preds = %guarded, %loop_, %prehead
; CHECK: [[META1]] = !{!"llvm.loop.unroll.disable"}
; CHECK: [[META2]] = !{!"llvm.loop.vectorize.enable", i1 false}
; CHECK: [[META3]] = !{!"llvm.loop.licm_versioning.disable"}
-; CHECK: [[META4]] = !{!"llvm.loop.distribute.enable", i1 false}
+; CHECK: [[META4]] = !{!"llvm.loop.distribute.disable"}
; CHECK: [[META5]] = !{}
; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]], [[META3]], [[META4]]}
;.
diff --git a/llvm/test/Transforms/IRCE/pre_post_loops.ll b/llvm/test/Transforms/IRCE/pre_post_loops.ll
index da2faa34719af..2807adba35940 100644
--- a/llvm/test/Transforms/IRCE/pre_post_loops.ll
+++ b/llvm/test/Transforms/IRCE/pre_post_loops.ll
@@ -163,7 +163,7 @@ exit:
; CHECK: [[META2]] = !{!"llvm.loop.unroll.disable"}
; CHECK: [[META3]] = !{!"llvm.loop.vectorize.enable", i1 false}
; CHECK: [[META4]] = !{!"llvm.loop.licm_versioning.disable"}
-; CHECK: [[META5]] = !{!"llvm.loop.distribute.enable", i1 false}
+; CHECK: [[META5]] = !{!"llvm.loop.distribute.disable"}
; CHECK: [[META6]] = !{}
; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META3]], [[META4]], [[META5]]}
;.
diff --git a/llvm/test/Transforms/IRCE/range_intersect_miscompile.ll b/llvm/test/Transforms/IRCE/range_intersect_miscompile.ll
index 68613feacba32..2e21bb5ad0bd0 100644
--- a/llvm/test/Transforms/IRCE/range_intersect_miscompile.ll
+++ b/llvm/test/Transforms/IRCE/range_intersect_miscompile.ll
@@ -490,7 +490,7 @@ deopt: ; preds = %range_check_block
; CHECK: [[META1]] = !{!"llvm.loop.unroll.disable"}
; CHECK: [[META2]] = !{!"llvm.loop.vectorize.enable", i1 false}
; CHECK: [[META3]] = !{!"llvm.loop.licm_versioning.disable"}
-; CHECK: [[META4]] = !{!"llvm.loop.distribute.enable", i1 false}
+; CHECK: [[META4]] = !{!"llvm.loop.distribute.disable"}
; CHECK: [[META5]] = !{}
; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]], [[META3]], [[META4]]}
; CHECK: [[RNG7]] = !{i32 0, i32 50}
diff --git a/llvm/test/Transforms/IRCE/unsigned_comparisons_ugt.ll b/llvm/test/Transforms/IRCE/unsigned_comparisons_ugt.ll
index 7236cf4817ade..cdd7235ac45b4 100644
--- a/llvm/test/Transforms/IRCE/unsigned_comparisons_ugt.ll
+++ b/llvm/test/Transforms/IRCE/unsigned_comparisons_ugt.ll
@@ -447,7 +447,7 @@ exit:
; CHECK: [[META2]] = !{!"llvm.loop.unroll.disable"}
; CHECK: [[META3]] = !{!"llvm.loop.vectorize.enable", i1 false}
; CHECK: [[META4]] = !{!"llvm.loop.licm_versioning.disable"}
-; CHECK: [[META5]] = !{!"llvm.loop.distribute.enable", i1 false}
+; CHECK: [[META5]] = !{!"llvm.loop.distribute.disable"}
; CHECK: [[META6]] = !{}
; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META3]], [[META4]], [[META5]]}
; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META2]], [[META3]], [[META4]], [[META5]]}
diff --git a/llvm/test/Transforms/IRCE/unsigned_comparisons_ult.ll b/llvm/test/Transforms/IRCE/unsigned_comparisons_ult.ll
index 546e1b0faa1c3..107a3554282ad 100644
--- a/llvm/test/Transforms/IRCE/unsigned_comparisons_ult.ll
+++ b/llvm/test/Transforms/IRCE/unsigned_comparisons_ult.ll
@@ -654,7 +654,7 @@ exit:
; CHECK: [[META2]] = !{!"llvm.loop.unroll.disable"}
; CHECK: [[META3]] = !{!"llvm.loop.vectorize.enable", i1 false}
; CHECK: [[META4]] = !{!"llvm.loop.licm_versioning.disable"}
-; CHECK: [[META5]] = !{!"llvm.loop.distribute.enable", i1 false}
+; CHECK: [[META5]] = !{!"llvm.loop.distribute.disable"}
; CHECK: [[META6]] = !{}
; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META3]], [[META4]], [[META5]]}
; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META2]], [[META3]], [[META4]], [[META5]]}
diff --git a/llvm/test/Transforms/Inline/dilocation-loop-metadata-update.ll b/llvm/test/Transforms/Inline/dilocation-loop-metadata-update.ll
index 1bc132663331b..0d8dcfbcf2a8b 100644
--- a/llvm/test/Transforms/Inline/dilocation-loop-metadata-update.ll
+++ b/llvm/test/Transforms/Inline/dilocation-loop-metadata-update.ll
@@ -47,7 +47,7 @@ entry:
!7 = !DILocation(line: 6, column: 3, scope: !3)
!8 = !DILocation(line: 7, column: 22, scope: !3)
!9 = !{!"llvm.loop.mustprogress"}
-!10 = !{!"llvm.loop.distribute.enable", i1 true}
+!10 = !{!"llvm.loop.distribute.enable"}
!11 = !{!"llvm.loop.distribute.followup_all", !7, !8, !9, !12, !13, !14}
!12 = !{!"llvm.loop.vectorize.width", i32 8}
!13 = !{!"llvm.loop.vectorize.enable", i1 true}
@@ -66,7 +66,7 @@ entry:
; CHECK: [[META7]] = !DILocation(line: 6, column: 3, scope: [[DBG3]])
; CHECK: [[META8]] = !DILocation(line: 7, column: 22, scope: [[DBG3]])
; CHECK: [[META9]] = !{!"llvm.loop.mustprogress"}
-; CHECK: [[META10]] = !{!"llvm.loop.distribute.enable", i1 true}
+; CHECK: [[META10]] = !{!"llvm.loop.distribute.enable"}
; CHECK: [[META11]] = !{!"llvm.loop.distribute.followup_all", [[META7]], [[META8]], [[META9]], [[META12:![0-9]+]], [[META13:![0-9]+]], [[META14:![0-9]+]]}
; CHECK: [[META12]] = !{!"llvm.loop.vectorize.width", i32 8}
; CHECK: [[META13]] = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/llvm/test/Transforms/LoopDistribute/basic-with-memchecks.ll b/llvm/test/Transforms/LoopDistribute/basic-with-memchecks.ll
index 2828882afe779..dcd231a900ee2 100644
--- a/llvm/test/Transforms/LoopDistribute/basic-with-memchecks.ll
+++ b/llvm/test/Transforms/LoopDistribute/basic-with-memchecks.ll
@@ -288,5 +288,5 @@ attributes #0 = { nounwind readnone convergent }
attributes #1 = { nounwind convergent }
!0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!1 = !{!"llvm.loop.distribute.enable"}
; CHECK: ![[PROF1]] = !{!"unknown", !"loop-versioning"}
diff --git a/llvm/test/Transforms/LoopDistribute/diagnostics-with-hotness.ll b/llvm/test/Transforms/LoopDistribute/diagnostics-with-hotness.ll
index b5ef3578eadd9..4f2f76191e615 100644
--- a/llvm/test/Transforms/LoopDistribute/diagnostics-with-hotness.ll
+++ b/llvm/test/Transforms/LoopDistribute/diagnostics-with-hotness.ll
@@ -74,7 +74,7 @@ for.cond.cleanup:
!18 = !DILocation(line: 4, column: 5, scope: !7)
!19 = !DILocation(line: 4, column: 10, scope: !7)
!20 = distinct !{!20, !21}
-!21 = !{!"llvm.loop.distribute.enable", i1 true}
+!21 = !{!"llvm.loop.distribute.enable"}
!22 = !{!"function_entry_count", i64 3}
!23 = !{!"branch_weights", i32 2000, i32 1}
!24 = !{!"branch_weights", i32 1, i32 99}
diff --git a/llvm/test/Transforms/LoopDistribute/diagnostics.ll b/llvm/test/Transforms/LoopDistribute/diagnostics.ll
index e6a0d83bd63d2..80b217d0abb2b 100644
--- a/llvm/test/Transforms/LoopDistribute/diagnostics.ll
+++ b/llvm/test/Transforms/LoopDistribute/diagnostics.ll
@@ -194,7 +194,7 @@ attributes #1 = { nounwind convergent }
!18 = !DILocation(line: 4, column: 5, scope: !7)
!19 = !DILocation(line: 4, column: 10, scope: !7)
!20 = distinct !{!20, !21}
-!21 = !{!"llvm.loop.distribute.enable", i1 true}
+!21 = !{!"llvm.loop.distribute.enable"}
!22 = distinct !DISubprogram(name: "not_forced", scope: !1, file: !1, line: 8, type: !8, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2)
!23 = !DILocation(line: 9, column: 20, scope: !22)
!24 = !DILocation(line: 9, column: 3, scope: !22)
diff --git a/llvm/test/Transforms/LoopDistribute/disable_nonforced_enable.ll b/llvm/test/Transforms/LoopDistribute/disable_nonforced_enable.ll
index 45a2d31256a27..eff1621cd7ada 100644
--- a/llvm/test/Transforms/LoopDistribute/disable_nonforced_enable.ll
+++ b/llvm/test/Transforms/LoopDistribute/disable_nonforced_enable.ll
@@ -43,4 +43,4 @@ for.end:
ret void
}
-!0 = distinct !{!0, !{!"llvm.loop.disable_nonforced"}, !{!"llvm.loop.distribute.enable", i32 1}}
+!0 = distinct !{!0, !{!"llvm.loop.disable_nonforced"}, !{!"llvm.loop.distribute.enable"}}
diff --git a/llvm/test/Transforms/LoopDistribute/early-exit.ll b/llvm/test/Transforms/LoopDistribute/early-exit.ll
index 9353d842523f4..d2ad9b1bcd6c5 100644
--- a/llvm/test/Transforms/LoopDistribute/early-exit.ll
+++ b/llvm/test/Transforms/LoopDistribute/early-exit.ll
@@ -89,4 +89,4 @@ attributes #0 = { nounwind readnone convergent }
attributes #1 = { nounwind convergent }
!0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!1 = !{!"llvm.loop.distribute.enable"}
diff --git a/llvm/test/Transforms/LoopDistribute/followup.ll b/llvm/test/Transforms/LoopDistribute/followup.ll
index ae418ad9e6b42..2753bad5e1c1e 100644
--- a/llvm/test/Transforms/LoopDistribute/followup.ll
+++ b/llvm/test/Transforms/LoopDistribute/followup.ll
@@ -125,7 +125,7 @@ for.end:
}
!0 = distinct !{!0, !1, !2, !3, !4, !5}
-!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!1 = !{!"llvm.loop.distribute.enable"}
!2 = !{!"llvm.loop.distribute.followup_all", !{!"FollowupAll"}}
!3 = !{!"llvm.loop.distribute.followup_coincident", !{!"FollowupCoincident", i1 false}}
!4 = !{!"llvm.loop.distribute.followup_sequential", !{!"FollowupSequential", i32 8}}
diff --git a/llvm/test/Transforms/LoopDistribute/metadata.ll b/llvm/test/Transforms/LoopDistribute/metadata.ll
index b0e461fe0ea75..8b74ac4249550 100644
--- a/llvm/test/Transforms/LoopDistribute/metadata.ll
+++ b/llvm/test/Transforms/LoopDistribute/metadata.ll
@@ -131,6 +131,6 @@ for.end: ; preds = %for.body
}
!0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!1 = !{!"llvm.loop.distribute.enable"}
!2 = distinct !{!2, !3}
-!3 = !{!"llvm.loop.distribute.enable", i1 false}
+!3 = !{!"llvm.loop.distribute.disable"}
diff --git a/llvm/test/Transforms/LoopSimplify/preserve-llvm-loop-metadata.ll b/llvm/test/Transforms/LoopSimplify/preserve-llvm-loop-metadata.ll
index 2c1dff7ee5a5f..049880a97a211 100644
--- a/llvm/test/Transforms/LoopSimplify/preserve-llvm-loop-metadata.ll
+++ b/llvm/test/Transforms/LoopSimplify/preserve-llvm-loop-metadata.ll
@@ -65,6 +65,6 @@ cleanup: ; preds = %cleanup.loopexit, %
}
!0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!1 = !{!"llvm.loop.distribute.enable"}
; CHECK: !0 = distinct !{!0, !1}
-; CHECK: !1 = !{!"llvm.loop.distribute.enable", i1 true}
+; CHECK: !1 = !{!"llvm.loop.distribute.enable"}
diff --git a/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll b/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll
index 8b3bdbee2249c..d565b860a9ef6 100644
--- a/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll
+++ b/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll
@@ -147,7 +147,7 @@ while.end: ; preds = %while.cond
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = distinct !{!1, !2}
-!2 = !{!"llvm.loop.distribute.enable", i1 true}
+!2 = !{!"llvm.loop.distribute.enable"}
!3 = distinct !{!3, !4}
!4 = !{!"llvm.loop.mustprogress"}
!5 = distinct !{!5, !4, !6}
@@ -161,7 +161,7 @@ while.end: ; preds = %while.cond
!13 = !DILocation(line: 9, column: 23, scope: !12)
; CHECK: !1 = distinct !{!1, !2}
-; CHECK: !2 = !{!"llvm.loop.distribute.enable", i1 true}
+; CHECK: !2 = !{!"llvm.loop.distribute.enable"}
; CHECK: !3 = distinct !{!3, !4}
; CHECK: !4 = !{!"llvm.loop.mustprogress"}
; CHECK: !5 = distinct !{!5, !4, !6}
diff --git a/llvm/test/Verifier/llvm.loop.distribute.ll b/llvm/test/Verifier/llvm.loop.distribute.ll
new file mode 100644
index 0000000000000..9e1e8138e93dc
--- /dev/null
+++ b/llvm/test/Verifier/llvm.loop.distribute.ll
@@ -0,0 +1,49 @@
+; Test "llvm.loop.distribute.enable" / "llvm.loop.distribute.disable"
+; single-operand validation.
+
+; DEFINE: %{RUN} = opt -passes=verify %t -disable-output 2>&1 | \
+; DEFINE: FileCheck %s -allow-empty -check-prefix
+
+define void @test() {
+entry:
+ br label %body
+body:
+ br i1 0, label %body, label %exit, !llvm.loop !0
+exit:
+ ret void
+}
+!0 = distinct !{!0, !1}
+
+; GOOD-NOT: {{.}}
+
+; BAD: Expected one operand for llvm.loop.distribute metadata
+
+; Single-operand enable.
+; RUN: cp %s %t
+; RUN: chmod u+w %t
+; RUN: echo '!1 = !{!"llvm.loop.distribute.enable"}' >> %t
+; RUN: %{RUN} GOOD
+
+; Single-operand disable.
+; RUN: cp %s %t
+; RUN: chmod u+w %t
+; RUN: echo '!1 = !{!"llvm.loop.distribute.disable"}' >> %t
+; RUN: %{RUN} GOOD
+
+; Two-operand enable with boolean false (legacy form, now rejected).
+; RUN: cp %s %t
+; RUN: chmod u+w %t
+; RUN: echo '!1 = !{!"llvm.loop.distribute.enable", i1 0}' >> %t
+; RUN: not %{RUN} BAD
+
+; Two-operand enable with boolean true (legacy form, now rejected).
+; RUN: cp %s %t
+; RUN: chmod u+w %t
+; RUN: echo '!1 = !{!"llvm.loop.distribute.enable", i1 1}' >> %t
+; RUN: not %{RUN} BAD
+
+; Two-operand disable (rejected).
+; RUN: cp %s %t
+; RUN: chmod u+w %t
+; RUN: echo '!1 = !{!"llvm.loop.distribute.disable", i1 0}' >> %t
+; RUN: not %{RUN} BAD
diff --git a/llvm/unittests/Analysis/LoopInfoTest.cpp b/llvm/unittests/Analysis/LoopInfoTest.cpp
index 4828573c32c10..5321f72aa1784 100644
--- a/llvm/unittests/Analysis/LoopInfoTest.cpp
+++ b/llvm/unittests/Analysis/LoopInfoTest.cpp
@@ -72,7 +72,7 @@ TEST(LoopInfoTest, LoopWithSingleLatch) {
" ret void\n"
"}\n"
"!0 = distinct !{!0, !1}\n"
- "!1 = !{!\"llvm.loop.distribute.enable\", i1 true}\n";
+ "!1 = !{!\"llvm.loop.distribute.enable\"}\n";
// Parse the module.
LLVMContext Context;
@@ -122,7 +122,7 @@ TEST(LoopInfoTest, LoopWithMultipleLatches) {
" ret void\n"
"}\n"
"!0 = distinct !{!0, !1}\n"
- "!1 = !{!\"llvm.loop.distribute.enable\", i1 true}\n";
+ "!1 = !{!\"llvm.loop.distribute.enable\"}\n";
// Parse the module.
LLVMContext Context;
@@ -1397,7 +1397,7 @@ TEST(LoopInfoTest, LoopUniqueExitBlocks) {
" ret void\n"
"}\n"
"!0 = distinct !{!0, !1}\n"
- "!1 = !{!\"llvm.loop.distribute.enable\", i1 true}\n";
+ "!1 = !{!\"llvm.loop.distribute.enable\"}\n";
// Parse the module.
LLVMContext Context;
@@ -1440,7 +1440,7 @@ TEST(LoopInfoTest, LoopNonLatchUniqueExitBlocks) {
" ret void\n"
"}\n"
"!0 = distinct !{!0, !1}\n"
- "!1 = !{!\"llvm.loop.distribute.enable\", i1 true}\n";
+ "!1 = !{!\"llvm.loop.distribute.enable\"}\n";
// Parse the module.
LLVMContext Context;
diff --git a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
index e4905423347a2..4022afc433a61 100644
--- a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
@@ -358,8 +358,10 @@ FailureOr<LoopLICMAttr> LoopMetadataConversion::convertLICMAttr() {
}
FailureOr<LoopDistributeAttr> LoopMetadataConversion::convertDistributeAttr() {
- FailureOr<BoolAttr> disable =
- lookupBoolNode("llvm.loop.distribute.enable", true);
+ FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
+ "llvm.loop.distribute.enable",
+ "llvm.loop.distribute.disable",
+ /*negated=*/true);
FailureOr<LoopAnnotationAttr> followupCoincident =
lookupFollowupNode("llvm.loop.distribute.followup_coincident");
FailureOr<LoopAnnotationAttr> followupSequential =
diff --git a/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp b/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
index f3ec18c9074e4..41ba31106f788 100644
--- a/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp
@@ -162,7 +162,12 @@ void LoopAnnotationConversion::convertLoopOptions(LoopLICMAttr options) {
}
void LoopAnnotationConversion::convertLoopOptions(LoopDistributeAttr options) {
- convertBoolNode("llvm.loop.distribute.enable", options.getDisable(), true);
+ if (auto disable = options.getDisable()) {
+ if (disable.getValue())
+ addUnitNode("llvm.loop.distribute.disable");
+ else
+ addUnitNode("llvm.loop.distribute.enable");
+ }
convertFollowupNode("llvm.loop.distribute.followup_coincident",
options.getFollowupCoincident());
convertFollowupNode("llvm.loop.distribute.followup_sequential",
diff --git a/mlir/test/Target/LLVMIR/Import/metadata-loop.ll b/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
index c09fe92dc9cdc..021818ded3d3c 100644
--- a/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
+++ b/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
@@ -219,7 +219,7 @@ end:
}
!1 = distinct !{!1, !2, !3, !4, !5, !6}
-!2 = !{!"llvm.loop.distribute.enable", i1 0}
+!2 = !{!"llvm.loop.distribute.disable"}
!3 = !{!"llvm.loop.distribute.followup_coincident", !9}
!4 = !{!"llvm.loop.distribute.followup_sequential", !9}
!5 = !{!"llvm.loop.distribute.followup_fallback", !9}
diff --git a/mlir/test/Target/LLVMIR/loop-metadata.mlir b/mlir/test/Target/LLVMIR/loop-metadata.mlir
index 72f0cf06ed0fe..299bcb481f67f 100644
--- a/mlir/test/Target/LLVMIR/loop-metadata.mlir
+++ b/mlir/test/Target/LLVMIR/loop-metadata.mlir
@@ -185,7 +185,7 @@ 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.enable", i1 false}
+// 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]]}
>From beb17d017d5a38a3226afd1a8997880d3b374093 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Tue, 7 Jul 2026 00:52:57 -0700
Subject: [PATCH 2/3] fixup! Enforce single-operand form for
llvm.loop.distribute metadata
auto-upgrade old two-operand llvm.loop.distribute.enable metadata
---
llvm/include/llvm/IR/AutoUpgrade.h | 7 ++-
llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 3 ++
llvm/lib/IR/AutoUpgrade.cpp | 47 ++++++++++++++++--
.../Bitcode/upgrade-loop-distribute-enable.ll | 37 ++++++++++++++
.../upgrade-loop-distribute-enable.ll.bc | Bin 0 -> 2080 bytes
llvm/test/Verifier/llvm.loop.distribute.ll | 30 ++++-------
6 files changed, 101 insertions(+), 23 deletions(-)
create mode 100644 llvm/test/Bitcode/upgrade-loop-distribute-enable.ll
create mode 100644 llvm/test/Bitcode/upgrade-loop-distribute-enable.ll.bc
diff --git a/llvm/include/llvm/IR/AutoUpgrade.h b/llvm/include/llvm/IR/AutoUpgrade.h
index feb19e69389a9..423fea4205a80 100644
--- a/llvm/include/llvm/IR/AutoUpgrade.h
+++ b/llvm/include/llvm/IR/AutoUpgrade.h
@@ -112,7 +112,12 @@ namespace llvm {
/// Check whether a string looks like an old loop attachment tag.
inline bool mayBeOldLoopAttachmentTag(StringRef Name) {
- return Name.starts_with("llvm.vectorizer.");
+ // "llvm.loop.distribute.enable" is intentionally included: the current
+ // single-operand form shares the tag with the removed two-operand form
+ // (!{!"llvm.loop.distribute.enable", i1 X}), so we can only decide by
+ // inspecting the operands, which happens in upgradeLoopArgument().
+ return Name.starts_with("llvm.vectorizer.") ||
+ Name == "llvm.loop.distribute.enable";
}
/// Upgrade the loop attachment metadata node.
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 33062a0256bb8..5c4f8cb9fbeb1 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -2455,6 +2455,9 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
}
case bitc::METADATA_STRINGS: {
auto CreateNextMDString = [&](StringRef Str) {
+ // Modern bitcode encodes MDStrings via this bulk record, so mirror the
+ // METADATA_STRING check above to arm the loop-attachment upgrader.
+ HasSeenOldLoopTags |= mayBeOldLoopAttachmentTag(Str);
++NumMDStringLoaded;
MetadataList.assignValue(MDString::get(Context, Str), NextMetadataNo);
NextMetadataNo++;
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 229c7757db3dc..2cd42c0822b6c 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -6847,6 +6847,18 @@ void llvm::copyModuleAttrToFunctions(Module &M) {
}
}
+// Old two-operand form: !{!"llvm.loop.distribute.enable", i1 X}. The new
+// single-operand form uses "llvm.loop.distribute.enable" for X = true and
+// "llvm.loop.distribute.disable" for X = false.
+static bool isOldDistributeEnable(const MDTuple *T) {
+ if (T->getNumOperands() != 2)
+ return false;
+ auto *Tag = dyn_cast_or_null<MDString>(T->getOperand(0));
+ if (!Tag || Tag->getString() != "llvm.loop.distribute.enable")
+ return false;
+ return mdconst::hasa<ConstantInt>(T->getOperand(1));
+}
+
static bool isOldLoopArgument(Metadata *MD) {
auto *T = dyn_cast_or_null<MDTuple>(MD);
if (!T)
@@ -6856,7 +6868,9 @@ static bool isOldLoopArgument(Metadata *MD) {
auto *S = dyn_cast_or_null<MDString>(T->getOperand(0));
if (!S)
return false;
- return S->getString().starts_with("llvm.vectorizer.");
+ if (S->getString().starts_with("llvm.vectorizer."))
+ return true;
+ return isOldDistributeEnable(T);
}
static MDString *upgradeLoopTag(LLVMContext &C, StringRef OldTag) {
@@ -6880,17 +6894,28 @@ static Metadata *upgradeLoopArgument(Metadata *MD) {
auto *OldTag = dyn_cast_or_null<MDString>(T->getOperand(0));
if (!OldTag)
return MD;
+
+ LLVMContext &C = T->getContext();
+
+ // Rewrite the old two-operand distribute form to the single-operand pair.
+ if (isOldDistributeEnable(T)) {
+ bool Enable = !mdconst::extract<ConstantInt>(T->getOperand(1))->isZero();
+ return MDTuple::get(
+ C, {MDString::get(C, Enable ? "llvm.loop.distribute.enable"
+ : "llvm.loop.distribute.disable")});
+ }
+
if (!OldTag->getString().starts_with("llvm.vectorizer."))
return MD;
// This has an old tag. Upgrade it.
SmallVector<Metadata *, 8> Ops;
Ops.reserve(T->getNumOperands());
- Ops.push_back(upgradeLoopTag(T->getContext(), OldTag->getString()));
+ Ops.push_back(upgradeLoopTag(C, OldTag->getString()));
for (unsigned I = 1, E = T->getNumOperands(); I != E; ++I)
Ops.push_back(T->getOperand(I));
- return MDTuple::get(T->getContext(), Ops);
+ return MDTuple::get(C, Ops);
}
MDNode *llvm::upgradeInstructionLoopAttachment(MDNode &N) {
@@ -6901,6 +6926,22 @@ MDNode *llvm::upgradeInstructionLoopAttachment(MDNode &N) {
if (none_of(T->operands(), isOldLoopArgument))
return &N;
+ // Fix the old two-operand llvm.loop.distribute.enable nodes in place: the
+ // Verifier rejects any MDNode carrying the distribute tag with more than one
+ // operand, so a leftover reference (from the distinct loop-ID) would still
+ // trigger a diagnostic. In-place mutation is safe on distinct MDNodes.
+ if (T->isDistinct()) {
+ for (unsigned I = 0, E = T->getNumOperands(); I < E; ++I) {
+ auto *OpT = dyn_cast_or_null<MDTuple>(T->getOperand(I));
+ if (OpT && isOldDistributeEnable(OpT))
+ T->replaceOperandWith(I, upgradeLoopArgument(OpT));
+ }
+ if (none_of(T->operands(), isOldLoopArgument))
+ return &N;
+ }
+
+ // Remaining old arguments (e.g. llvm.vectorizer.*) are handled via a wrapper
+ // attachment; the original distinct loop-ID is kept as the first operand.
SmallVector<Metadata *, 8> Ops;
Ops.reserve(T->getNumOperands());
for (Metadata *MD : T->operands())
diff --git a/llvm/test/Bitcode/upgrade-loop-distribute-enable.ll b/llvm/test/Bitcode/upgrade-loop-distribute-enable.ll
new file mode 100644
index 0000000000000..8f1b5aec2d140
--- /dev/null
+++ b/llvm/test/Bitcode/upgrade-loop-distribute-enable.ll
@@ -0,0 +1,37 @@
+; Test that older bitcode carrying the two-operand form of
+; "llvm.loop.distribute.enable" is auto-upgraded to the single-operand
+; enable/disable pair on load.
+;
+; RUN: llvm-dis < %s.bc | FileCheck %s
+; RUN: verify-uselistorder < %s.bc
+
+define void @enable_true() {
+entry:
+ br label %body
+body:
+ br i1 0, label %body, label %exit, !llvm.loop !0
+exit:
+ ret void
+}
+
+define void @enable_false() {
+entry:
+ br label %body
+body:
+ br i1 0, label %body, label %exit, !llvm.loop !2
+exit:
+ ret void
+}
+
+; i1 true -> single-operand enable.
+; i1 false -> disable.
+; CHECK: !{!"llvm.loop.distribute.enable"}
+; CHECK: !{!"llvm.loop.distribute.disable"}
+; The old two-operand nodes must be gone from the module.
+; CHECK-NOT: llvm.loop.distribute.enable", i1
+; CHECK-NOT: llvm.loop.distribute.disable", i1
+
+!0 = distinct !{!0, !1}
+!1 = !{!"llvm.loop.distribute.enable", i1 true}
+!2 = distinct !{!2, !3}
+!3 = !{!"llvm.loop.distribute.enable", i1 false}
diff --git a/llvm/test/Bitcode/upgrade-loop-distribute-enable.ll.bc b/llvm/test/Bitcode/upgrade-loop-distribute-enable.ll.bc
new file mode 100644
index 0000000000000000000000000000000000000000..fdcbda4584522c06b5f5668e53c6c24fede99c65
GIT binary patch
literal 2080
zcmbtVZ%iBK8GntzXA*N~5;pAQ&btdVved*Jh87#!lI=^GD`lIT<^$cbg)_DTnFGcc
z0;J3A*yG4*b#CQlmX=JQPF1UZAuS(Jix$i|%t at _`rt5?n%Ixwd$wUH4*i>zqwC7B>
zec89Y(!F=D?!D)p-=F7so!sp5b2SK6AcQ<Bw*EV>{O;|a{A22S`*Zb2WX1}_s1W)@
zhS2UZ29?2{I=HZC-5ZWv`HKp*(fp<?u6m|IsnwOg=833YD0BY2E?!?7&(U6eP|aSd
z at p{#7blh-`s;VnrH+kc(FO$^=T*o3REpw^Nn^RWTo9%6*>W^hcV_a!G?mkYxHEnMT
zMO9kkC~@goqgSJS5jT3X?V%)7*Oq)nO|^z|W3MNfBcq9OV>3b*X~+$7I^Zu?zwf+o
zLwyXUWZ#_IwX5<VH(%j29#pFK$@C6I+1qGcDM3K{n4@@i@%s5+h#R$k|H5$XbKdx&
zfw;C9IQLP-udaQz*7(os{yTRXMuxxp)5=e`AN~5o`Ok`{hSMi{uKu}q=(Wqg`E;$j
z at 5+yQe)$F8_|b;v1EGEPfE4!M;}BxA-`4<V{}~-Jbg`=Jh4<tLy>H*)+NevbwADwG
ziOPfDo-gN4S0xa-szGQAK59}%$ZV1H*T`&RoGC6QoDpnz2<uPxsn!wkK#gxl at Fta0
zH<zJqO^|-JqO>ixKQFiCI9oz)%MT^OLF}9o8+Hl7AT|<|4-N at ITF~aJ at r@*2WQiV@
zSlPn2+<22ZOD!|xB16sbIzM~SG83~baONqwbtYzw%Psk>n!yh2To=~TC4^v(2*IQf
z?7#-~*x*+c5cX_DIH?r+G(spX45y=q9&X_e3;17W at eNk)$xV=}6J)+LFY)9}hRjB(
zo4n#rNzR<(%<0lREt*oCX-sZOi4E}6rxz at Llv^f6)$hB7V7m|s#=>3LP=^rK2;p%-
zd+TN5AtD~T at zo^0Vke3;z5ys`J++k4%{g?p8FDGATPl#NMd~jyonP~kX_9Nb9JA!z
z^<M+&5Y7%^L+O`}ZYK$e0o`fcO`g2RP|F$Wyi6x0%urjr;`q;Ero3pG<ZM95(>d!Z
zXBmT~n7F<RkP2rZA0;-T$3p4oi4`@zF^jLc at h5Cu=C(t(TC80xQp=ElOKX{o*`{Lq
z<Dx0Sne(D`I%Cd>fYF+FP4y`;$f^$rY!|e5=JAaV;z2>NMH6c*u|^YrbK^Z~e1*kf
z`J|w at U%*%0_*ZP*mm54e7o`@9wHpkz&QMu~0tN3e-}2K}EHj*KT5e9o%=z{iP#?gK
zK%Oq)Y*5gCd>7wjiDCi2Zzt}L!(T+1y#E~xu$)YTRV0SP3m|1Q?l2cbpw0$L<?Y#V
z>gEJhaOjpZq`$tC#fy@@1O!=QIVLus!TMdo$#LP;2z+}rC9 at _(Yf3aNaIIjcJTRtm
zG2d|VI!N_ahB_9l at gF_K;+r(FSx{`ciESwqzE)7I(?oFrz`kXV4R&F}N<n*U-?V4}
zAO4mz<$*)FIT^F&<yIgwC92x0=E1t)s0s3XRQFg0I?i8JfCC{8XwkIid5sW^U?cBf
z!+MY`GvzQ%$}KaZ>1mm5Mr=(%Ze2?>^|?$3?9Bs#nJP(re)MrE2qIQyrDA!)#-g#3
zQW8e+f4?3ZNk7UuTBjkgnB?1Wt`({e+`9 at jK1?ID7wY&;or~tiRN6|fH+O at MLc?ln
zYug)jjwc^wb4s&wG~uzo3j6lM6$lKTF$8*hg9dMRe>l|b83_9fz8>Ba at WESz-i6-K
z0{7j!LVBn<Y@|Jy2Aw5|%nRa$b#i{9>YhVt3Bd7=m%rJ((t+P~Lx~WpQlSuc-T3xo
zBr1_1Rq&7im?ZzU2QQ1JDH%YqrNpuyLo*<kisTYauJY1+FRGj4$%P3rw_`d!BO|s!
zD9|l}?;hI`zv2%jka`gcS_JD^!0FJ3a&pTdJ^1uCMB_6@@HOx<_^yK}!VG<4LGdI>
zJfQK-SzN;Si5ejV+_AhBSiKAlL2et5S)n;3MX8<g`W;^Dl%rcLtbuB at H|}g_R9OWB
z-x`LZ>dAt=be7fH%Wp*}yQBH#_!Z<hkt>J2G7l=9VLuqP?}24${O_2a|0`x6y_1^}
zS09L at _v9L6E&c0<aF#v`PkZDkn}laa-jm_bfbZ)^KOgA#8Ji5Ofj!k7rkgxwqshoN
zHk&-Wzp<tBdA7;#?euw at S&ymN+wvUSWNh^CEyjjGZzmsU=;}S=YdFJuy9PphgJh_~
x!BFpMUuU?qXbAiI!wt^vaA&XA*Dw$~72>_V!;<9=|JQPdcM>rK0;P-*`WG%g;B5c^
literal 0
HcmV?d00001
diff --git a/llvm/test/Verifier/llvm.loop.distribute.ll b/llvm/test/Verifier/llvm.loop.distribute.ll
index 9e1e8138e93dc..65ca27720542b 100644
--- a/llvm/test/Verifier/llvm.loop.distribute.ll
+++ b/llvm/test/Verifier/llvm.loop.distribute.ll
@@ -1,8 +1,7 @@
; Test "llvm.loop.distribute.enable" / "llvm.loop.distribute.disable"
; single-operand validation.
-; DEFINE: %{RUN} = opt -passes=verify %t -disable-output 2>&1 | \
-; DEFINE: FileCheck %s -allow-empty -check-prefix
+; DEFINE: %{VERIFY} = llvm-as -disable-output %t 2>&1
define void @test() {
entry:
@@ -14,36 +13,29 @@ exit:
}
!0 = distinct !{!0, !1}
-; GOOD-NOT: {{.}}
-
; BAD: Expected one operand for llvm.loop.distribute metadata
; Single-operand enable.
-; RUN: cp %s %t
-; RUN: chmod u+w %t
+; RUN: cat %s > %t
; RUN: echo '!1 = !{!"llvm.loop.distribute.enable"}' >> %t
-; RUN: %{RUN} GOOD
+; RUN: %{VERIFY}
; Single-operand disable.
-; RUN: cp %s %t
-; RUN: chmod u+w %t
+; RUN: cat %s > %t
; RUN: echo '!1 = !{!"llvm.loop.distribute.disable"}' >> %t
-; RUN: %{RUN} GOOD
+; RUN: %{VERIFY}
; Two-operand enable with boolean false (legacy form, now rejected).
-; RUN: cp %s %t
-; RUN: chmod u+w %t
+; RUN: cat %s > %t
; RUN: echo '!1 = !{!"llvm.loop.distribute.enable", i1 0}' >> %t
-; RUN: not %{RUN} BAD
+; RUN: not %{VERIFY} | FileCheck %s -check-prefix=BAD
; Two-operand enable with boolean true (legacy form, now rejected).
-; RUN: cp %s %t
-; RUN: chmod u+w %t
+; RUN: cat %s > %t
; RUN: echo '!1 = !{!"llvm.loop.distribute.enable", i1 1}' >> %t
-; RUN: not %{RUN} BAD
+; RUN: not %{VERIFY} | FileCheck %s -check-prefix=BAD
; Two-operand disable (rejected).
-; RUN: cp %s %t
-; RUN: chmod u+w %t
+; RUN: cat %s > %t
; RUN: echo '!1 = !{!"llvm.loop.distribute.disable", i1 0}' >> %t
-; RUN: not %{RUN} BAD
+; RUN: not %{VERIFY} | FileCheck %s -check-prefix=BAD
>From e4f257b97ca79e0df10d1623f9462e7b390f369d Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Tue, 7 Jul 2026 09:47:40 -0700
Subject: [PATCH 3/3] fixup! LangRef changes
---
llvm/docs/LangRef.rst | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9d37207753686..9e31caa1aa8b2 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8385,17 +8385,16 @@ this is only performed if the entire loop cannot be vectorized due to unsafe
memory dependencies. The transformation will attempt to isolate the unsafe
dependencies into their own loop.
-This metadata can be used to selectively enable or disable
-distribution of the loop. Each node has a single operand
-containing the name string:
+This metadata can be used to selectively enable or disable distribution of the
+loop. Each node has a single operand containing the name string:
.. code-block:: llvm
!0 = !{!"llvm.loop.distribute.enable"}
!1 = !{!"llvm.loop.distribute.disable"}
-This metadata should be used in conjunction with ``llvm.loop``
-loop identification metadata.
+This metadata should be used in conjunction with ``llvm.loop`` loop
+identification metadata.
'``llvm.loop.distribute.followup_coincident``' Metadata
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
More information about the cfe-commits
mailing list