Skip to content

Enforce single-operand form for llvm.loop.vectorize.predicate metadata - #213902

Open
madhur13490 wants to merge 1 commit into
llvm:mainfrom
madhur13490:phase3-predicate-enable
Open

Enforce single-operand form for llvm.loop.vectorize.predicate metadata#213902
madhur13490 wants to merge 1 commit into
llvm:mainfrom
madhur13490:phase3-predicate-enable

Conversation

@madhur13490

@madhur13490 madhur13490 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Replace the two-operand boolean form
!{!"llvm.loop.vectorize.predicate.enable", i1 0/1} with a single-operand enable/disable pair:

!{!"llvm.loop.vectorize.predicate.enable"}
!{!"llvm.loop.vectorize.predicate.disable"}

The Verifier rejects the two-operand form, AutoUpgrade rewrites old bitcode, and the readers and producers in LLVM, Clang and MLIR are updated.

Please refer to RFC:
https://discourse.llvm.org/t/rfc-enforce-single-operand-format-for-all-enable-metadata-nodes/90571/

Assisted by AI

@llvmorg-github-actions

llvmorg-github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-clang-codegen

Author: Madhur Amilkanthwar (madhur13490)

Changes

Replace the two-operand boolean form
!{!"llvm.loop.vectorize.predicate.enable", i1 0/1} with a single-operand enable/disable pair:

!{!"llvm.loop.vectorize.predicate.enable"}
!{!"llvm.loop.vectorize.predicate.disable"}

The Verifier rejects the two-operand form, AutoUpgrade rewrites old bitcode, and the readers and producers in LLVM, Clang and MLIR are updated.

Please refer to RFC:
https://discourse.llvm.org/t/rfc-enforce-single-operand-format-for-all-enable-metadata-nodes/90571/


Patch is 35.37 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/213902.diff

40 Files Affected:

  • (modified) clang/lib/CodeGen/CGLoopInfo.cpp (+5-5)
  • (modified) clang/test/CodeGenCXX/pragma-loop-predicate.cpp (+2-2)
  • (modified) llvm/docs/LangRef.md (+3-6)
  • (modified) llvm/include/llvm/IR/AutoUpgrade.h (+7-5)
  • (modified) llvm/lib/IR/AutoUpgrade.cpp (+34-19)
  • (modified) llvm/lib/IR/Verifier.cpp (+9)
  • (modified) llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp (+8)
  • (added) llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll (+37)
  • (added) llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc ()
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/ARM/tail-folding-loop-hint.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/ARM/tail-folding-prefer-flag.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/VPlan/AArch64/sve-tail-folding-forced.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/VPlan/AArch64/vplan-printing.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/VPlan/constant-fold.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/induction-costs.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/tail_folding_and_assume_safety.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/tail_loop_folding.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/no-fold-tail-by-masking-iv-external-uses.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/reduction-inloop-uf4.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/reduction-inloop.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/use-scalar-epilogue-if-tp-fails.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/vector-loop-backedge-elimination-predicated-early-exit.ll (+1-1)
  • (added) llvm/test/Verifier/llvm.loop.vectorize.predicate.ll (+41)
  • (modified) mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp (+2-1)
  • (modified) mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp (+19-8)
  • (modified) mlir/test/Target/LLVMIR/Import/metadata-loop.ll (+1-1)
  • (modified) mlir/test/Target/LLVMIR/loop-metadata.mlir (+1-1)
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index 499e2287ae84a..45ec2d36eb7a3 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -228,11 +228,11 @@ clang::CodeGen::LoopInfo::createLoopVectorizeMetadata(
     IsVectorPredicateEnabled =
         (Attrs.VectorizePredicateEnable == LoopAttributes::Enable);
 
-    Metadata *Vals[] = {
-        MDString::get(Ctx, "llvm.loop.vectorize.predicate.enable"),
-        ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt1Ty(Ctx),
-                                                 IsVectorPredicateEnabled))};
-    Args.push_back(MDNode::get(Ctx, Vals));
+    Args.push_back(MDNode::get(
+        Ctx,
+        {MDString::get(Ctx, IsVectorPredicateEnabled
+                                ? "llvm.loop.vectorize.predicate.enable"
+                                : "llvm.loop.vectorize.predicate.disable")}));
   }
 
   // Setting vectorize.width
diff --git a/clang/test/CodeGenCXX/pragma-loop-predicate.cpp b/clang/test/CodeGenCXX/pragma-loop-predicate.cpp
index 8a25ed8de6239..b80c952fb122a 100644
--- a/clang/test/CodeGenCXX/pragma-loop-predicate.cpp
+++ b/clang/test/CodeGenCXX/pragma-loop-predicate.cpp
@@ -106,10 +106,10 @@ void test9(int *List, int Length) {
 // CHECK-NEXT: [[GEN3]] = !{!"llvm.loop.vectorize.enable", i1 true}
 
 // CHECK-NEXT: ![[LOOP1]] = distinct !{![[LOOP1]], [[MP]], [[GEN6:![0-9]+]], [[GEN3]]}
-// CHECK-NEXT: [[GEN6]] = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+// CHECK-NEXT: [[GEN6]] = !{!"llvm.loop.vectorize.predicate.enable"}
 
 // CHECK-NEXT: ![[LOOP2]] = distinct !{![[LOOP2]], [[MP]], [[GEN8:![0-9]+]], [[GEN3]]}
-// CHECK-NEXT: [[GEN8]] = !{!"llvm.loop.vectorize.predicate.enable", i1 false}
+// CHECK-NEXT: [[GEN8]] = !{!"llvm.loop.vectorize.predicate.disable"}
 
 // CHECK-NEXT: ![[LOOP3]] = distinct !{![[LOOP3]], [[MP]], [[GEN6]], [[GEN3]]}
 
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 3735039b99977..58318e8a9888a 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -8073,14 +8073,11 @@ is a bit. If the bit operand value is 1 vectorization is enabled. A value of
 
 This metadata selectively enables or disables creating predicated instructions
 for the loop, which can enable folding of the scalar epilogue loop into the
-main loop. The first operand is the string
-`llvm.loop.vectorize.predicate.enable` and the second operand is a bit. If
-the bit operand value is 1 predication is enabled. A value of 0 disables
-predication:
+main loop. Each node has a single operand containing the name string:
 
 ```llvm
-!0 = !{!"llvm.loop.vectorize.predicate.enable", i1 0}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 1}
+!0 = !{!"llvm.loop.vectorize.predicate.enable"}
+!1 = !{!"llvm.loop.vectorize.predicate.disable"}
 ```
 
 Additionally, enabling predication implicitly enables vectorization.
diff --git a/llvm/include/llvm/IR/AutoUpgrade.h b/llvm/include/llvm/IR/AutoUpgrade.h
index 423fea4205a80..ed8187ed1c512 100644
--- a/llvm/include/llvm/IR/AutoUpgrade.h
+++ b/llvm/include/llvm/IR/AutoUpgrade.h
@@ -112,12 +112,14 @@ namespace llvm {
 
   /// Check whether a string looks like an old loop attachment tag.
   inline bool mayBeOldLoopAttachmentTag(StringRef Name) {
-    // "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().
+    // "llvm.loop.distribute.enable" and
+    // "llvm.loop.vectorize.predicate.enable" are intentionally included: the
+    // current single-operand form shares the tag with the removed two-operand
+    // form (!{!"...", 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";
+           Name == "llvm.loop.distribute.enable" ||
+           Name == "llvm.loop.vectorize.predicate.enable";
   }
 
   /// Upgrade the loop attachment metadata node.
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 4502759417c5a..1a3e538c3f8c6 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -7011,16 +7011,32 @@ 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;
+namespace {
+// Single-operand tags replacing a removed two-operand form
+// !{!"<Enable>", i1 X}: X = true selects Enable, X = false selects Disable.
+struct BooleanLoopTags {
+  StringLiteral Enable;
+  StringLiteral Disable;
+};
+} // namespace
+
+static constexpr BooleanLoopTags OldBooleanLoopTags[] = {
+    {"llvm.loop.distribute.enable", "llvm.loop.distribute.disable"},
+    {"llvm.loop.vectorize.predicate.enable",
+     "llvm.loop.vectorize.predicate.disable"}};
+
+// Return the replacement tags if \p T still uses a removed two-operand form.
+static const BooleanLoopTags *getOldBooleanLoopTags(const MDTuple *T) {
+  if (T->getNumOperands() != 2 || !mdconst::hasa<ConstantInt>(T->getOperand(1)))
+    return nullptr;
   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));
+  if (!Tag)
+    return nullptr;
+  const auto *Tags =
+      find_if(OldBooleanLoopTags, [Tag](const BooleanLoopTags &Candidate) {
+        return Candidate.Enable == Tag->getString();
+      });
+  return Tags == std::end(OldBooleanLoopTags) ? nullptr : Tags;
 }
 
 static bool isOldLoopArgument(Metadata *MD) {
@@ -7034,7 +7050,7 @@ static bool isOldLoopArgument(Metadata *MD) {
     return false;
   if (S->getString().starts_with("llvm.vectorizer."))
     return true;
-  return isOldDistributeEnable(T);
+  return getOldBooleanLoopTags(T) != nullptr;
 }
 
 static MDString *upgradeLoopTag(LLVMContext &C, StringRef OldTag) {
@@ -7061,12 +7077,11 @@ static Metadata *upgradeLoopArgument(Metadata *MD) {
 
   LLVMContext &C = T->getContext();
 
-  // Rewrite the old two-operand distribute form to the single-operand pair.
-  if (isOldDistributeEnable(T)) {
+  // Rewrite a removed two-operand boolean form to the single-operand pair.
+  if (const BooleanLoopTags *Tags = getOldBooleanLoopTags(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")});
+        C, {MDString::get(C, Enable ? Tags->Enable : Tags->Disable)});
   }
 
   if (!OldTag->getString().starts_with("llvm.vectorizer."))
@@ -7090,14 +7105,14 @@ 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.
+  // Fix the removed two-operand boolean nodes in place: the Verifier rejects
+  // any MDNode carrying those tags 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))
+      if (OpT && getOldBooleanLoopTags(OpT))
         T->replaceOperandWith(I, upgradeLoopArgument(OpT));
     }
     if (none_of(T->operands(), isOldLoopArgument))
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index c21b8c427ea46..2b72916ff40b2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1017,6 +1017,15 @@ void Verifier::visitMDNode(const MDNode &BaseMD,
             "Expected one operand for llvm.loop.distribute metadata",
             CurrentMD);
 
+    // Enforce the single-operand form of the vectorize predication metadata.
+    if (CurrentMD->getNumOperands() > 0 &&
+        (CurrentMD->getOperand(0).equalsStr(
+             "llvm.loop.vectorize.predicate.enable") ||
+         CurrentMD->getOperand(0).equalsStr(
+             "llvm.loop.vectorize.predicate.disable")))
+      Check(CurrentMD->getNumOperands() == 1,
+            "Expecting only the metadata name", 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/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 8d875b2b6e492..e1afd87f15fc3 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -287,6 +287,14 @@ void LoopVectorizeHints::getHintsFromMetadata() {
 
     // Check if the hint starts with the loop metadata prefix.
     StringRef Name = S->getString();
+    // The single-operand enable/disable pair carries no argument.
+    if (Args.empty()) {
+      if (Name == "llvm.loop.vectorize.predicate.enable")
+        Predicate.Value = FK_Enabled;
+      else if (Name == "llvm.loop.vectorize.predicate.disable")
+        Predicate.Value = FK_Disabled;
+      continue;
+    }
     if (Args.size() == 1)
       setHint(Name, Args[0]);
   }
diff --git a/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll
new file mode 100644
index 0000000000000..20e1f264e559c
--- /dev/null
+++ b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll
@@ -0,0 +1,37 @@
+; Test that older bitcode carrying the two-operand form of
+; "llvm.loop.vectorize.predicate.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.vectorize.predicate.enable"}
+; CHECK: !{!"llvm.loop.vectorize.predicate.disable"}
+; The old two-operand nodes must be gone from the module.
+; CHECK-NOT: llvm.loop.vectorize.predicate.enable", i1
+; CHECK-NOT: llvm.loop.vectorize.predicate.disable", i1
+
+!0 = distinct !{!0, !1}
+!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!2 = distinct !{!2, !3}
+!3 = !{!"llvm.loop.vectorize.predicate.enable", i1 false}
diff --git a/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc
new file mode 100644
index 0000000000000..d8de6672e251b
Binary files /dev/null and b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc differ
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll b/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll
index 1138b19bd3471..c68421ac4a2a4 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll
@@ -528,7 +528,7 @@ exit:
 
 
 !0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!1 = !{!"llvm.loop.vectorize.predicate.enable"}
 !2 = !{!"branch_weights", i32 10, i32 30}
 
 ;.
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll
index 2f27092622192..80c5d3a89db8e 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll
@@ -447,7 +447,7 @@ exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll
index 0985d7f052a90..dbb541eb032a6 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll
@@ -393,7 +393,7 @@ for.exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
 attributes #1 = { "target-features"="+neon" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll
index f0f9e8e74b3f5..6de37a2dc1dc4 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll
@@ -2394,5 +2394,5 @@ exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll
index 09e5959f7083c..0e09f6b5fd10c 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll
@@ -2691,7 +2691,7 @@ for.body:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
 attributes #1 = { vscale_range(1,16) "target-features"="+neon,+dotprod,+sve" "target-cpu"="neoverse-v2" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll
index dd21d1994d95d..947c6625e9742 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll
@@ -523,7 +523,7 @@ for.exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll
index 03938490e465c..9aa27cee2ecb8 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll
@@ -1285,7 +1285,7 @@ exit:
 
 
 !0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!1 = !{!"llvm.loop.vectorize.predicate.enable"}
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
 attributes #1 = { vscale_range(1,16) "target-features"="+neon,+dotprod,+sve" "target-cpu"="neoverse-v2" }
 attributes #2 = { "target-features"="+neon,+dotprod" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll b/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
index 363223a66f398..72c225127fb9f 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
@@ -370,7 +370,7 @@ attributes #1 = { "target-cpu"="neoverse-v2" }
 
 !0 = distinct !{!0, !1, !2, !3}
 !1 = !{!"llvm.loop.mustprogress"}
-!2 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!2 = !{!"llvm.loop.vectorize.predicate.enable"}
 !3 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 ; BFI computes if is taken 20 times, and loop 32 times. Make sure we round the
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll b/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll
index 4b2e5d051730b..8ce6605696529 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll
@@ -1417,5 +1417,5 @@ for.cond.cleanup:
 !9 = !{!"llvm.loop.interleave.count", i32 1}
 !10 = !{!"llvm.loop.interleave.count", i32 4}
 !11 = !{!"llvm.loop.vectorize.enable", i1 true}
-!12 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!12 = !{!"llvm.loop.vectorize.predicate.enable"}
 !13 = distinct !{!13, !6, !9, !11}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll b/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll
index 2ec48b25af5b5..b6bef8c3fe15c 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll
@@ -877,7 +877,7 @@ attributes #0 = { "target-features"="+sve2" vscale_range(1,16) }
 !0 = distinct !{!0, !1}
 !1 = !{!"llvm.loop.interleave.count", i32 2}
 !2 = distinct !{!2, !3}
-!3 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!3 = !{!"llvm.loop.vectorize.predicate.enable"}
 !4 = distinct !{!4, !5}
 !5 = !{!"llvm.loop.interleave.count", i32 1}
 !6 = !{!7}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll b/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll
index 0b783375a33e1..d323dce104e66 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll
@@ -150,7 +150,7 @@ while.end.loopexit:
 }
 
 !0 = distinct !{!0, !1, !2, !3, !4}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!1 = !{!"llvm.loop.vectorize.predicate.enable"}
 !2 = !{!"llvm.loop.vectorize.scalable.enable", i1 true}
 !3 = !{!"llvm.loop.interleave.count", i32 1}
 !4 = !{!"llvm.loop.vectorize.width", i32 4}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll b/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll
index fbc313eddea8a..912b6a4215590 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll
@@ -55,7 +55,7 @@ attributes #0 = { "target-cpu"="neoverse-v2" }
 
 !0 = distinct !{!0, !1, !2}
 !1 = !{!"llvm.loop.vectorize.enable", i1 true}
-!2 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!2 = !{!"llvm.loop.vectorize.predicate.enable"}
 ;.
 ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
 ; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
diff --git a/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll b/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll
index 1b5db04061631..7e7b96d8a4113 100644
--- a/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll
+++ b/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll
@@ -425,7 +425,7 @@ attributes #0 = { nofree norecurse nounwind "target-features"="+armv8.1-m.main,+
 !6 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 !7 = distinct !{!7, !8}
-!8 = !{!"llvm.loop.vectorize.predi...
[truncated]

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-mlir-llvm

Author: Madhur Amilkanthwar (madhur13490)

Changes

Replace the two-operand boolean form
!{!"llvm.loop.vectorize.predicate.enable", i1 0/1} with a single-operand enable/disable pair:

!{!"llvm.loop.vectorize.predicate.enable"}
!{!"llvm.loop.vectorize.predicate.disable"}

The Verifier rejects the two-operand form, AutoUpgrade rewrites old bitcode, and the readers and producers in LLVM, Clang and MLIR are updated.

Please refer to RFC:
https://discourse.llvm.org/t/rfc-enforce-single-operand-format-for-all-enable-metadata-nodes/90571/


Patch is 35.37 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/213902.diff

40 Files Affected:

  • (modified) clang/lib/CodeGen/CGLoopInfo.cpp (+5-5)
  • (modified) clang/test/CodeGenCXX/pragma-loop-predicate.cpp (+2-2)
  • (modified) llvm/docs/LangRef.md (+3-6)
  • (modified) llvm/include/llvm/IR/AutoUpgrade.h (+7-5)
  • (modified) llvm/lib/IR/AutoUpgrade.cpp (+34-19)
  • (modified) llvm/lib/IR/Verifier.cpp (+9)
  • (modified) llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp (+8)
  • (added) llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll (+37)
  • (added) llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc ()
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/ARM/tail-folding-loop-hint.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/ARM/tail-folding-prefer-flag.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/VPlan/AArch64/sve-tail-folding-forced.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/VPlan/AArch64/vplan-printing.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/VPlan/constant-fold.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/induction-costs.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/tail_folding_and_assume_safety.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/tail_loop_folding.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/no-fold-tail-by-masking-iv-external-uses.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/reduction-inloop-uf4.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/reduction-inloop.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/use-scalar-epilogue-if-tp-fails.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/vector-loop-backedge-elimination-predicated-early-exit.ll (+1-1)
  • (added) llvm/test/Verifier/llvm.loop.vectorize.predicate.ll (+41)
  • (modified) mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp (+2-1)
  • (modified) mlir/lib/Target/LLVMIR/LoopAnnotationTranslation.cpp (+19-8)
  • (modified) mlir/test/Target/LLVMIR/Import/metadata-loop.ll (+1-1)
  • (modified) mlir/test/Target/LLVMIR/loop-metadata.mlir (+1-1)
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index 499e2287ae84a..45ec2d36eb7a3 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -228,11 +228,11 @@ clang::CodeGen::LoopInfo::createLoopVectorizeMetadata(
     IsVectorPredicateEnabled =
         (Attrs.VectorizePredicateEnable == LoopAttributes::Enable);
 
-    Metadata *Vals[] = {
-        MDString::get(Ctx, "llvm.loop.vectorize.predicate.enable"),
-        ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt1Ty(Ctx),
-                                                 IsVectorPredicateEnabled))};
-    Args.push_back(MDNode::get(Ctx, Vals));
+    Args.push_back(MDNode::get(
+        Ctx,
+        {MDString::get(Ctx, IsVectorPredicateEnabled
+                                ? "llvm.loop.vectorize.predicate.enable"
+                                : "llvm.loop.vectorize.predicate.disable")}));
   }
 
   // Setting vectorize.width
diff --git a/clang/test/CodeGenCXX/pragma-loop-predicate.cpp b/clang/test/CodeGenCXX/pragma-loop-predicate.cpp
index 8a25ed8de6239..b80c952fb122a 100644
--- a/clang/test/CodeGenCXX/pragma-loop-predicate.cpp
+++ b/clang/test/CodeGenCXX/pragma-loop-predicate.cpp
@@ -106,10 +106,10 @@ void test9(int *List, int Length) {
 // CHECK-NEXT: [[GEN3]] = !{!"llvm.loop.vectorize.enable", i1 true}
 
 // CHECK-NEXT: ![[LOOP1]] = distinct !{![[LOOP1]], [[MP]], [[GEN6:![0-9]+]], [[GEN3]]}
-// CHECK-NEXT: [[GEN6]] = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+// CHECK-NEXT: [[GEN6]] = !{!"llvm.loop.vectorize.predicate.enable"}
 
 // CHECK-NEXT: ![[LOOP2]] = distinct !{![[LOOP2]], [[MP]], [[GEN8:![0-9]+]], [[GEN3]]}
-// CHECK-NEXT: [[GEN8]] = !{!"llvm.loop.vectorize.predicate.enable", i1 false}
+// CHECK-NEXT: [[GEN8]] = !{!"llvm.loop.vectorize.predicate.disable"}
 
 // CHECK-NEXT: ![[LOOP3]] = distinct !{![[LOOP3]], [[MP]], [[GEN6]], [[GEN3]]}
 
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 3735039b99977..58318e8a9888a 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -8073,14 +8073,11 @@ is a bit. If the bit operand value is 1 vectorization is enabled. A value of
 
 This metadata selectively enables or disables creating predicated instructions
 for the loop, which can enable folding of the scalar epilogue loop into the
-main loop. The first operand is the string
-`llvm.loop.vectorize.predicate.enable` and the second operand is a bit. If
-the bit operand value is 1 predication is enabled. A value of 0 disables
-predication:
+main loop. Each node has a single operand containing the name string:
 
 ```llvm
-!0 = !{!"llvm.loop.vectorize.predicate.enable", i1 0}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 1}
+!0 = !{!"llvm.loop.vectorize.predicate.enable"}
+!1 = !{!"llvm.loop.vectorize.predicate.disable"}
 ```
 
 Additionally, enabling predication implicitly enables vectorization.
diff --git a/llvm/include/llvm/IR/AutoUpgrade.h b/llvm/include/llvm/IR/AutoUpgrade.h
index 423fea4205a80..ed8187ed1c512 100644
--- a/llvm/include/llvm/IR/AutoUpgrade.h
+++ b/llvm/include/llvm/IR/AutoUpgrade.h
@@ -112,12 +112,14 @@ namespace llvm {
 
   /// Check whether a string looks like an old loop attachment tag.
   inline bool mayBeOldLoopAttachmentTag(StringRef Name) {
-    // "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().
+    // "llvm.loop.distribute.enable" and
+    // "llvm.loop.vectorize.predicate.enable" are intentionally included: the
+    // current single-operand form shares the tag with the removed two-operand
+    // form (!{!"...", 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";
+           Name == "llvm.loop.distribute.enable" ||
+           Name == "llvm.loop.vectorize.predicate.enable";
   }
 
   /// Upgrade the loop attachment metadata node.
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 4502759417c5a..1a3e538c3f8c6 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -7011,16 +7011,32 @@ 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;
+namespace {
+// Single-operand tags replacing a removed two-operand form
+// !{!"<Enable>", i1 X}: X = true selects Enable, X = false selects Disable.
+struct BooleanLoopTags {
+  StringLiteral Enable;
+  StringLiteral Disable;
+};
+} // namespace
+
+static constexpr BooleanLoopTags OldBooleanLoopTags[] = {
+    {"llvm.loop.distribute.enable", "llvm.loop.distribute.disable"},
+    {"llvm.loop.vectorize.predicate.enable",
+     "llvm.loop.vectorize.predicate.disable"}};
+
+// Return the replacement tags if \p T still uses a removed two-operand form.
+static const BooleanLoopTags *getOldBooleanLoopTags(const MDTuple *T) {
+  if (T->getNumOperands() != 2 || !mdconst::hasa<ConstantInt>(T->getOperand(1)))
+    return nullptr;
   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));
+  if (!Tag)
+    return nullptr;
+  const auto *Tags =
+      find_if(OldBooleanLoopTags, [Tag](const BooleanLoopTags &Candidate) {
+        return Candidate.Enable == Tag->getString();
+      });
+  return Tags == std::end(OldBooleanLoopTags) ? nullptr : Tags;
 }
 
 static bool isOldLoopArgument(Metadata *MD) {
@@ -7034,7 +7050,7 @@ static bool isOldLoopArgument(Metadata *MD) {
     return false;
   if (S->getString().starts_with("llvm.vectorizer."))
     return true;
-  return isOldDistributeEnable(T);
+  return getOldBooleanLoopTags(T) != nullptr;
 }
 
 static MDString *upgradeLoopTag(LLVMContext &C, StringRef OldTag) {
@@ -7061,12 +7077,11 @@ static Metadata *upgradeLoopArgument(Metadata *MD) {
 
   LLVMContext &C = T->getContext();
 
-  // Rewrite the old two-operand distribute form to the single-operand pair.
-  if (isOldDistributeEnable(T)) {
+  // Rewrite a removed two-operand boolean form to the single-operand pair.
+  if (const BooleanLoopTags *Tags = getOldBooleanLoopTags(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")});
+        C, {MDString::get(C, Enable ? Tags->Enable : Tags->Disable)});
   }
 
   if (!OldTag->getString().starts_with("llvm.vectorizer."))
@@ -7090,14 +7105,14 @@ 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.
+  // Fix the removed two-operand boolean nodes in place: the Verifier rejects
+  // any MDNode carrying those tags 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))
+      if (OpT && getOldBooleanLoopTags(OpT))
         T->replaceOperandWith(I, upgradeLoopArgument(OpT));
     }
     if (none_of(T->operands(), isOldLoopArgument))
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index c21b8c427ea46..2b72916ff40b2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1017,6 +1017,15 @@ void Verifier::visitMDNode(const MDNode &BaseMD,
             "Expected one operand for llvm.loop.distribute metadata",
             CurrentMD);
 
+    // Enforce the single-operand form of the vectorize predication metadata.
+    if (CurrentMD->getNumOperands() > 0 &&
+        (CurrentMD->getOperand(0).equalsStr(
+             "llvm.loop.vectorize.predicate.enable") ||
+         CurrentMD->getOperand(0).equalsStr(
+             "llvm.loop.vectorize.predicate.disable")))
+      Check(CurrentMD->getNumOperands() == 1,
+            "Expecting only the metadata name", 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/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 8d875b2b6e492..e1afd87f15fc3 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -287,6 +287,14 @@ void LoopVectorizeHints::getHintsFromMetadata() {
 
     // Check if the hint starts with the loop metadata prefix.
     StringRef Name = S->getString();
+    // The single-operand enable/disable pair carries no argument.
+    if (Args.empty()) {
+      if (Name == "llvm.loop.vectorize.predicate.enable")
+        Predicate.Value = FK_Enabled;
+      else if (Name == "llvm.loop.vectorize.predicate.disable")
+        Predicate.Value = FK_Disabled;
+      continue;
+    }
     if (Args.size() == 1)
       setHint(Name, Args[0]);
   }
diff --git a/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll
new file mode 100644
index 0000000000000..20e1f264e559c
--- /dev/null
+++ b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll
@@ -0,0 +1,37 @@
+; Test that older bitcode carrying the two-operand form of
+; "llvm.loop.vectorize.predicate.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.vectorize.predicate.enable"}
+; CHECK: !{!"llvm.loop.vectorize.predicate.disable"}
+; The old two-operand nodes must be gone from the module.
+; CHECK-NOT: llvm.loop.vectorize.predicate.enable", i1
+; CHECK-NOT: llvm.loop.vectorize.predicate.disable", i1
+
+!0 = distinct !{!0, !1}
+!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!2 = distinct !{!2, !3}
+!3 = !{!"llvm.loop.vectorize.predicate.enable", i1 false}
diff --git a/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc
new file mode 100644
index 0000000000000..d8de6672e251b
Binary files /dev/null and b/llvm/test/Bitcode/upgrade-loop-vectorize-predicate-enable.ll.bc differ
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll b/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll
index 1138b19bd3471..c68421ac4a2a4 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/low_trip_count_predicates.ll
@@ -528,7 +528,7 @@ exit:
 
 
 !0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!1 = !{!"llvm.loop.vectorize.predicate.enable"}
 !2 = !{!"branch_weights", i32 10, i32 30}
 
 ;.
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll
index 2f27092622192..80c5d3a89db8e 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-epilogue.ll
@@ -447,7 +447,7 @@ exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll
index 0985d7f052a90..dbb541eb032a6 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-mixed.ll
@@ -393,7 +393,7 @@ for.exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
 attributes #1 = { "target-features"="+neon" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll
index f0f9e8e74b3f5..6de37a2dc1dc4 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product-neon.ll
@@ -2394,5 +2394,5 @@ exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll
index 09e5959f7083c..0e09f6b5fd10c 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-dot-product.ll
@@ -2691,7 +2691,7 @@ for.body:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
 attributes #1 = { vscale_range(1,16) "target-features"="+neon,+dotprod,+sve" "target-cpu"="neoverse-v2" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll
index dd21d1994d95d..947c6625e9742 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce-sub.ll
@@ -523,7 +523,7 @@ for.exit:
 
 !7 = distinct !{!7, !8, !9, !10}
 !8 = !{!"llvm.loop.mustprogress"}
-!9 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!9 = !{!"llvm.loop.vectorize.predicate.enable"}
 !10 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll
index 03938490e465c..9aa27cee2ecb8 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/partial-reduce.ll
@@ -1285,7 +1285,7 @@ exit:
 
 
 !0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!1 = !{!"llvm.loop.vectorize.predicate.enable"}
 attributes #0 = { vscale_range(1,16) "target-features"="+sve" }
 attributes #1 = { vscale_range(1,16) "target-features"="+neon,+dotprod,+sve" "target-cpu"="neoverse-v2" }
 attributes #2 = { "target-features"="+neon,+dotprod" }
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll b/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
index 363223a66f398..72c225127fb9f 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
@@ -370,7 +370,7 @@ attributes #1 = { "target-cpu"="neoverse-v2" }
 
 !0 = distinct !{!0, !1, !2, !3}
 !1 = !{!"llvm.loop.mustprogress"}
-!2 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!2 = !{!"llvm.loop.vectorize.predicate.enable"}
 !3 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 ; BFI computes if is taken 20 times, and loop 32 times. Make sure we round the
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll b/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll
index 4b2e5d051730b..8ce6605696529 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/strict-fadd.ll
@@ -1417,5 +1417,5 @@ for.cond.cleanup:
 !9 = !{!"llvm.loop.interleave.count", i32 1}
 !10 = !{!"llvm.loop.interleave.count", i32 4}
 !11 = !{!"llvm.loop.vectorize.enable", i1 true}
-!12 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!12 = !{!"llvm.loop.vectorize.predicate.enable"}
 !13 = distinct !{!13, !6, !9, !11}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll b/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll
index 2ec48b25af5b5..b6bef8c3fe15c 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/sve2-histcnt.ll
@@ -877,7 +877,7 @@ attributes #0 = { "target-features"="+sve2" vscale_range(1,16) }
 !0 = distinct !{!0, !1}
 !1 = !{!"llvm.loop.interleave.count", i32 2}
 !2 = distinct !{!2, !3}
-!3 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!3 = !{!"llvm.loop.vectorize.predicate.enable"}
 !4 = distinct !{!4, !5}
 !5 = !{!"llvm.loop.interleave.count", i32 1}
 !6 = !{!7}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll b/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll
index 0b783375a33e1..d323dce104e66 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/tail-folding-styles.ll
@@ -150,7 +150,7 @@ while.end.loopexit:
 }
 
 !0 = distinct !{!0, !1, !2, !3, !4}
-!1 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!1 = !{!"llvm.loop.vectorize.predicate.enable"}
 !2 = !{!"llvm.loop.vectorize.scalable.enable", i1 true}
 !3 = !{!"llvm.loop.interleave.count", i32 1}
 !4 = !{!"llvm.loop.vectorize.width", i32 4}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll b/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll
index fbc313eddea8a..912b6a4215590 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/widen-gep-all-indices-invariant.ll
@@ -55,7 +55,7 @@ attributes #0 = { "target-cpu"="neoverse-v2" }
 
 !0 = distinct !{!0, !1, !2}
 !1 = !{!"llvm.loop.vectorize.enable", i1 true}
-!2 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
+!2 = !{!"llvm.loop.vectorize.predicate.enable"}
 ;.
 ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
 ; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
diff --git a/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll b/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll
index 1b5db04061631..7e7b96d8a4113 100644
--- a/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll
+++ b/llvm/test/Transforms/LoopVectorize/ARM/prefer-tail-loop-folding.ll
@@ -425,7 +425,7 @@ attributes #0 = { nofree norecurse nounwind "target-features"="+armv8.1-m.main,+
 !6 = !{!"llvm.loop.vectorize.enable", i1 true}
 
 !7 = distinct !{!7, !8}
-!8 = !{!"llvm.loop.vectorize.predi...
[truncated]

Replace the two-operand boolean form
!{!"llvm.loop.vectorize.predicate.enable", i1 0/1} with a single-operand
enable/disable pair:

  !{!"llvm.loop.vectorize.predicate.enable"}
  !{!"llvm.loop.vectorize.predicate.disable"}

The Verifier rejects the two-operand form, AutoUpgrade rewrites old
bitcode, and the readers and producers in LLVM, Clang and MLIR are
updated.

Please refer to RFC:
https://discourse.llvm.org/t/rfc-enforce-single-operand-format-for-all-enable-metadata-nodes/90571/
@madhur13490
madhur13490 force-pushed the phase3-predicate-enable branch from 19ad2d7 to 31cd99c Compare August 4, 2026 11:25
static bool isOldVectorizeEnable(const MDTuple *T) {
if (T->getNumOperands() != 2)
return false;
// Return the replacement tags if \p T still uses a removed two-operand form.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Return the replacement tags if \p T still uses a removed two-operand form.
/// Return the replacement tags if \p T still uses a removed two-operand form.

[nit]

{"llvm.loop.vectorize.predicate.enable",
"llvm.loop.vectorize.predicate.disable"}};

// Return the replacement tags for the enable tag \p Name, or nullptr.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Return the replacement tags for the enable tag \p Name, or nullptr.
/// Return the replacement tags for the enable tag \p Name, or nullptr.

[nit]

// enable/disable pair.
if (isOldVectorizeEnable(T))
return makeVectorizeEnableNode(C, T->getOperand(1));
// Rewrite a removed two-operand boolean form to the single-operand pair.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Rewrite a removed two-operand boolean form to the single-operand pair.
/// Rewrite a removed two-operand boolean form to the single-operand pair.

[nit]

Comment on lines +88 to +89
/// Emits the single-operand node of an enable/disable pair. As in
/// convertBoolNode, \p negated ^ the attribute value is the enable bit.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add explantion that its ternary logic: If BoolAttr is unset, don't add any node.

Comment thread llvm/lib/IR/Verifier.cpp
Comment on lines +1027 to +1035
// Enforce the single-operand form of the vectorize predication metadata.
if (CurrentMD->getNumOperands() > 0 &&
(CurrentMD->getOperand(0).equalsStr(
"llvm.loop.vectorize.predicate.enable") ||
CurrentMD->getOperand(0).equalsStr(
"llvm.loop.vectorize.predicate.disable")))
Check(CurrentMD->getNumOperands() == 1,
"Expecting only the metadata name", CurrentMD);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be generalized with the code above?

Comment on lines 119 to +122
return Name.starts_with("llvm.vectorizer.") ||
Name == "llvm.loop.distribute.enable" ||
Name == "llvm.loop.vectorize.enable";
Name == "llvm.loop.vectorize.enable" ||
Name == "llvm.loop.vectorize.predicate.enable";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the OldBooleanLoopTags list here?

Comment on lines 316 to 317
Hint *Hints[] = {&Width, &Interleave, &Force,
&IsVectorized, &Predicate, &Scalable};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these stil needed? Predicate.Name is us used only be the old mechanism

Comment thread llvm/docs/LangRef.md
!1 = !{!"llvm.loop.vectorize.disable"}
```

#### '`llvm.loop.vectorize.predicate.enable`' Metadata

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### '`llvm.loop.vectorize.predicate.enable`' and '`llvm.loop.vectorize.predicate.disable`' Metadata

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants