Skip to content

Commit

Permalink
Folding compares with unescaped allocations
Browse files Browse the repository at this point in the history
Summary:
If we know that the pointer allocated within a function does not escape,
we can fold away comparisons that are done with global pointers

Patch by Anna Thomas!

Reviewers: reames, majnemer, sanjoy

Subscribers: mgrang, mcrosier, majnemer, llvm-commits

Differential Revision: http://reviews.llvm.org/D19276

llvm-svn: 267035
  • Loading branch information
sanjoy committed Apr 21, 2016
1 parent 5de5910 commit a085cfc
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
15 changes: 14 additions & 1 deletion llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Expand Up @@ -1863,6 +1863,14 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) {
return nullptr;
}

static bool isNeverEqualToUnescapedAlloc(Value *V) {
if (isa<ConstantPointerNull>(V))
return true;
if (auto *LI = dyn_cast<LoadInst>(V))
return isa<GlobalVariable>(LI->getPointerOperand());
return false;
}

static bool
isAllocSiteRemovable(Instruction *AI, SmallVectorImpl<WeakVH> &Users,
const TargetLibraryInfo *TLI) {
Expand All @@ -1887,7 +1895,12 @@ isAllocSiteRemovable(Instruction *AI, SmallVectorImpl<WeakVH> &Users,
case Instruction::ICmp: {
ICmpInst *ICI = cast<ICmpInst>(I);
// We can fold eq/ne comparisons with null to false/true, respectively.
if (!ICI->isEquality() || !isa<ConstantPointerNull>(ICI->getOperand(1)))
// We fold comparisons in some conditions provided the alloc has not
// escaped.
if (!ICI->isEquality())
return false;
unsigned OtherIndex = (ICI->getOperand(0) == PI) ? 1 : 0;
if (!isNeverEqualToUnescapedAlloc(ICI->getOperand(OtherIndex)))
return false;
Users.emplace_back(I);
continue;
Expand Down
42 changes: 42 additions & 0 deletions llvm/test/Transforms/InstCombine/compare-unescaped.ll
@@ -0,0 +1,42 @@
; RUN: opt -instcombine -S < %s | FileCheck %s

@gp = global i32* null, align 8

declare i8* @malloc(i64) #1

define i1 @compare_global_trivialeq() {
%m = call i8* @malloc(i64 4)
%bc = bitcast i8* %m to i32*
%lgp = load i32*, i32** @gp, align 8
%cmp = icmp eq i32* %bc, %lgp
ret i1 %cmp
; CHECK-LABEL: compare_global_trivialeq
; CHECK: ret i1 false
}

define i1 @compare_global_trivialne() {
%m = call i8* @malloc(i64 4)
%bc = bitcast i8* %m to i32*
%lgp = load i32*, i32** @gp, align 8
%cmp = icmp ne i32* %bc, %lgp
ret i1 %cmp
; CHECK-LABEL: compare_global_trivialne
; CHECK: ret i1 true
}


; Although the %m is marked nocapture in the deopt operand in call to function f,
; we cannot remove the alloc site: call to malloc
; FIXME: The comparison should fold to false irrespective of whether the call to malloc can be elided or not
declare void @f()
define i32 @compare_and_call_with_deopt() {
; CHECK-LABEL: compare_and_call_with_deopt
%m = call i8* @malloc(i64 24)
%bc = bitcast i8* %m to i32*
%lgp = load i32*, i32** @gp, align 8
%cmp = icmp eq i32* %bc, %lgp
%rt = zext i1 %cmp to i32
tail call void @f() [ "deopt"(i8* %m) ]
ret i32 %rt
; CHECK: ret i32 %rt
}

0 comments on commit a085cfc

Please sign in to comment.