[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