Skip to content

Commit

Permalink
Improve what can be promoted in LICM.
Browse files Browse the repository at this point in the history
Summary:
In case of non-alloca pointers, we check for whether it is a pointer
from malloc-like calls and it is not captured. In such case, we can
promote the pointer, as the caller will have no way to access this pointer
even if there is unwinding in middle of the loop.

Reviewers: hfinkel, sanjoy, reames, eli.friedman

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D28834

llvm-svn: 292510
  • Loading branch information
trentxintong committed Jan 19, 2017
1 parent 6e47a10 commit 5ee40ba
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 9 deletions.
37 changes: 31 additions & 6 deletions llvm/lib/Transforms/Scalar/LICM.cpp
Expand Up @@ -999,14 +999,34 @@ bool llvm::promoteLoopAccessesToScalars(

const DataLayout &MDL = Preheader->getModule()->getDataLayout();

// Do we know this object does not escape ?
bool IsKnownNonEscapingObject = false;
if (SafetyInfo->MayThrow) {
// If a loop can throw, we have to insert a store along each unwind edge.
// That said, we can't actually make the unwind edge explicit. Therefore,
// we have to prove that the store is dead along the unwind edge.
//
// Currently, this code just special-cases alloca instructions.
if (!isa<AllocaInst>(GetUnderlyingObject(SomePtr, MDL)))
return false;
// If the underlying object is not an alloca, nor a pointer that does not
// escape, then we can not effectively prove that the store is dead along
// the unwind edge. i.e. the caller of this function could have ways to
// access the pointed object.
Value *Object = GetUnderlyingObject(SomePtr, MDL);
// If this is a base pointer we do not understand, simply bail.
// We only handle alloca and return value from alloc-like fn right now.
if (!isa<AllocaInst>(Object)) {
if (!isAllocLikeFn(Object, TLI))
return false;
// If this is an alloc like fn. There are more constraints we need to verify.
// More specifically, we must make sure that the pointer can not escape.
//
// NOTE: PointerMayBeCaptured is not enough as the pointer may have escaped
// even though its not captured by the enclosing function. Standard allocation
// functions like malloc, calloc, and operator new return values which can
// be assumed not to have previously escaped.
if (PointerMayBeCaptured(Object, true, true))
return false;
IsKnownNonEscapingObject = true;
}
}

// Check that all of the pointers in the alias set have the same type. We
Expand Down Expand Up @@ -1109,10 +1129,15 @@ bool llvm::promoteLoopAccessesToScalars(
// stores along paths which originally didn't have them without violating the
// memory model.
if (!SafeToInsertStore) {
Value *Object = GetUnderlyingObject(SomePtr, MDL);
SafeToInsertStore =
(isAllocLikeFn(Object, TLI) || isa<AllocaInst>(Object)) &&
// If this is a known non-escaping object, it is safe to insert the stores.
if (IsKnownNonEscapingObject)
SafeToInsertStore = true;
else {
Value *Object = GetUnderlyingObject(SomePtr, MDL);
SafeToInsertStore =
(isAllocLikeFn(Object, TLI) || isa<AllocaInst>(Object)) &&
!PointerMayBeCaptured(Object, true, true);
}
}

// If we've still failed to prove we can sink the store, give up.
Expand Down
121 changes: 118 additions & 3 deletions llvm/test/Transforms/LICM/scalar-promote-unwind.ll
Expand Up @@ -135,14 +135,129 @@ eh.resume:
resume { i8*, i32 } %lpad.val3
}

declare void @boo()

declare i32 @__gxx_personality_v0(...)
; The malloc'ed memory is not capture and therefore promoted.
define void @malloc_no_capture() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
%call = call i8* @malloc(i64 4)
%0 = bitcast i8* %call to i32*
br label %for.body

declare i32 @llvm.eh.typeid.for(i8*)
; CHECK: for.body:
; CHECK-NOT: load
; CHECK-NOT: store
; CHECK: br
for.body:
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.latch ]
%1 = load i32, i32* %0, align 4
%add = add nsw i32 %1, 1
store i32 %add, i32* %0, align 4
br label %for.call

for.call:
invoke void @boo()
to label %invoke.cont unwind label %lpad

invoke.cont:
br label %for.latch

for.latch:
%inc = add i32 %i.0, 1
%cmp = icmp slt i32 %i.0, 1024
br i1 %cmp, label %for.body, label %for.end

for.end:
br label %fun.ret

lpad:
%2 = landingpad { i8*, i32 }
catch i8* null
%3 = extractvalue { i8*, i32 } %2, 0
%4 = extractvalue { i8*, i32 } %2, 1
br label %catch

catch:
%5 = call i8* @__cxa_begin_catch(i8* %3) #4
%6 = bitcast i32* %0 to i8*
call void @free(i8* %6)
call void @__cxa_end_catch()
br label %fun.ret

fun.ret:
ret void
}

; The malloc'ed memory can be captured and therefore not promoted.
define void @malloc_capture(i32** noalias %A) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
%call = call i8* @malloc(i64 4)
%0 = bitcast i8* %call to i32*
br label %for.body

; CHECK: for.body:
; CHECK: load
; CHECK: store
; CHECK: br
for.body:
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.latch ]
%1 = load i32, i32* %0, align 4
%add = add nsw i32 %1, 1
store i32 %add, i32* %0, align 4
br label %for.call

for.call:
invoke void @boo_readnone()
to label %invoke.cont unwind label %lpad

invoke.cont:
br label %for.latch

for.latch:
store i32* %0, i32** %A
%inc = add i32 %i.0, 1
%cmp = icmp slt i32 %i.0, 1024
br i1 %cmp, label %for.body, label %for.end

for.end:
br label %fun.ret

lpad:
%2 = landingpad { i8*, i32 }
catch i8* null
%3 = extractvalue { i8*, i32 } %2, 0
%4 = extractvalue { i8*, i32 } %2, 1
br label %catch

catch:
%5 = call i8* @__cxa_begin_catch(i8* %3) #4
%6 = bitcast i32* %0 to i8*
call void @free(i8* %6)
call void @__cxa_end_catch()
br label %fun.ret

fun.ret:
ret void
}

; Function Attrs: nounwind
declare noalias i8* @malloc(i64)

; Function Attrs: nounwind
declare void @free(i8* nocapture)

declare void @boo()

; This is an artifical example, readnone functions by definition cannot unwind
; exceptions by calling the C++ exception throwing methods
; This function should only be used to test malloc_capture.
declare void @boo_readnone() readnone

declare i32 @__gxx_personality_v0(...)

declare i8* @__cxa_begin_catch(i8*)

declare void @__cxa_end_catch()

declare i32 @llvm.eh.typeid.for(i8*)

declare void @f() uwtable

0 comments on commit 5ee40ba

Please sign in to comment.