1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 03:23:01 +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()) { switch (I->getOpcode()) {
case Instruction::Call: case Instruction::Call:
case Instruction::Invoke: { case Instruction::Invoke: {
CallSite CS = CallSite::get(I); CallSite CS(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;
// Not captured if only passed via 'nocapture' arguments. Note that // Not captured if only passed via 'nocapture' arguments. Note that
// calling a function pointer does not in itself cause the pointer to // 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 // 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 // captured, even though the loaded value might be the pointer itself
// (think of self-referential objects). // (think of self-referential objects).
bool MayBeCaptured = false;
CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end(); CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
for (CallSite::arg_iterator A = B; A != E; ++A) for (CallSite::arg_iterator A = B; A != E; ++A)
if (A->get() == V && !CS.paramHasAttr(A - B + 1, Attribute::NoCapture)) if (A->get() == V && !CS.paramHasAttr(A-B+1, Attribute::NoCapture)) {
// The parameter is not marked 'nocapture' - captured. // The parameter is not marked 'nocapture' - handled by generic code
return true; // below.
// Only passed via 'nocapture' arguments, or is the called function - not MayBeCaptured = true;
// captured. 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; break;
} }
case Instruction::Free: case Instruction::Free:
// Freeing a pointer does not cause it to be captured. // Freeing a pointer does not cause it to be captured.
break; continue;
case Instruction::Load: case Instruction::Load:
// Loading from a pointer does not cause it to be captured. // Loading from a pointer does not cause it to be captured.
break; continue;
case Instruction::Ret: case Instruction::Ret:
if (ReturnCaptures) if (ReturnCaptures)
return true; return true;
break; continue;
case Instruction::Store: case Instruction::Store:
if (V == I->getOperand(0)) if (V == I->getOperand(0))
// Stored the pointer - it may be captured. // Stored the pointer - it may be captured.
return true; return true;
// Storing to the pointee does not cause the pointer to be captured. // Storing to the pointee does not cause the pointer to be captured.
break; continue;
case Instruction::BitCast: }
case Instruction::GetElementPtr:
case Instruction::PHI: // If it may write to memory and isn't one of the special cases above,
case Instruction::Select: // be conservative and assume the pointer is captured.
// The original value is not captured via this if the new value isn't. if (I->mayWriteToMemory())
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.
return true; 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 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) { define i32 @nc1(i32* %q, i32* %p, i1 %b) {
e: e:
br label %l br label %l
@ -63,14 +73,20 @@ define void @nc3(void ()* %p) {
ret void ret void
} }
declare void @external(i8*) readonly declare void @external(i8*) readonly nounwind
define void @nc4(i8* %p) { define void @nc4(i8* %p) {
call void @external(i8* %p) call void @external(i8* %p)
ret void ret void
} }
define void @nc5(void (i8*)* %f, i8* %p) { define void @nc5(void (i8*)* %p, i8* %r) {
call void %f(i8* %p) readonly call void %p(i8* %r)
call void %f(i8* nocapture %p) 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 ret void
} }