1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 19:12:56 +02:00

Teach capture tracking that readonly functions can

only capture their arguments by returning them or
throwing an exception or not based on the argument
value.  Patch essentially by Frits van Bommel.

llvm-svn: 70876
This commit is contained in:
Duncan Sands 2009-05-04 16:50:29 +00:00
parent b77e5b9e2e
commit 4c7021febf
2 changed files with 67 additions and 32 deletions

View File

@ -49,11 +49,7 @@ bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures) {
switch (I->getOpcode()) {
case Instruction::Call:
case Instruction::Invoke: {
CallSite CS = CallSite::get(I);
// Not captured if the callee is readonly and doesn't return a copy
// through its return value.
if (CS.onlyReadsMemory() && I->getType() == Type::VoidTy)
break;
CallSite CS(I);
// Not captured if only passed via 'nocapture' arguments. Note that
// calling a function pointer does not in itself cause the pointer to
@ -62,46 +58,69 @@ bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures) {
// that loading a value from a pointer does not cause the pointer to be
// captured, even though the loaded value might be the pointer itself
// (think of self-referential objects).
bool MayBeCaptured = false;
CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
for (CallSite::arg_iterator A = B; A != E; ++A)
if (A->get() == V && !CS.paramHasAttr(A - B + 1, Attribute::NoCapture))
// The parameter is not marked 'nocapture' - captured.
return true;
// Only passed via 'nocapture' arguments, or is the called function - not
// captured.
if (A->get() == V && !CS.paramHasAttr(A-B+1, Attribute::NoCapture)) {
// The parameter is not marked 'nocapture' - handled by generic code
// below.
MayBeCaptured = true;
break;
}
if (!MayBeCaptured)
// Only passed via 'nocapture' arguments, or is the called function -
// not captured.
continue;
if (!CS.doesNotThrow())
// Even a readonly function can leak bits by throwing an exception or
// not depending on the input value.
return true;
// Fall through to the generic code.
break;
}
case Instruction::Free:
// Freeing a pointer does not cause it to be captured.
break;
continue;
case Instruction::Load:
// Loading from a pointer does not cause it to be captured.
break;
continue;
case Instruction::Ret:
if (ReturnCaptures)
return true;
break;
continue;
case Instruction::Store:
if (V == I->getOperand(0))
// Stored the pointer - it may be captured.
return true;
// Storing to the pointee does not cause the pointer to be captured.
break;
case Instruction::BitCast:
case Instruction::GetElementPtr:
case Instruction::PHI:
case Instruction::Select:
// The original value is not captured via this if the new value isn't.
for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end();
UI != UE; ++UI) {
Use *U = &UI.getUse();
if (Visited.insert(U))
Worklist.push_back(U);
}
break;
default:
// Something else - be conservative and say it is captured.
continue;
}
// If it may write to memory and isn't one of the special cases above,
// be conservative and assume the pointer is captured.
if (I->mayWriteToMemory())
return true;
// If the instruction doesn't write memory, it can only capture by
// having its own value depend on the input value.
const Type* Ty = I->getType();
if (Ty == Type::VoidTy)
// The value of an instruction can't be a copy if it can't contain any
// information.
continue;
if (!isa<PointerType>(Ty))
// At the moment, we don't track non-pointer values, so be conservative
// and assume the pointer is captured.
// FIXME: Track these too. This would need to be done very carefully as
// it is easy to leak bits via control flow if integer values are allowed.
return true;
// The original value is not captured via this if the new value isn't.
for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end();
UI != UE; ++UI) {
Use *U = &UI.getUse();
if (Visited.insert(U))
Worklist.push_back(U);
}
}

View File

@ -39,6 +39,16 @@ define i1 @c5(i32* %q, i32 %bitno) {
ret i1 %val
}
declare void @throw_if_bit_set(i8*, i8) readonly
define i1 @c6(i8* %q, i8 %bit) {
invoke void @throw_if_bit_set(i8* %q, i8 %bit)
to label %ret0 unwind label %ret1
ret0:
ret i1 0
ret1:
ret i1 1
}
define i32 @nc1(i32* %q, i32* %p, i1 %b) {
e:
br label %l
@ -63,14 +73,20 @@ define void @nc3(void ()* %p) {
ret void
}
declare void @external(i8*) readonly
declare void @external(i8*) readonly nounwind
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)
define void @nc5(void (i8*)* %p, i8* %r) {
call void %p(i8* %r)
call void %p(i8* nocapture %r)
ret void
}
declare i8* @external_identity(i8*) readonly nounwind
define void @nc6(i8* %p) {
call i8* @external_identity(i8* %p)
ret void
}