Skip to content

llvm-reduce: Try to preserve instruction metadata as argument attributes #133557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

arsenm
Copy link
Contributor

@arsenm arsenm commented Mar 29, 2025

Fixes #131825

@llvmbot
Copy link
Member

llvmbot commented Mar 29, 2025

@llvm/pr-subscribers-llvm-ir

Author: Matt Arsenault (arsenm)

Changes

Fixes #131825


Full diff: https://github.com/llvm/llvm-project/pull/133557.diff

4 Files Affected:

  • (modified) llvm/include/llvm/IR/Attributes.h (+6)
  • (modified) llvm/lib/IR/Attributes.cpp (+32)
  • (added) llvm/test/tools/llvm-reduce/reduce-operands-to-args-metadata-to-attributes.ll (+77)
  • (modified) llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp (+10-1)
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index d6533b9bcbea1..5252f26f398d2 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -42,6 +42,7 @@ class ConstantRangeList;
 class FoldingSetNodeID;
 class Function;
 class LLVMContext;
+class Instruction;
 class Type;
 class raw_ostream;
 enum FPClassTest : unsigned;
@@ -1285,6 +1286,11 @@ class AttrBuilder {
   /// Add initializes attribute.
   AttrBuilder &addInitializesAttr(const ConstantRangeList &CRL);
 
+  /// Add 0 or more parameter attributes which are equivalent to metadata
+  /// attached to \p I. e.g. !align -> align. This assumes the argument type is
+  /// the same as the original instruction and the attribute is compatible.
+  AttrBuilder &addFromEquivalentMetadata(const Instruction &I);
+
   ArrayRef<Attribute> attrs() const { return Attrs; }
 
   bool operator==(const AttrBuilder &B) const;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 8da1dfe914818..8cb8b0d927afd 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -2291,6 +2291,38 @@ AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
   return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());
 }
 
+AttrBuilder &AttrBuilder::addFromEquivalentMetadata(const Instruction &I) {
+  if (const MDNode *NonNull = I.getMetadata(LLVMContext::MD_nonnull))
+    addAttribute(Attribute::NonNull);
+
+  if (const MDNode *NoUndef = I.getMetadata(LLVMContext::MD_noundef))
+    addAttribute(Attribute::NoUndef);
+
+  if (const MDNode *Align = I.getMetadata(LLVMContext::MD_align)) {
+    ConstantInt *CI = mdconst::extract<ConstantInt>(Align->getOperand(0));
+    addAlignmentAttr(CI->getZExtValue());
+  }
+
+  if (const MDNode *Dereferenceable =
+          I.getMetadata(LLVMContext::MD_dereferenceable)) {
+    ConstantInt *CI =
+        mdconst::extract<ConstantInt>(Dereferenceable->getOperand(0));
+    addDereferenceableAttr(CI->getZExtValue());
+  }
+
+  if (const MDNode *DereferenceableOrNull =
+          I.getMetadata(LLVMContext::MD_dereferenceable_or_null)) {
+    ConstantInt *CI =
+        mdconst::extract<ConstantInt>(DereferenceableOrNull->getOperand(0));
+    addDereferenceableAttr(CI->getZExtValue());
+  }
+
+  if (const MDNode *Range = I.getMetadata(LLVMContext::MD_range))
+    addRangeAttr(getConstantRangeFromMetadata(*Range));
+
+  return *this;
+}
+
 AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
   // TODO: Could make this O(n) as we're merging two sorted lists.
   for (const auto &I : B.attrs())
diff --git a/llvm/test/tools/llvm-reduce/reduce-operands-to-args-metadata-to-attributes.ll b/llvm/test/tools/llvm-reduce/reduce-operands-to-args-metadata-to-attributes.ll
new file mode 100644
index 0000000000000..913ba9d3218fd
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-operands-to-args-metadata-to-attributes.ll
@@ -0,0 +1,77 @@
+; Check that equivalent parameter attributes are introduced when
+; moving instructions with metadata to arguments.
+
+; RUN: llvm-reduce %s -o %t --abort-on-invalid-reduction --delta-passes=operands-to-args --test FileCheck --test-arg %s --test-arg --check-prefix=INTERESTING --test-arg --input-file
+; RUN: FileCheck --input-file %t --check-prefix=REDUCED %s
+
+; INTERESTING-LABEL: define ptr @use_nonnull(
+; REDUCED-LABEL: define ptr @use_nonnull(ptr nonnull %nonnull) {
+define ptr @use_nonnull() {
+  %nonnull = load ptr, ptr null, !nonnull !0
+  ret ptr %nonnull
+}
+
+; INTERESTING-LABEL: define void @use_noundef(
+; REDUCED-LABEL: define void @use_noundef(ptr noundef %noundef, <2 x ptr> noundef %noundef_vec) {
+define void @use_noundef() {
+  %noundef = load ptr, ptr null, !noundef !0
+  %noundef_vec = load <2 x ptr>, ptr null, !noundef !0
+  store ptr %noundef, ptr null
+  store <2 x ptr> %noundef_vec, ptr null
+  ret void
+}
+
+; INTERESTING-LABEL: define ptr @use_align(
+; REDUCED-LABEL: define ptr @use_align(ptr align 16 %align) {
+define ptr @use_align() {
+  %align = load ptr, ptr null, !align !1
+  ret ptr %align
+}
+
+; INTERESTING-LABEL: define ptr @use_dereferenceable(
+; REDUCED-LABEL: define ptr @use_dereferenceable(ptr dereferenceable(12345) %deref) {
+define ptr @use_dereferenceable() {
+  %deref = load ptr, ptr null, !dereferenceable !2
+  ret ptr %deref
+}
+
+; INTERESTING-LABEL: define ptr @use_dereferenceable_or_null(
+; REDUCED-LABEL: define ptr @use_dereferenceable_or_null(ptr dereferenceable(77777) %deref) {
+define ptr @use_dereferenceable_or_null() {
+  %deref = load ptr, ptr null, !dereferenceable_or_null !3
+  ret ptr %deref
+}
+
+; INTERESTING-LABEL: define void @use_range(
+; REDUCED-LABEL: define void @use_range(i32 range(i32 8, 25) %simple_range, i32 range(i32 8, 420) %disjoint_range, i32 range(i32 42, 0) %wrapping_range, <2 x i32> range(i32 8, 25) %vector_range) {
+define void @use_range() {
+  %simple_range = load i32, ptr null, !range !4
+  %disjoint_range = load i32, ptr null, !range !5
+  %wrapping_range = load i32, ptr null, !range !6
+  %vector_range = load <2 x i32>, ptr null, !range !4
+  store i32 %simple_range, ptr null
+  store i32 %disjoint_range, ptr null
+  store i32 %wrapping_range, ptr null
+  store <2 x i32> %vector_range, ptr null
+  ret void
+}
+
+; INTERESTING-LABEL: define void @use_noundef_range(
+; REDUCED-LABEL: define void @use_noundef_range(i32 noundef range(i32 8, 25) %load, <2 x i32> noundef range(i32 8, 25) %load_vec) {
+define void @use_noundef_range() {
+  %load = load i32, ptr null, !range !4, !noundef !0
+  %load_vec = load <2 x i32>, ptr null, !range !4, !noundef !0
+  store i32 %load, ptr null
+  store <2 x i32> %load_vec, ptr null
+  ret void
+}
+
+
+
+!0 = !{}
+!1 = !{i64 16}
+!2 = !{i64 12345}
+!3 = !{i64 77777}
+!4 = !{i32 8, i32 25}
+!5 = !{i32 8, i32 25, i32 69, i32 420}
+!6 = !{i32 42, i32 0}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
index 6b1958e24c932..a652f892414df 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
@@ -160,6 +160,8 @@ static void substituteOperandWithArgument(Function *OldF,
     VMap[&OldArg] = &NewArg;          // Add mapping to VMap
   }
 
+  LLVMContext &Ctx = OldF->getContext();
+
   // Adjust the new parameters.
   ValueToValueMapTy OldValMap;
   for (auto Z : zip_first(UniqueValues, drop_begin(NewF->args(), ArgOffset))) {
@@ -176,9 +178,16 @@ static void substituteOperandWithArgument(Function *OldF,
 
   // Replace the actual operands.
   for (Use *Op : OpsToReplace) {
-    Value *NewArg = OldValMap.lookup(Op->get());
+    Argument *NewArg = cast<Argument>(OldValMap.lookup(Op->get()));
     auto *NewUser = cast<Instruction>(VMap.lookup(Op->getUser()));
 
+    // Try to preserve any information contained metadata annotations as the
+    // equivalent parameter attributes if possible.
+    if (auto *MDSrcInst = dyn_cast<Instruction>(Op)) {
+      AttrBuilder AB(Ctx);
+      NewArg->addAttrs(AB.addFromEquivalentMetadata(*MDSrcInst));
+    }
+
     if (PHINode *NewPhi = dyn_cast<PHINode>(NewUser)) {
       PHINode *OldPhi = cast<PHINode>(Op->getUser());
       BasicBlock *OldBB = OldPhi->getIncomingBlock(*Op);

@arsenm arsenm force-pushed the users/arsenm/llvm-reduce/fix-losing-metadata-operands-to-args branch from b6a919f to d6d67eb Compare March 29, 2025 09:17
Base automatically changed from users/arsenm/llvm-reduce/fix-losing-metadata-operands-to-args to main March 29, 2025 09:20
@arsenm arsenm force-pushed the users/arsenm/issue131825/llvm-reduce-preserve-metadata-as-argument-attrs branch from 9867ba4 to afe2a96 Compare March 29, 2025 09:22
@arsenm arsenm force-pushed the users/arsenm/issue131825/llvm-reduce-preserve-metadata-as-argument-attrs branch from afe2a96 to f2b3826 Compare March 30, 2025 11:38
@arsenm arsenm merged commit f77f2b9 into main Apr 1, 2025
11 checks passed
@arsenm arsenm deleted the users/arsenm/issue131825/llvm-reduce-preserve-metadata-as-argument-attrs branch April 1, 2025 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

llvm-reduce's ReduceOperandsToArgs transformation should try to replace load metadata with argument attribute equivalents
4 participants