Reapply "[SCEVExp] Use SCEVPtrToAddr in tryToReuseLCSSAPhi if possible. (#180257)"

This reverts commit cb905605b2.

Recommit the patch with a small change to check the destination
type matches the address type, to avoid a crash on mismatch.

Original message:

This patch updates tryToReuseLCSSAPhi to use SCEVPtrToAddr, unless using
SCEVPtrToInt allows re-use, because the IR already contains a re-usable
phi using PtrToInt.

This is a first step towards migrating to SCEVPtrToAddr and avoids
regressions in follow-up changes.

PR: https://github.com/llvm/llvm-project/pull/178727
This commit is contained in:
Florian Hahn
2026-02-06 21:14:33 +00:00
parent 5f644d966e
commit bd40d1de9c
4 changed files with 106 additions and 21 deletions

View File

@@ -186,6 +186,12 @@ m_scev_PtrToInt(const Op0_t &Op0) {
return SCEVUnaryExpr_match<SCEVPtrToIntExpr, Op0_t>(Op0);
}
template <typename Op0_t>
inline SCEVUnaryExpr_match<SCEVPtrToAddrExpr, Op0_t>
m_scev_PtrToAddr(const Op0_t &Op0) {
return SCEVUnaryExpr_match<SCEVPtrToAddrExpr, Op0_t>(Op0);
}
template <typename Op0_t>
inline SCEVUnaryExpr_match<SCEVTruncateExpr, Op0_t>
m_scev_Trunc(const Op0_t &Op0) {

View File

@@ -1254,6 +1254,22 @@ Value *SCEVExpander::tryToReuseLCSSAPhi(const SCEVAddRecExpr *S) {
!SE.DT.dominates(EB, Builder.GetInsertBlock()))
return nullptr;
// Helper to check if the diff between S and ExitSCEV is simple enough to
// allow reusing the LCSSA phi.
auto CanReuse = [&](const SCEV *ExitSCEV) -> const SCEV * {
if (isa<SCEVCouldNotCompute>(ExitSCEV))
return nullptr;
const SCEV *Diff = SE.getMinusSCEV(S, ExitSCEV);
const SCEV *Op = Diff;
match(Op, m_scev_Add(m_SCEVConstant(), m_SCEV(Op)));
match(Op, m_scev_Mul(m_scev_AllOnes(), m_SCEV(Op)));
match(Op, m_scev_PtrToAddr(m_SCEV(Op))) ||
match(Op, m_scev_PtrToInt(m_SCEV(Op)));
if (!isa<SCEVConstant, SCEVUnknown>(Op))
return nullptr;
return Diff;
};
for (auto &PN : EB->phis()) {
if (!SE.isSCEVable(PN.getType()))
continue;
@@ -1261,22 +1277,20 @@ Value *SCEVExpander::tryToReuseLCSSAPhi(const SCEVAddRecExpr *S) {
if (!isa<SCEVAddRecExpr>(ExitSCEV))
continue;
Type *PhiTy = PN.getType();
if (STy->isIntegerTy() && PhiTy->isPointerTy()) {
ExitSCEV = SE.getPtrToIntExpr(ExitSCEV, STy);
if (isa<SCEVCouldNotCompute>(ExitSCEV))
continue;
} else if (S->getType() != PN.getType()) {
continue;
const SCEV *Diff = nullptr;
if (STy->isIntegerTy() && PhiTy->isPointerTy() &&
DL.getAddressType(PhiTy) == STy) {
// Prefer ptrtoaddr over ptrtoint.
const SCEV *AddrSCEV = SE.getPtrToAddrExpr(ExitSCEV);
Diff = CanReuse(AddrSCEV);
if (!Diff) {
const SCEV *IntSCEV = SE.getPtrToIntExpr(ExitSCEV, STy);
Diff = CanReuse(IntSCEV);
}
} else if (STy == PhiTy) {
Diff = CanReuse(ExitSCEV);
}
// Check if we can re-use the existing PN, by adjusting it with an expanded
// offset, if the offset is simpler.
const SCEV *Diff = SE.getMinusSCEV(S, ExitSCEV);
const SCEV *Op = Diff;
match(Op, m_scev_Add(m_SCEVConstant(), m_SCEV(Op)));
match(Op, m_scev_Mul(m_scev_AllOnes(), m_SCEV(Op)));
match(Op, m_scev_PtrToInt(m_SCEV(Op)));
if (!isa<SCEVConstant, SCEVUnknown>(Op))
if (!Diff)
continue;
assert(Diff->getType()->isIntegerTy() &&
@@ -1286,7 +1300,7 @@ Value *SCEVExpander::tryToReuseLCSSAPhi(const SCEVAddRecExpr *S) {
if (PhiTy->isPointerTy()) {
if (STy->isPointerTy())
return Builder.CreatePtrAdd(BaseV, DiffV);
BaseV = Builder.CreatePtrToInt(BaseV, DiffV->getType());
BaseV = Builder.CreatePtrToAddr(BaseV);
}
return Builder.CreateAdd(BaseV, DiffV);
}

View File

@@ -10,7 +10,7 @@ define void @scev_expand_ptrtoint(i8 %x, ptr %start) {
; CHECK-LABEL: define void @scev_expand_ptrtoint(
; CHECK-SAME: i8 [[X:%.*]], ptr [[START:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[START1:%.*]] = ptrtoint ptr [[START]] to i64
; CHECK-NEXT: [[START1:%.*]] = ptrtoaddr ptr [[START]] to i64
; CHECK-NEXT: br label %[[LOOP_1_HEADER:.*]]
; CHECK: [[LOOP_1_HEADER]]:
; CHECK-NEXT: [[PTR_IV_1:%.*]] = phi ptr [ [[START]], %[[ENTRY]] ], [ [[PTR_IV_1_NEXT:%.*]], %[[LOOP_1_LATCH:.*]] ]
@@ -36,7 +36,7 @@ define void @scev_expand_ptrtoint(i8 %x, ptr %start) {
; CHECK-NEXT: [[INDVAR_LCSSA:%.*]] = phi i64 [ [[INDVAR]], %[[LOOP_2_HEADER]] ], [ [[INDVAR]], %[[LOOP_2_HEADER]] ]
; CHECK-NEXT: [[PTR_IV_2_LCSSA:%.*]] = phi ptr [ [[PTR_IV_2]], %[[LOOP_2_HEADER]] ], [ [[PTR_IV_2]], %[[LOOP_2_HEADER]] ]
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 1, [[START1]]
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR_IV_1_LCSSA]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR_IV_1_LCSSA]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[TMP0]]
; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[CMP_EXT]], [[TMP2]]
; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[INDVAR_LCSSA]], [[TMP4]]
@@ -222,3 +222,68 @@ loop.2.latch:
exit:
ret void
}
define void @expand_truncated_ptrtoint(ptr %A, ptr %B) {
; CHECK-LABEL: define void @expand_truncated_ptrtoint(
; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[A1:%.*]] = ptrtoint ptr [[A]] to i64
; CHECK-NEXT: br label %[[LOOP_1:.*]]
; CHECK: [[LOOP_1]]:
; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ [[INDVAR_NEXT:%.*]], %[[LOOP_1]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[P_0:%.*]] = phi ptr [ [[A]], %[[ENTRY]] ], [ [[P_0_NEXT:%.*]], %[[LOOP_1]] ]
; CHECK-NEXT: [[P_0_NEXT]] = getelementptr i8, ptr [[P_0]], i64 -1
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
; CHECK-NEXT: br i1 false, label %[[MIDDLE:.*]], label %[[LOOP_1]]
; CHECK: [[MIDDLE]]:
; CHECK-NEXT: [[INDVAR_LCSSA:%.*]] = phi i32 [ [[INDVAR]], %[[LOOP_1]] ]
; CHECK-NEXT: [[P_0_LCSSA:%.*]] = phi ptr [ [[P_0]], %[[LOOP_1]] ]
; CHECK-NEXT: [[P_0_TO_INT:%.*]] = ptrtoint ptr [[P_0_LCSSA]] to i64
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[P_0_TO_INT]] to i32
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[TRUNC]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i64 [[TMP0]], -1
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[B]], i64 [[TMP1]]
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[A1]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], 1
; CHECK-NEXT: [[TMP6:%.*]] = mul i32 [[INDVAR_LCSSA]], -1
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP6]], [[TMP3]]
; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[TMP5]] to i64
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[SCEVGEP]], i8 0, i64 [[TMP4]], i1 false)
; CHECK-NEXT: br label %[[LOOP_2:.*]]
; CHECK: [[LOOP_2]]:
; CHECK-NEXT: [[P_1:%.*]] = phi ptr [ [[B]], %[[MIDDLE]] ], [ [[P_1_NEXT:%.*]], %[[LOOP_2]] ]
; CHECK-NEXT: [[P_2:%.*]] = phi i32 [ [[TRUNC]], %[[MIDDLE]] ], [ [[P_2_NEXT:%.*]], %[[LOOP_2]] ]
; CHECK-NEXT: [[P_1_NEXT]] = getelementptr i8, ptr [[P_1]], i64 -1
; CHECK-NEXT: [[P_2_NEXT]] = add i32 [[P_2]], -1
; CHECK-NEXT: [[EC:%.*]] = icmp sgt i32 [[P_2]], 0
; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_2]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop.1
loop.1:
%p.0 = phi ptr [ %A, %entry ], [ %p.0.next, %loop.1 ]
%p.0.next = getelementptr i8, ptr %p.0, i64 -1
call void @foo()
br i1 false, label %middle, label %loop.1
middle:
%p.0.to.int = ptrtoint ptr %p.0 to i64
%trunc = trunc i64 %p.0.to.int to i32
br label %loop.2
loop.2:
%p.1 = phi ptr [ %B, %middle ], [ %p.1.next, %loop.2 ]
%p.2 = phi i32 [ %trunc, %middle ], [ %p.2.next, %loop.2 ]
%p.1.next = getelementptr i8, ptr %p.1, i64 -1
store i8 0, ptr %p.1, align 1
%p.2.next = add i32 %p.2, -1
%ec = icmp sgt i32 %p.2, 0
br i1 %ec, label %loop.2, label %exit
exit:
ret void
}

View File

@@ -118,7 +118,7 @@ define void @runtime_checks_ptr_inductions(ptr %dst.1, ptr %dst.2, i1 %c) {
; CHECK-NEXT: [[SEL_DST_LCSSA:%.*]] = phi ptr [ [[SEL_DST]], %[[LOOP_1]] ]
; CHECK-NEXT: br label %[[VECTOR_MEMCHECK:.*]]
; CHECK: [[VECTOR_MEMCHECK]]:
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[PTR_IV_1_LCSSA]] to i64
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoaddr ptr [[PTR_IV_1_LCSSA]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[TMP0]], [[SEL_DST_LCSSA12]]
; CHECK-NEXT: [[DIFF_CHECK:%.*]] = icmp ult i64 [[TMP1]], 2
; CHECK-NEXT: br i1 [[DIFF_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
@@ -308,7 +308,7 @@ define void @expand_diff_neg_ptrtoint_expr(ptr %src, ptr %start) {
; CHECK-NEXT: br label %[[VECTOR_MEMCHECK:.*]]
; CHECK: [[VECTOR_MEMCHECK]]:
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 0, [[SRC2]]
; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[TMP1]] to i64
; CHECK-NEXT: [[TMP5:%.*]] = ptrtoaddr ptr [[TMP1]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP5]], [[TMP0]]
; CHECK-NEXT: [[DIFF_CHECK:%.*]] = icmp ult i64 [[TMP2]], 16
; CHECK-NEXT: br i1 [[DIFF_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
@@ -403,7 +403,7 @@ define void @scev_exp_reuse_const_add(ptr %dst, ptr %src) {
; CHECK-NEXT: br label %[[VECTOR_MEMCHECK:.*]]
; CHECK: [[VECTOR_MEMCHECK]]:
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 -2, [[SRC2]]
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR_IV_1_NEXT_LCSSA]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR_IV_1_NEXT_LCSSA]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[TMP0]]
; CHECK-NEXT: [[DIFF_CHECK:%.*]] = icmp ult i64 [[TMP2]], 4
; CHECK-NEXT: br i1 [[DIFF_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]