[llvm] [Attributor] Propagate alignment through ptrmask (PR #150158)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 28 18:57:56 PDT 2025


https://github.com/Shoreshen updated https://github.com/llvm/llvm-project/pull/150158

>From bd9c95b1e2c35e5655f4c0814c58c7e5ecc21c68 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 23 Jul 2025 10:57:39 +0800
Subject: [PATCH 1/5] propagate alignment through ptrmask instruction

---
 .../Transforms/IPO/AttributorAttributes.cpp   |  62 +++++++++++
 .../Transforms/Attributor/align-ptrmask.ll    | 101 ++++++++++++++++++
 2 files changed, 163 insertions(+)
 create mode 100644 llvm/test/Transforms/Attributor/align-ptrmask.ll

diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 3c24d2eca647d..67aed0a327f8e 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -5203,6 +5203,32 @@ static unsigned getKnownAlignForUse(Attributor &A, AAAlign &QueryingAA,
       TrackUse = true;
     return 0;
   }
+  if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+    if (II->getIntrinsicID() == Intrinsic::ptrmask) {
+      auto *ConstVals = A.getAAFor<AAPotentialConstantValues>(
+          QueryingAA, IRPosition::value(*(II->getOperand(1))),
+          DepClassTy::NONE);
+      const AAAlign *AlignAA = A.getAAFor<AAAlign>(
+          QueryingAA, IRPosition::value(*(II)), DepClassTy::NONE);
+      if (ConstVals && ConstVals->isValidState()) {
+        if (ConstVals->isAtFixpoint()) {
+          uint64_t TrailingZeros = 64;
+          for (const auto &It : ConstVals->getAssumedSet())
+            if (It.countTrailingZeros() < TrailingZeros)
+              TrailingZeros = It.countTrailingZeros();
+          if (TrailingZeros < 64) {
+            uint64_t Mask = 1 << TrailingZeros;
+            if (Mask >= AlignAA->getKnownAlign().value()) {
+              return 0;
+            }
+          }
+          return AlignAA->getKnownAlign().value();
+        }
+      } else if (AlignAA) {
+        return AlignAA->getKnownAlign().value();
+      }
+    }
+  }
 
   MaybeAlign MA;
   if (const auto *CB = dyn_cast<CallBase>(I)) {
@@ -5502,6 +5528,42 @@ struct AAAlignCallSiteReturned final
   AAAlignCallSiteReturned(const IRPosition &IRP, Attributor &A)
       : Base(IRP, A) {}
 
+  ChangeStatus updateImpl(Attributor &A) override {
+    Instruction *I = getIRPosition().getCtxI();
+    if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+      if (II->getIntrinsicID() == Intrinsic::ptrmask) {
+        const AAPotentialConstantValues *ConstVals =
+            A.getAAFor<AAPotentialConstantValues>(
+                *this, IRPosition::value(*(II->getOperand(1))),
+                DepClassTy::REQUIRED);
+        const AAAlign *AlignAA =
+            A.getAAFor<AAAlign>(*this, IRPosition::value(*(II->getOperand(0))),
+                                DepClassTy::REQUIRED);
+        uint64_t Alignment = 0;
+        if (ConstVals && ConstVals->isValidState()) {
+          unsigned TrailingZeros = 64;
+          for (const auto &It : ConstVals->getAssumedSet())
+            if (It.countTrailingZeros() < TrailingZeros)
+              TrailingZeros = It.countTrailingZeros();
+          if (TrailingZeros < 64)
+            Alignment = 1 << TrailingZeros;
+        }
+        if (AlignAA && AlignAA->isValidState() &&
+            Alignment < AlignAA->getAssumedAlign().value())
+          Alignment = AlignAA->getAssumedAlign().value();
+
+        if (Alignment != 0) {
+          uint64_t OldAssumed = getAssumed();
+          takeAssumedMinimum(Alignment);
+          return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
+                                            : ChangeStatus::CHANGED;
+        } else {
+          return ChangeStatus::UNCHANGED;
+        }
+      }
+    }
+    return Base::updateImpl(A);
+  };
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(align); }
 };
diff --git a/llvm/test/Transforms/Attributor/align-ptrmask.ll b/llvm/test/Transforms/Attributor/align-ptrmask.ll
new file mode 100644
index 0000000000000..710f1c3983b7b
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/align-ptrmask.ll
@@ -0,0 +1,101 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=attributor -S < %s | FileCheck %s
+
+define float @align_ptrmask_back_no_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define float @align_ptrmask_back_no_prop(
+; CHECK-SAME: ptr nofree readonly align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0:![0-9]+]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %sel = select i1 %cmp1, i64 -32, i64 -8
+  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
+  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
+  %res = load float, ptr %p, align 8
+  ret float %res
+}
+
+define float @align_ptrmask_back_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define float @align_ptrmask_back_prop(
+; CHECK-SAME: ptr nofree readonly align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
+; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2]]
+; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 16, !invariant.load [[META0]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %sel = select i1 %cmp1, i64 -32, i64 -8
+  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
+  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
+  %res = load float, ptr %p, align 16
+  ret float %res
+}
+
+define float @align_ptrmask_forward_mask(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define float @align_ptrmask_forward_mask(
+; CHECK-SAME: ptr nofree readonly align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2]]
+; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %sel = select i1 %cmp1, i64 -32, i64 -8
+  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
+  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
+  %res = load float, ptr %p, align 4
+  ret float %res
+}
+
+define float @align_ptrmask_forward_ptr(ptr align 16 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define float @align_ptrmask_forward_ptr(
+; CHECK-SAME: ptr nofree readonly align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
+; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2]]
+; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 16, !invariant.load [[META0]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %sel = select i1 %cmp1, i64 -32, i64 -8
+  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
+  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
+  %res = load float, ptr %p, align 4
+  ret float %res
+}
+
+define float @align_ptrmask_forward_nonconst_mask(ptr align 8 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define float @align_ptrmask_forward_nonconst_mask(
+; CHECK-SAME: ptr nofree readonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 [[Y]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR2]]
+; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %sel = select i1 %cmp1, i64 -32, i64 %y
+  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
+  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
+  %res = load float, ptr %p, align 4
+  ret float %res
+}
+
+define float @align_ptrmask_back_nonconst_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define float @align_ptrmask_back_nonconst_mask(
+; CHECK-SAME: ptr nofree readonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 [[Y]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR2]]
+; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %sel = select i1 %cmp1, i64 -32, i64 %y
+  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
+  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
+  %res = load float, ptr %p, align 8
+  ret float %res
+}
+;.
+; CHECK: [[META0]] = !{}
+;.

>From 48cd7d645d59f988d27f1a538aa52c3ecb47f8f1 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Mon, 28 Jul 2025 13:35:17 +0800
Subject: [PATCH 2/5] fix matthews comments

---
 .../Transforms/IPO/AttributorAttributes.cpp   | 140 +++++++++-------
 .../Transforms/Attributor/align-ptrmask.ll    | 149 +++++++++++-------
 llvm/test/lit.cfg.py                          |   2 +-
 3 files changed, 180 insertions(+), 111 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 67aed0a327f8e..e1b634eb328a7 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -5188,6 +5188,82 @@ struct AADereferenceableCallSiteReturned final
 // ------------------------ Align Argument Attribute ------------------------
 
 namespace {
+
+static std::optional<uint64_t>
+getKnownAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
+                          const IntrinsicInst *II) {
+  switch (II->getIntrinsicID()) {
+  case Intrinsic::ptrmask: {
+    auto *ConstVals = A.getAAFor<AAPotentialConstantValues>(
+        QueryingAA, IRPosition::value(*(II->getOperand(1))), DepClassTy::NONE);
+    const AAAlign *AlignAA = A.getAAFor<AAAlign>(
+        QueryingAA, IRPosition::value(*(II)), DepClassTy::NONE);
+    if (ConstVals && ConstVals->isValidState()) {
+      if (ConstVals->isAtFixpoint()) {
+        const DataLayout &DL = A.getDataLayout();
+        unsigned Size =
+            DL.getPointerTypeSizeInBits(II->getOperand(0)->getType());
+        uint64_t TrailingZeros = Size;
+        for (const auto &It : ConstVals->getAssumedSet())
+          if (It.countTrailingZeros() < TrailingZeros)
+            TrailingZeros = It.countTrailingZeros();
+        if (TrailingZeros < Size) {
+          uint64_t Mask = 1 << TrailingZeros;
+          if (Mask >= AlignAA->getKnownAlign().value()) {
+            return 0;
+          }
+        }
+        return AlignAA->getKnownAlign().value();
+      }
+    } else if (AlignAA) {
+      return AlignAA->getKnownAlign().value();
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  return std::nullopt;
+}
+
+static std::optional<uint64_t>
+getAssumedAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
+                            const IntrinsicInst *II) {
+  switch (II->getIntrinsicID()) {
+  case Intrinsic::ptrmask: {
+    const AAPotentialConstantValues *ConstVals =
+        A.getAAFor<AAPotentialConstantValues>(
+            QueryingAA, IRPosition::value(*(II->getOperand(1))),
+            DepClassTy::REQUIRED);
+    const AAAlign *AlignAA =
+        A.getAAFor<AAAlign>(QueryingAA, IRPosition::value(*(II->getOperand(0))),
+                            DepClassTy::REQUIRED);
+    uint64_t Alignment = 0;
+    if (ConstVals && ConstVals->isValidState()) {
+      const DataLayout &DL = A.getDataLayout();
+      unsigned Size = DL.getPointerTypeSizeInBits(II->getOperand(0)->getType());
+      unsigned TrailingZeros = Size;
+      for (const auto &It : ConstVals->getAssumedSet())
+        if (It.countTrailingZeros() < TrailingZeros)
+          TrailingZeros = It.countTrailingZeros();
+      if (TrailingZeros < Size)
+        Alignment = 1 << TrailingZeros;
+    }
+    if (AlignAA && AlignAA->isValidState() &&
+        Alignment < AlignAA->getAssumedAlign().value())
+      Alignment = AlignAA->getAssumedAlign().value();
+
+    if (Alignment != 0) {
+      return Alignment;
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  return std::nullopt;
+}
+
 static unsigned getKnownAlignForUse(Attributor &A, AAAlign &QueryingAA,
                                     Value &AssociatedValue, const Use *U,
                                     const Instruction *I, bool &TrackUse) {
@@ -5204,30 +5280,10 @@ static unsigned getKnownAlignForUse(Attributor &A, AAAlign &QueryingAA,
     return 0;
   }
   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
-    if (II->getIntrinsicID() == Intrinsic::ptrmask) {
-      auto *ConstVals = A.getAAFor<AAPotentialConstantValues>(
-          QueryingAA, IRPosition::value(*(II->getOperand(1))),
-          DepClassTy::NONE);
-      const AAAlign *AlignAA = A.getAAFor<AAAlign>(
-          QueryingAA, IRPosition::value(*(II)), DepClassTy::NONE);
-      if (ConstVals && ConstVals->isValidState()) {
-        if (ConstVals->isAtFixpoint()) {
-          uint64_t TrailingZeros = 64;
-          for (const auto &It : ConstVals->getAssumedSet())
-            if (It.countTrailingZeros() < TrailingZeros)
-              TrailingZeros = It.countTrailingZeros();
-          if (TrailingZeros < 64) {
-            uint64_t Mask = 1 << TrailingZeros;
-            if (Mask >= AlignAA->getKnownAlign().value()) {
-              return 0;
-            }
-          }
-          return AlignAA->getKnownAlign().value();
-        }
-      } else if (AlignAA) {
-        return AlignAA->getKnownAlign().value();
-      }
-    }
+    std::optional<uint64_t> Align =
+        getKnownAlignForIntrinsic(A, QueryingAA, II);
+    if (Align.has_value())
+      return Align.value();
   }
 
   MaybeAlign MA;
@@ -5531,36 +5587,14 @@ struct AAAlignCallSiteReturned final
   ChangeStatus updateImpl(Attributor &A) override {
     Instruction *I = getIRPosition().getCtxI();
     if (auto *II = dyn_cast<IntrinsicInst>(I)) {
-      if (II->getIntrinsicID() == Intrinsic::ptrmask) {
-        const AAPotentialConstantValues *ConstVals =
-            A.getAAFor<AAPotentialConstantValues>(
-                *this, IRPosition::value(*(II->getOperand(1))),
-                DepClassTy::REQUIRED);
-        const AAAlign *AlignAA =
-            A.getAAFor<AAAlign>(*this, IRPosition::value(*(II->getOperand(0))),
-                                DepClassTy::REQUIRED);
-        uint64_t Alignment = 0;
-        if (ConstVals && ConstVals->isValidState()) {
-          unsigned TrailingZeros = 64;
-          for (const auto &It : ConstVals->getAssumedSet())
-            if (It.countTrailingZeros() < TrailingZeros)
-              TrailingZeros = It.countTrailingZeros();
-          if (TrailingZeros < 64)
-            Alignment = 1 << TrailingZeros;
-        }
-        if (AlignAA && AlignAA->isValidState() &&
-            Alignment < AlignAA->getAssumedAlign().value())
-          Alignment = AlignAA->getAssumedAlign().value();
-
-        if (Alignment != 0) {
-          uint64_t OldAssumed = getAssumed();
-          takeAssumedMinimum(Alignment);
-          return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
-                                            : ChangeStatus::CHANGED;
-        } else {
-          return ChangeStatus::UNCHANGED;
-        }
+      std::optional<uint64_t> Align = getAssumedAlignForIntrinsic(A, *this, II);
+      if (Align.has_value()) {
+        uint64_t OldAssumed = getAssumed();
+        takeAssumedMinimum(Align.value());
+        return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
+                                          : ChangeStatus::CHANGED;
       }
+      return ChangeStatus::UNCHANGED;
     }
     return Base::updateImpl(A);
   };
diff --git a/llvm/test/Transforms/Attributor/align-ptrmask.ll b/llvm/test/Transforms/Attributor/align-ptrmask.ll
index 710f1c3983b7b..117e551f6ea47 100644
--- a/llvm/test/Transforms/Attributor/align-ptrmask.ll
+++ b/llvm/test/Transforms/Attributor/align-ptrmask.ll
@@ -1,101 +1,136 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -passes=attributor -S < %s | FileCheck %s
 
-define float @align_ptrmask_back_no_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
-; CHECK-LABEL: define float @align_ptrmask_back_no_prop(
-; CHECK-SAME: ptr nofree readonly align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0:[0-9]+]] {
+define ptr @align_ptrmask_back_no_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_no_prop(
+; CHECK-SAME: ptr nofree writeonly align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
-; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2:[0-9]+]]
-; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0:![0-9]+]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 -8
   %sel1 = select i1 %cmp2, i64 %sel, i64 -16
-  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
-  %res = load float, ptr %p, align 8
-  ret float %res
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
+  store float 1.0, ptr %p, align 8
+  ret ptr %p
 }
 
-define float @align_ptrmask_back_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
-; CHECK-LABEL: define float @align_ptrmask_back_prop(
-; CHECK-SAME: ptr nofree readonly align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+define ptr @align_ptrmask_back_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define noundef nonnull align 16 dereferenceable(4) ptr @align_ptrmask_back_prop(
+; CHECK-SAME: ptr nofree writeonly align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
-; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2]]
-; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 16, !invariant.load [[META0]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 16 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 16
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 -8
   %sel1 = select i1 %cmp2, i64 %sel, i64 -16
-  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
-  %res = load float, ptr %p, align 16
-  ret float %res
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
+  store float 1.0, ptr %p, align 16
+  ret ptr %p
 }
 
-define float @align_ptrmask_forward_mask(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
-; CHECK-LABEL: define float @align_ptrmask_forward_mask(
-; CHECK-SAME: ptr nofree readonly align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+define ptr @align_ptrmask_forward_mask(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define align 8 ptr @align_ptrmask_forward_mask(
+; CHECK-SAME: ptr nofree readnone align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1:[0-9]+]] {
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
-; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2]]
-; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 -8
   %sel1 = select i1 %cmp2, i64 %sel, i64 -16
-  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
-  %res = load float, ptr %p, align 4
-  ret float %res
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
+  ret ptr %p
 }
 
-define float @align_ptrmask_forward_ptr(ptr align 16 %x, i1 %cmp1, i1 %cmp2) {
-; CHECK-LABEL: define float @align_ptrmask_forward_ptr(
-; CHECK-SAME: ptr nofree readonly align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+define ptr @align_ptrmask_forward_ptr(ptr align 16 %x, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define align 16 ptr @align_ptrmask_forward_ptr(
+; CHECK-SAME: ptr nofree readnone align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
-; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR2]]
-; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 16, !invariant.load [[META0]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 -8
   %sel1 = select i1 %cmp2, i64 %sel, i64 -16
-  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
-  %res = load float, ptr %p, align 4
-  ret float %res
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
+  ret ptr %p
 }
 
-define float @align_ptrmask_forward_nonconst_mask(ptr align 8 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
-; CHECK-LABEL: define float @align_ptrmask_forward_nonconst_mask(
-; CHECK-SAME: ptr nofree readonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+define ptr @align_ptrmask_forward_nonconst_mask(ptr align 8 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define align 8 ptr @align_ptrmask_forward_nonconst_mask(
+; CHECK-SAME: ptr nofree readnone align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 [[Y]]
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
-; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR2]]
-; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 %y
   %sel1 = select i1 %cmp2, i64 %sel, i64 -16
-  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
-  %res = load float, ptr %p, align 4
-  ret float %res
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
+  ret ptr %p
 }
 
-define float @align_ptrmask_back_nonconst_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
-; CHECK-LABEL: define float @align_ptrmask_back_nonconst_mask(
-; CHECK-SAME: ptr nofree readonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+define ptr @align_ptrmask_back_nonconst_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_nonconst_mask(
+; CHECK-SAME: ptr nofree writeonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 [[Y]]
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
-; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR2]]
-; CHECK-NEXT:    [[RES:%.*]] = load float, ptr [[P]], align 8, !invariant.load [[META0]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 %y
   %sel1 = select i1 %cmp2, i64 %sel, i64 -16
-  %p = tail call ptr @llvm.ptrmask(ptr %x, i64 %sel1)
-  %res = load float, ptr %p, align 8
-  ret float %res
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
+  store float 1.0, ptr %p, align 8
+  ret ptr %p
+}
+
+define ptr @align_ptrmask_back_const_back_noprop(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_const_back_noprop(
+; CHECK-SAME: ptr nofree writeonly align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR3]]
+; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
+; CHECK-NEXT:    ret ptr [[P]]
+;
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
+  store float 1.0, ptr %p, align 8
+  ret ptr %p
+}
+
+define ptr @align_ptrmask_back_const_back_prop(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_const_back_prop(
+; CHECK-SAME: ptr nofree writeonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -2) #[[ATTR3]]
+; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
+; CHECK-NEXT:    ret ptr [[P]]
+;
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -2)
+  store float 1.0, ptr %p, align 8
+  ret ptr %p
+}
+
+define ptr @align_ptrmask_back_const_forward_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define align 8 ptr @align_ptrmask_back_const_forward_mask(
+; CHECK-SAME: ptr nofree readnone align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR3]]
+; CHECK-NEXT:    ret ptr [[P]]
+;
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
+  ret ptr %p
+}
+
+define ptr @align_ptrmask_back_const_forward_ptr(ptr align 16 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
+; CHECK-LABEL: define align 16 ptr @align_ptrmask_back_const_forward_ptr(
+; CHECK-SAME: ptr nofree readnone align 16 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR3]]
+; CHECK-NEXT:    ret ptr [[P]]
+;
+  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
+  ret ptr %p
 }
-;.
-; CHECK: [[META0]] = !{}
-;.
diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py
index 143cc3817bd08..e24a4814ab64c 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -482,7 +482,7 @@ def have_cxx_shared_library():
         print("could not exec llvm-readobj")
         return False
 
-    readobj_out = readobj_cmd.stdout.read().decode("ascii")
+    readobj_out = readobj_cmd.stdout.read().decode("utf-8")
     readobj_cmd.wait()
 
     regex = re.compile(r"(libc\+\+|libstdc\+\+|msvcp).*\.(so|dylib|dll)")

>From 8091ffb5eda7572c9d914cbf8f86bdf9965e9969 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Mon, 28 Jul 2025 13:35:33 +0800
Subject: [PATCH 3/5] fix lit

---
 llvm/test/lit.cfg.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py
index e24a4814ab64c..143cc3817bd08 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -482,7 +482,7 @@ def have_cxx_shared_library():
         print("could not exec llvm-readobj")
         return False
 
-    readobj_out = readobj_cmd.stdout.read().decode("utf-8")
+    readobj_out = readobj_cmd.stdout.read().decode("ascii")
     readobj_cmd.wait()
 
     regex = re.compile(r"(libc\+\+|libstdc\+\+|msvcp).*\.(so|dylib|dll)")

>From 7b1abf243daceb3e73969f1ca6a375c0f96c1d32 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Mon, 28 Jul 2025 14:14:51 +0800
Subject: [PATCH 4/5] fix test cases

---
 llvm/lib/Transforms/IPO/AttributorAttributes.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index e1b634eb328a7..fb070c4dcf2dc 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -5256,6 +5256,7 @@ getAssumedAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
     if (Alignment != 0) {
       return Alignment;
     }
+    return QueryingAA.getAssumedAlign().value();
     break;
   }
   default:
@@ -5594,7 +5595,6 @@ struct AAAlignCallSiteReturned final
         return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
                                           : ChangeStatus::CHANGED;
       }
-      return ChangeStatus::UNCHANGED;
     }
     return Base::updateImpl(A);
   };

>From 258238f6905b696dd0dbc58de59dd219146b2fb6 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 29 Jul 2025 09:57:37 +0800
Subject: [PATCH 5/5] add test case not propagate extractelement

---
 .../Transforms/Attributor/align-ptrmask.ll    | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/llvm/test/Transforms/Attributor/align-ptrmask.ll b/llvm/test/Transforms/Attributor/align-ptrmask.ll
index 117e551f6ea47..2c41ef62e2a31 100644
--- a/llvm/test/Transforms/Attributor/align-ptrmask.ll
+++ b/llvm/test/Transforms/Attributor/align-ptrmask.ll
@@ -134,3 +134,23 @@ define ptr @align_ptrmask_back_const_forward_ptr(ptr align 16 %x, i64 %y, i1 %cm
   %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
   ret ptr %p
 }
+
+; FIXME: The store will create AAAlign for %ptr1,
+; but the attribute didn't propagate through extractelement, need propagate
+define <2 x ptr> @ptrmask_v2p0_v2i64(<2 x ptr> align 2 %ptr, i64 %a) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_v2p0_v2i64(
+; CHECK-SAME: <2 x ptr> align 2 [[PTR:%.*]], i64 [[A:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:    [[RESULT:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PTR]], <2 x i64> noundef splat (i64 -8)) #[[ATTR4]]
+; CHECK-NEXT:    [[PTR1:%.*]] = extractelement <2 x ptr> [[RESULT]], i32 0
+; CHECK-NEXT:    [[PTR2:%.*]] = extractelement <2 x ptr> [[RESULT]], i32 1
+; CHECK-NEXT:    store i64 [[A]], ptr [[PTR1]], align 16
+; CHECK-NEXT:    store i64 [[A]], ptr [[PTR2]], align 16
+; CHECK-NEXT:    ret <2 x ptr> [[RESULT]]
+;
+  %result = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %ptr, <2 x i64> splat(i64 -8))
+  %ptr1 = extractelement <2 x ptr> %result, i32 0
+  %ptr2 = extractelement <2 x ptr> %result, i32 1
+  store i64 %a, ptr %ptr1, align 16
+  store i64 %a, ptr %ptr2, align 16
+  ret <2 x ptr> %result
+}



More information about the llvm-commits mailing list