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

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 31 23:59:48 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/8] 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/8] 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/8] 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/8] 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/8] 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
+}

>From 88789839f1c92f56a9ca993adb186f093889a747 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 29 Jul 2025 10:40:01 +0800
Subject: [PATCH 6/8] fix test case

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

diff --git a/llvm/test/Transforms/Attributor/align-ptrmask.ll b/llvm/test/Transforms/Attributor/align-ptrmask.ll
index 2c41ef62e2a31..defe3e3374b78 100644
--- a/llvm/test/Transforms/Attributor/align-ptrmask.ll
+++ b/llvm/test/Transforms/Attributor/align-ptrmask.ll
@@ -6,7 +6,7 @@ define ptr @align_ptrmask_back_no_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
 ; 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 noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4:[0-9]+]]
 ; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
@@ -22,7 +22,7 @@ define ptr @align_ptrmask_back_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
 ; 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 noundef nonnull align 16 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 16 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4]]
 ; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 16
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
@@ -38,7 +38,7 @@ define ptr @align_ptrmask_forward_mask(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
 ; 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]]) #[[ATTR3]]
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4]]
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 -8
@@ -52,7 +52,7 @@ define ptr @align_ptrmask_forward_ptr(ptr align 16 %x, i1 %cmp1, i1 %cmp2) {
 ; 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]]) #[[ATTR3]]
+; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4]]
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 -8
@@ -66,7 +66,7 @@ define ptr @align_ptrmask_forward_nonconst_mask(ptr align 8 %x, i64 %y, i1 %cmp1
 ; 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]]) #[[ATTR3]]
+; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR4]]
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
   %sel = select i1 %cmp1, i64 -32, i64 %y
@@ -80,7 +80,7 @@ define ptr @align_ptrmask_back_nonconst_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i
 ; 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 noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR3]]
+; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR4]]
 ; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
@@ -94,7 +94,7 @@ define ptr @align_ptrmask_back_nonconst_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i
 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:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR4]]
 ; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
@@ -106,7 +106,7 @@ define ptr @align_ptrmask_back_const_back_noprop(ptr align 4 %x, i64 %y, i1 %cmp
 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:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -2) #[[ATTR4]]
 ; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
@@ -118,7 +118,7 @@ define ptr @align_ptrmask_back_const_back_prop(ptr align 4 %x, i64 %y, i1 %cmp1,
 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:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR4]]
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
   %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
@@ -128,7 +128,7 @@ define ptr @align_ptrmask_back_const_forward_mask(ptr align 4 %x, i64 %y, i1 %cm
 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:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR4]]
 ; CHECK-NEXT:    ret ptr [[P]]
 ;
   %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)

>From ebbfc0b67720923f4b6a082ae22531b34eb2260c Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 31 Jul 2025 08:58:06 +0800
Subject: [PATCH 7/8] fix comments

---
 .../Transforms/IPO/AttributorAttributes.cpp   | 52 +++++++++----------
 1 file changed, 24 insertions(+), 28 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index fb070c4dcf2dc..24460b4db076d 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -5189,14 +5189,14 @@ struct AADereferenceableCallSiteReturned final
 
 namespace {
 
-static std::optional<uint64_t>
-getKnownAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
-                          const IntrinsicInst *II) {
+static std::optional<Align> getKnownAlignForIntrinsic(Attributor &A,
+                                                      AAAlign &QueryingAA,
+                                                      const IntrinsicInst *II) {
   switch (II->getIntrinsicID()) {
   case Intrinsic::ptrmask: {
-    auto *ConstVals = A.getAAFor<AAPotentialConstantValues>(
+    const auto *ConstVals = A.getAAFor<AAPotentialConstantValues>(
         QueryingAA, IRPosition::value(*(II->getOperand(1))), DepClassTy::NONE);
-    const AAAlign *AlignAA = A.getAAFor<AAAlign>(
+    const auto *AlignAA = A.getAAFor<AAAlign>(
         QueryingAA, IRPosition::value(*(II)), DepClassTy::NONE);
     if (ConstVals && ConstVals->isValidState()) {
       if (ConstVals->isAtFixpoint()) {
@@ -5204,19 +5204,19 @@ getKnownAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
         unsigned Size =
             DL.getPointerTypeSizeInBits(II->getOperand(0)->getType());
         uint64_t TrailingZeros = Size;
-        for (const auto &It : ConstVals->getAssumedSet())
+        for (const APInt &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 Align(1);
           }
         }
-        return AlignAA->getKnownAlign().value();
+        return AlignAA->getKnownAlign();
       }
     } else if (AlignAA) {
-      return AlignAA->getKnownAlign().value();
+      return AlignAA->getKnownAlign();
     }
     break;
   }
@@ -5226,16 +5226,15 @@ getKnownAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
   return std::nullopt;
 }
 
-static std::optional<uint64_t>
+static std::optional<Align>
 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 =
+    const auto *ConstVals = A.getAAFor<AAPotentialConstantValues>(
+        QueryingAA, IRPosition::value(*(II->getOperand(1))),
+        DepClassTy::REQUIRED);
+    const auto *AlignAA =
         A.getAAFor<AAAlign>(QueryingAA, IRPosition::value(*(II->getOperand(0))),
                             DepClassTy::REQUIRED);
     uint64_t Alignment = 0;
@@ -5243,7 +5242,7 @@ getAssumedAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
       const DataLayout &DL = A.getDataLayout();
       unsigned Size = DL.getPointerTypeSizeInBits(II->getOperand(0)->getType());
       unsigned TrailingZeros = Size;
-      for (const auto &It : ConstVals->getAssumedSet())
+      for (const APInt &It : ConstVals->getAssumedSet())
         if (It.countTrailingZeros() < TrailingZeros)
           TrailingZeros = It.countTrailingZeros();
       if (TrailingZeros < Size)
@@ -5253,11 +5252,9 @@ getAssumedAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
         Alignment < AlignAA->getAssumedAlign().value())
       Alignment = AlignAA->getAssumedAlign().value();
 
-    if (Alignment != 0) {
-      return Alignment;
-    }
-    return QueryingAA.getAssumedAlign().value();
-    break;
+    if (Alignment != 0)
+      return Align(Alignment);
+    return QueryingAA.getAssumedAlign();
   }
   default:
     break;
@@ -5280,11 +5277,10 @@ static unsigned getKnownAlignForUse(Attributor &A, AAAlign &QueryingAA,
       TrackUse = true;
     return 0;
   }
-  if (auto *II = dyn_cast<IntrinsicInst>(I)) {
-    std::optional<uint64_t> Align =
-        getKnownAlignForIntrinsic(A, QueryingAA, II);
+  if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
+    std::optional<Align> Align = getKnownAlignForIntrinsic(A, QueryingAA, II);
     if (Align.has_value())
-      return Align.value();
+      return Align.value().value();
   }
 
   MaybeAlign MA;
@@ -5587,11 +5583,11 @@ struct AAAlignCallSiteReturned final
 
   ChangeStatus updateImpl(Attributor &A) override {
     Instruction *I = getIRPosition().getCtxI();
-    if (auto *II = dyn_cast<IntrinsicInst>(I)) {
-      std::optional<uint64_t> Align = getAssumedAlignForIntrinsic(A, *this, II);
+    if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
+      std::optional<Align> Align = getAssumedAlignForIntrinsic(A, *this, II);
       if (Align.has_value()) {
         uint64_t OldAssumed = getAssumed();
-        takeAssumedMinimum(Align.value());
+        takeAssumedMinimum(Align.value().value());
         return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
                                           : ChangeStatus::CHANGED;
       }

>From 47dc43473f90704ff331b8eb3b36df93d0f69237 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Fri, 1 Aug 2025 14:59:29 +0800
Subject: [PATCH 8/8] fix matthew's comments

---
 .../Transforms/IPO/AttributorAttributes.cpp   | 33 ++++++++++---------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 24460b4db076d..0b4e0b0ad1fc8 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -5203,16 +5203,16 @@ static std::optional<Align> getKnownAlignForIntrinsic(Attributor &A,
         const DataLayout &DL = A.getDataLayout();
         unsigned Size =
             DL.getPointerTypeSizeInBits(II->getOperand(0)->getType());
-        uint64_t TrailingZeros = Size;
+        uint64_t TrailingZeros = Size - 1;
         for (const APInt &It : ConstVals->getAssumedSet())
           if (It.countTrailingZeros() < TrailingZeros)
             TrailingZeros = It.countTrailingZeros();
-        if (TrailingZeros < Size) {
-          uint64_t Mask = 1 << TrailingZeros;
-          if (Mask >= AlignAA->getKnownAlign().value()) {
-            return Align(1);
-          }
-        }
+
+        APInt Mask = APInt(Size, 1).shl(TrailingZeros);
+        APInt PtrAlign = APInt(Size, 1).shl(Log2(AlignAA->getKnownAlign()));
+        if (Mask.uge(PtrAlign))
+          return Align(1);
+
         return AlignAA->getKnownAlign();
       }
     } else if (AlignAA) {
@@ -5237,22 +5237,25 @@ getAssumedAlignForIntrinsic(Attributor &A, AAAlign &QueryingAA,
     const auto *AlignAA =
         A.getAAFor<AAAlign>(QueryingAA, IRPosition::value(*(II->getOperand(0))),
                             DepClassTy::REQUIRED);
-    uint64_t Alignment = 0;
+    Align Alignment;
+    bool NeedRet = false;
     if (ConstVals && ConstVals->isValidState()) {
       const DataLayout &DL = A.getDataLayout();
       unsigned Size = DL.getPointerTypeSizeInBits(II->getOperand(0)->getType());
-      unsigned TrailingZeros = Size;
+      unsigned TrailingZeros = Size - 1;
       for (const APInt &It : ConstVals->getAssumedSet())
         if (It.countTrailingZeros() < TrailingZeros)
           TrailingZeros = It.countTrailingZeros();
-      if (TrailingZeros < Size)
-        Alignment = 1 << TrailingZeros;
+      Alignment = Align(1 << TrailingZeros);
+      NeedRet = true;
+    }
+    if (AlignAA && AlignAA->isValidState()) {
+      NeedRet = true;
+      if (Alignment < AlignAA->getAssumedAlign())
+        Alignment = AlignAA->getAssumedAlign();
     }
-    if (AlignAA && AlignAA->isValidState() &&
-        Alignment < AlignAA->getAssumedAlign().value())
-      Alignment = AlignAA->getAssumedAlign().value();
 
-    if (Alignment != 0)
+    if (NeedRet)
       return Align(Alignment);
     return QueryingAA.getAssumedAlign();
   }



More information about the llvm-commits mailing list