Skip to content

Commit 2502dc8

Browse files
committed
[InstCombine] Use CaptureTracking in foldAllocaCmp()
foldAllocaCmp() checks whether the alloca is not captured (ignoring the icmp). Replace the manual implementation of escape analysis with CaptureTracking. The primary practical difference is that CaptureTracking handles nocapture arguments, while foldAllocaCmp() was using a hardcoded list. This is basically just the CaptureTracking refactoring from D120371 without the other changes.
1 parent 4a87241 commit 2502dc8

File tree

2 files changed

+26
-61
lines changed

2 files changed

+26
-61
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/APSInt.h"
1515
#include "llvm/ADT/SetVector.h"
1616
#include "llvm/ADT/Statistic.h"
17+
#include "llvm/Analysis/CaptureTracking.h"
1718
#include "llvm/Analysis/CmpInstAnalysis.h"
1819
#include "llvm/Analysis/ConstantFolding.h"
1920
#include "llvm/Analysis/InstructionSimplify.h"
@@ -915,57 +916,27 @@ Instruction *InstCombinerImpl::foldAllocaCmp(ICmpInst &ICI,
915916
// comparisons against the alloca consistently, and avoids the risk of
916917
// erroneously folding a comparison of the pointer with itself.
917918

918-
unsigned MaxIter = 32; // Break cycles and bound to constant-time.
919+
struct CmpCaptureTracker : public CaptureTracker {
920+
bool Captured = false;
921+
unsigned NumCmps = 0;
919922

920-
SmallVector<const Use *, 32> Worklist;
921-
for (const Use &U : Alloca->uses()) {
922-
if (Worklist.size() >= MaxIter)
923-
return nullptr;
924-
Worklist.push_back(&U);
925-
}
926-
927-
unsigned NumCmps = 0;
928-
while (!Worklist.empty()) {
929-
assert(Worklist.size() <= MaxIter);
930-
const Use *U = Worklist.pop_back_val();
931-
const Value *V = U->getUser();
932-
--MaxIter;
923+
void tooManyUses() override { Captured = true; }
933924

934-
if (isa<BitCastInst>(V) || isa<GetElementPtrInst>(V) || isa<PHINode>(V) ||
935-
isa<SelectInst>(V)) {
936-
// Track the uses.
937-
} else if (isa<LoadInst>(V)) {
938-
// Loading from the pointer doesn't escape it.
939-
continue;
940-
} else if (const auto *SI = dyn_cast<StoreInst>(V)) {
941-
// Storing *to* the pointer is fine, but storing the pointer escapes it.
942-
if (SI->getValueOperand() == U->get())
943-
return nullptr;
944-
continue;
945-
} else if (isa<ICmpInst>(V)) {
946-
if (NumCmps++)
947-
return nullptr; // Found more than one cmp.
948-
continue;
949-
} else if (const auto *Intrin = dyn_cast<IntrinsicInst>(V)) {
950-
switch (Intrin->getIntrinsicID()) {
951-
// These intrinsics don't escape or compare the pointer. Memset is safe
952-
// because we don't allow ptrtoint. Memcpy and memmove are safe because
953-
// we don't allow stores, so src cannot point to V.
954-
case Intrinsic::lifetime_start: case Intrinsic::lifetime_end:
955-
case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset:
956-
continue;
957-
default:
958-
return nullptr;
925+
bool captured(const Use *U) override {
926+
if (isa<ICmpInst>(U->getUser()) && ++NumCmps == 1) {
927+
// Ignore one icmp capture.
928+
return false;
959929
}
960-
} else {
961-
return nullptr;
962-
}
963-
for (const Use &U : V->uses()) {
964-
if (Worklist.size() >= MaxIter)
965-
return nullptr;
966-
Worklist.push_back(&U);
930+
931+
Captured = true;
932+
return true;
967933
}
968-
}
934+
};
935+
936+
CmpCaptureTracker Tracker;
937+
PointerMayBeCaptured(Alloca, &Tracker);
938+
if (Tracker.Captured)
939+
return nullptr;
969940

970941
auto *Res = ConstantInt::get(ICI.getType(),
971942
!CmpInst::isTrueWhenEqual(ICI.getPredicate()));

llvm/test/Transforms/InstCombine/compare-alloca.ll

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,12 @@ define void @neg_consistent_fold2() {
193193
ret void
194194
}
195195

196-
define void @neg_consistent_fold3() {
197-
; CHECK-LABEL: @neg_consistent_fold3(
198-
; CHECK-NEXT: [[M1:%.*]] = alloca [4 x i8], align 1
199-
; CHECK-NEXT: [[LGP:%.*]] = load ptr, ptr @gp, align 8
196+
; FIXME: The end result is correct, but the fold happens for the wrong
197+
; reason (incorrect icmp GlobalValue special case in CaptureTracking).
198+
define void @consistent_fold3() {
199+
; CHECK-LABEL: @consistent_fold3(
200200
; CHECK-NEXT: [[RHS2:%.*]] = call ptr @hidden_inttoptr()
201-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[M1]], [[LGP]]
202-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr [[M1]], [[RHS2]]
203-
; CHECK-NEXT: call void @witness(i1 [[CMP1]], i1 [[CMP2]])
201+
; CHECK-NEXT: call void @witness(i1 false, i1 false)
204202
; CHECK-NEXT: ret void
205203
;
206204
%m = alloca i8, i32 4
@@ -231,13 +229,11 @@ define void @neg_consistent_fold4() {
231229

232230
declare void @unknown(ptr)
233231

234-
; TODO: Missing optimization
235232
define i1 @consistent_nocapture_inttoptr() {
236233
; CHECK-LABEL: @consistent_nocapture_inttoptr(
237234
; CHECK-NEXT: [[M1:%.*]] = alloca [4 x i8], align 1
238235
; CHECK-NEXT: call void @unknown(ptr nocapture nonnull [[M1]])
239-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[M1]], inttoptr (i64 2048 to ptr)
240-
; CHECK-NEXT: ret i1 [[CMP]]
236+
; CHECK-NEXT: ret i1 false
241237
;
242238
%m = alloca i8, i32 4
243239
call void @unknown(ptr nocapture %m)
@@ -261,14 +257,12 @@ define i1 @consistent_nocapture_offset() {
261257
}
262258

263259
@gp = global ptr null, align 8
264-
; TODO: Missing optimization
260+
265261
define i1 @consistent_nocapture_through_global() {
266262
; CHECK-LABEL: @consistent_nocapture_through_global(
267263
; CHECK-NEXT: [[M1:%.*]] = alloca [4 x i8], align 1
268264
; CHECK-NEXT: call void @unknown(ptr nocapture nonnull [[M1]])
269-
; CHECK-NEXT: [[LGP:%.*]] = load ptr, ptr @gp, align 8, !nonnull !0
270-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[M1]], [[LGP]]
271-
; CHECK-NEXT: ret i1 [[CMP]]
265+
; CHECK-NEXT: ret i1 false
272266
;
273267
%m = alloca i8, i32 4
274268
call void @unknown(ptr nocapture %m)

0 commit comments

Comments
 (0)