Make adding nocapture a bit stronger. FreeInst is nocapture. Also,

functions that don't write can't leak a pointer except through 
the return value, so a void readonly function is implicitly nocapture.

Test these, and add a test that verifies that f1 calling f2 with an 
otherwise dead pointer gets both of them marked nocapture.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@61552 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nick Lewycky 2009-01-02 03:46:56 +00:00
parent b9b3a702c4
commit 6b05686283
2 changed files with 50 additions and 4 deletions

View File

@ -208,10 +208,20 @@ bool FunctionAttrs::isCaptured(Function &F, Value *V) {
continue;
}
if (isa<FreeInst>(I)) {
// Freeing a pointer does not cause it to escape.
continue;
}
CallSite CS = CallSite::get(I);
if (CS.getInstruction()) {
// Does not escape if only passed via 'nocapture' arguments. Note
// that calling a function pointer does not in itself cause that
// Does not escape if the callee is readonly and doesn't return a
// copy through its own return value.
if (CS.onlyReadsMemory() && I->getType() == Type::VoidTy)
continue;
// Does not escape if passed via 'nocapture' arguments. Note that
// calling a function pointer does not in itself cause that
// function pointer to escape. This is a subtle point considering
// that (for example) the callee might return its own address. It
// is analogous to saying that loading a value from a pointer does
@ -264,6 +274,20 @@ bool FunctionAttrs::AddNoCaptureAttrs(const std::vector<CallGraphNode *> &SCC) {
// External node - skip it;
continue;
// If the function is readonly and doesn't return any value, we
// know that the pointer value can't escape. Mark all of its pointer
// arguments nocapture.
if (F->onlyReadsMemory() && F->getReturnType() == Type::VoidTy) {
for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end();
A != E; ++A)
if (isa<PointerType>(A->getType()) && !A->hasNoCaptureAttr()) {
A->addAttr(Attribute::NoCapture);
++NumNoCapture;
Changed = true;
}
continue;
}
// Definitions with weak linkage may be overridden at linktime with
// something that writes memory, so treat them like declarations.
if (F->isDeclaration() || F->mayBeOverridden())
@ -273,7 +297,7 @@ bool FunctionAttrs::AddNoCaptureAttrs(const std::vector<CallGraphNode *> &SCC) {
if (isa<PointerType>(A->getType()) && !A->hasNoCaptureAttr() &&
!isCaptured(*F, A)) {
A->addAttr(Attribute::NoCapture);
NumNoCapture++;
++NumNoCapture;
Changed = true;
}
}

View File

@ -1,5 +1,5 @@
; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | not grep {nocapture *%%q}
; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep {nocapture *%%p} | count 3
; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep {nocapture *%%p} | count 8
@g = global i32* null ; <i32**> [#uses=1]
define i32* @c1(i32* %q) {
@ -62,3 +62,25 @@ define void @nc3(void ()* %p) {
call void %p()
ret void
}
declare void @external(i8*) readonly
define void @nc4(i8* %p) {
call void @external(i8* %p)
ret void
}
define void @nc5(void (i8*)* %f, i8* %p) {
call void %f(i8* %p) readonly
call void %f(i8* nocapture %p)
ret void
}
define void @nc6(i8* %p) {
call void @nc7(i8* %p)
ret void
}
define void @nc7(i8* %p) {
call void @nc6(i8* %p)
ret void
}