Skip to content

Commit e2af791

Browse files
[SCCP] Consider provenance when propagating constant ptrs
Similarly to what it is being already done in GVN (fb632ed), make sure pointers equalities derived via PredicatedInfo may be propagated, taking into account their provenance as well. Fixes: #159565.
1 parent eeca616 commit e2af791

File tree

5 files changed

+144
-6
lines changed

5 files changed

+144
-6
lines changed

llvm/include/llvm/Transforms/Utils/SCCPSolver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ class SCCPSolver {
218218
// old ValueLatticeElement::isOverdefined() and is intended to be used in the
219219
// transition to ValueLatticeElement.
220220
LLVM_ABI static bool isOverdefined(const ValueLatticeElement &LV);
221+
222+
// Helper to check whether \p V may be carrying a PredicateInfo derived copy
223+
// of a pointer.
224+
LLVM_ABI bool mayForwardPointerPredicatedCopy(Value *V);
221225
};
222226
} // namespace llvm
223227

llvm/lib/Analysis/Loads.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BatchAAResults &AA,
799799

800800
// Returns true if a use is either in an ICmp/PtrToInt or a Phi/Select that only
801801
// feeds into them.
802-
static bool isPointerUseReplacable(const Use &U) {
802+
static bool isPointerUseReplaceable(const Use &U) {
803803
unsigned Limit = 40;
804804
SmallVector<const User *> Worklist({U.getUser()});
805805
SmallPtrSet<const User *, 8> Visited;
@@ -847,7 +847,7 @@ bool llvm::canReplacePointersInUseIfEqual(const Use &U, const Value *To,
847847

848848
if (isPointerAlwaysReplaceable(&*U, To, DL))
849849
return true;
850-
return isPointerUseReplacable(U);
850+
return isPointerUseReplaceable(U);
851851
}
852852

853853
bool llvm::canReplacePointersIfEqual(const Value *From, const Value *To,

llvm/lib/Transforms/Utils/SCCPSolver.cpp

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/ADT/SetVector.h"
1717
#include "llvm/Analysis/ConstantFolding.h"
1818
#include "llvm/Analysis/InstructionSimplify.h"
19+
#include "llvm/Analysis/Loads.h"
1920
#include "llvm/Analysis/ValueLattice.h"
2021
#include "llvm/Analysis/ValueLatticeUtils.h"
2122
#include "llvm/Analysis/ValueTracking.h"
@@ -82,6 +83,24 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) {
8283
return false;
8384
}
8485

86+
// Perform constant pointer propagation as long as assuming PredicateInfo
87+
// derived equality between the two holds, and their provenance is the same.
88+
if (mayForwardPointerPredicatedCopy(V)) {
89+
bool MadeChange = false;
90+
const auto &DL = cast<Instruction>(V)->getDataLayout();
91+
92+
V->replaceUsesWithIf(Const, [&](Use &U) {
93+
bool CanReplace = canReplacePointersInUseIfEqual(U, Const, DL);
94+
if (CanReplace)
95+
LLVM_DEBUG(dbgs() << " Constant pointer: " << *Const << " = " << *V
96+
<< '\n');
97+
98+
MadeChange |= CanReplace;
99+
return CanReplace;
100+
});
101+
return MadeChange;
102+
}
103+
85104
LLVM_DEBUG(dbgs() << " Constant: " << *Const << " = " << *V << '\n');
86105

87106
// Replaces all of the uses of a variable with uses of the constant.
@@ -350,11 +369,12 @@ bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB,
350369
if (Inst.getType()->isVoidTy())
351370
continue;
352371
if (tryToReplaceWithConstant(&Inst)) {
353-
if (wouldInstructionBeTriviallyDead(&Inst))
372+
if (isInstructionTriviallyDead(&Inst)) {
354373
Inst.eraseFromParent();
374+
++InstRemovedStat;
375+
}
355376

356377
MadeChanges = true;
357-
++InstRemovedStat;
358378
} else if (replaceSignedInst(*this, InsertedValues, Inst)) {
359379
MadeChanges = true;
360380
++InstReplacedStat;
@@ -569,6 +589,9 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
569589
// The BasicBlock work list
570590
SmallVector<BasicBlock *, 64> BBWorkList;
571591

592+
/// List of users that carry forward the predicated copy.
593+
SmallPtrSet<Value *, 16> VisitedUsers;
594+
572595
/// KnownFeasibleEdges - Entries in this set are edges which have already had
573596
/// PHI nodes retriggered.
574597
using Edge = std::pair<BasicBlock *, BasicBlock *>;
@@ -1030,6 +1053,27 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
10301053
}
10311054
Invalidated.clear();
10321055
}
1056+
1057+
bool mayForwardPointerPredicatedCopy(Value *V) {
1058+
if (auto *I = dyn_cast<Instruction>(V); I && I->getType()->isPointerTy()) {
1059+
auto It = FnPredicateInfo.find(I->getFunction());
1060+
if (It == FnPredicateInfo.end())
1061+
return false;
1062+
if (It->second->getPredicateInfoFor(I))
1063+
return true;
1064+
// See whether there are intermediate copies of the predicated value.
1065+
// As per how the solver propagates constants, it should suffice to visit
1066+
// the operands of the currently examined instruction, adding it to the
1067+
// already visited users.
1068+
for (Value *Op : I->operand_values()) {
1069+
if (It->second->getPredicateInfoFor(Op) || VisitedUsers.count(Op)) {
1070+
VisitedUsers.insert(I);
1071+
return true;
1072+
}
1073+
}
1074+
}
1075+
return false;
1076+
}
10331077
};
10341078

10351079
} // namespace llvm
@@ -2379,3 +2423,7 @@ void SCCPSolver::markFunctionUnreachable(Function *F) {
23792423
void SCCPSolver::visit(Instruction *I) { Visitor->visit(I); }
23802424

23812425
void SCCPSolver::visitCall(CallInst &I) { Visitor->visitCall(I); }
2426+
2427+
bool SCCPSolver::mayForwardPointerPredicatedCopy(Value *V) {
2428+
return Visitor->mayForwardPointerPredicatedCopy(V);
2429+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
2+
; RUN: opt < %s -passes=ipsccp -S | FileCheck %s
3+
4+
define ptr @assume_pointers_equality_maybe_different_provenance_1(ptr %x) {
5+
; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_1(
6+
; CHECK-SAME: ptr [[X:%.*]]) {
7+
; CHECK-NEXT: [[ENTRY:.*:]]
8+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
9+
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
10+
; CHECK-NEXT: ret ptr [[X]]
11+
;
12+
entry:
13+
%cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
14+
call void @llvm.assume(i1 %cmp)
15+
ret ptr %x
16+
}
17+
18+
define ptr @assume_pointers_equality_maybe_different_provenance_2(ptr %x, i1 %cond) {
19+
; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_2(
20+
; CHECK-SAME: ptr [[X:%.*]], i1 [[COND:%.*]]) {
21+
; CHECK-NEXT: [[ENTRY:.*]]:
22+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
23+
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
24+
; CHECK-NEXT: br i1 [[COND]], label %[[NEXT:.*]], label %[[EXIT:.*]]
25+
; CHECK: [[NEXT]]:
26+
; CHECK-NEXT: br label %[[EXIT]]
27+
; CHECK: [[EXIT]]:
28+
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[X]], %[[ENTRY]] ], [ inttoptr (i64 12345678 to ptr), %[[NEXT]] ]
29+
; CHECK-NEXT: ret ptr [[PHI]]
30+
;
31+
entry:
32+
%cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
33+
call void @llvm.assume(i1 %cmp)
34+
br i1 %cond, label %next, label %exit
35+
36+
next:
37+
br label %exit
38+
39+
exit:
40+
%phi = phi ptr [ %x, %entry ], [ inttoptr (i64 12345678 to ptr), %next ]
41+
ret ptr %phi
42+
}
43+
44+
define internal ptr @callee(ptr returned %p) memory(none) {
45+
; CHECK-LABEL: define internal ptr @callee(
46+
; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0:[0-9]+]] {
47+
; CHECK-NEXT: [[ENTRY:.*:]]
48+
; CHECK-NEXT: ret ptr poison
49+
;
50+
entry:
51+
ret ptr %p
52+
}
53+
54+
define ptr @assume_pointers_equality_maybe_different_provenance_3(ptr %x, i1 %cond) {
55+
; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_3(
56+
; CHECK-SAME: ptr [[X:%.*]], i1 [[COND:%.*]]) {
57+
; CHECK-NEXT: [[ENTRY:.*]]:
58+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
59+
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
60+
; CHECK-NEXT: br i1 [[COND]], label %[[NEXT:.*]], label %[[EXIT:.*]]
61+
; CHECK: [[NEXT]]:
62+
; CHECK-NEXT: [[SEL:%.*]] = select i1 true, ptr [[X]], ptr inttoptr (i64 12345678 to ptr)
63+
; CHECK-NEXT: br label %[[EXIT]]
64+
; CHECK: [[EXIT]]:
65+
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[X]], %[[ENTRY]] ], [ [[SEL]], %[[NEXT]] ]
66+
; CHECK-NEXT: [[Q:%.*]] = call ptr @callee(ptr [[PHI]])
67+
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND]], ptr [[Q]], ptr [[X]]
68+
; CHECK-NEXT: ret ptr [[SEL2]]
69+
;
70+
entry:
71+
%cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
72+
call void @llvm.assume(i1 %cmp)
73+
br i1 %cond, label %next, label %exit
74+
75+
next:
76+
%sel = select i1 %cond, ptr %x, ptr inttoptr (i64 12345678 to ptr)
77+
br label %exit
78+
79+
exit:
80+
%phi = phi ptr [ %x, %entry ], [ %sel, %next ]
81+
%q = call ptr @callee(ptr %phi)
82+
%sel2 = select i1 %cond, ptr %q, ptr %x
83+
ret ptr %sel2
84+
}
85+
86+
declare void @llvm.assume(i1)

llvm/test/Transforms/SCCP/replace-dereferenceable-ptr-with-undereferenceable.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ define i32 @eq_undereferenceable(ptr %p) {
1111
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P:%.*]], getelementptr inbounds (i32, ptr @x, i64 1)
1212
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
1313
; CHECK: if.then:
14-
; CHECK-NEXT: store i32 2, ptr getelementptr inbounds (i32, ptr @x, i64 1), align 4
14+
; CHECK-NEXT: store i32 2, ptr [[P]], align 4
1515
; CHECK-NEXT: br label [[IF_END]]
1616
; CHECK: if.end:
1717
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @y, align 4
@@ -65,7 +65,7 @@ define i1 @eq_undereferenceable_cmp_simp(ptr %p) {
6565
; CHECK-NEXT: [[CMP_0:%.*]] = icmp eq ptr [[P:%.*]], getelementptr inbounds (i32, ptr @x, i64 1)
6666
; CHECK-NEXT: br i1 [[CMP_0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
6767
; CHECK: if.then:
68-
; CHECK-NEXT: store i32 2, ptr getelementptr inbounds (i32, ptr @x, i64 1), align 4
68+
; CHECK-NEXT: store i32 2, ptr [[P]], align 4
6969
; CHECK-NEXT: ret i1 true
7070
; CHECK: if.end:
7171
; CHECK-NEXT: ret i1 false

0 commit comments

Comments
 (0)