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

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 24 19:46:55 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] 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]] = !{}
+;.



More information about the llvm-commits mailing list