From 8556d2a7f155c7edfaf454a3acda8ce28863c5e4 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Sun, 18 Jan 2009 12:19:30 +0000 Subject: [PATCH] BasicAliasAnalysis and FunctionAttrs were both doing very similar pointer capture analysis. Factor out the common logic. The new version is from FunctionAttrs since it does a better job than the version in BasicAliasAnalysis git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62461 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/CaptureTracking.h | 29 +++++++ lib/Analysis/BasicAliasAnalysis.cpp | 55 +----------- lib/Analysis/CaptureTracking.cpp | 110 ++++++++++++++++++++++++ lib/Transforms/IPO/FunctionAttrs.cpp | 83 +----------------- 4 files changed, 144 insertions(+), 133 deletions(-) create mode 100644 include/llvm/Analysis/CaptureTracking.h create mode 100644 lib/Analysis/CaptureTracking.cpp diff --git a/include/llvm/Analysis/CaptureTracking.h b/include/llvm/Analysis/CaptureTracking.h new file mode 100644 index 00000000000..a0ff503a039 --- /dev/null +++ b/include/llvm/Analysis/CaptureTracking.h @@ -0,0 +1,29 @@ +//===----- llvm/Analysis/CaptureTracking.h - Pointer capture ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains routines that help determine which pointers are captured. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CAPTURETRACKING_H +#define LLVM_ANALYSIS_CAPTURETRACKING_H + +namespace llvm { + class Value; + + /// PointerMayBeCaptured - Return true if this pointer value may be captured + /// by the enclosing function (which is required to exist). This routine can + /// be expensive, so consider caching the results. The boolean ReturnCaptures + /// specifies whether returning the value (or part of it) from the function + /// counts as capturing it or not. + bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures); + +} // end namespace llvm + +#endif diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index 9cefdcf40dc..82514400b82 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/Passes.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -35,56 +36,6 @@ using namespace llvm; // Useful predicates //===----------------------------------------------------------------------===// -// Determine if a value escapes from the function it is contained in (being -// returned by the function does not count as escaping here). If a value local -// to the function does not escape, there is no way another function can mod/ref -// it. We do this by looking at its uses and determining if they can escape -// (recursively). -static bool AddressMightEscape(const Value *V) { - for (Value::use_const_iterator UI = V->use_begin(), E = V->use_end(); - UI != E; ++UI) { - const Instruction *I = cast(*UI); - switch (I->getOpcode()) { - case Instruction::Load: - break; //next use. - case Instruction::Store: - if (I->getOperand(0) == V) - return true; // Escapes if the pointer is stored. - break; // next use. - case Instruction::GetElementPtr: - if (AddressMightEscape(I)) - return true; - break; // next use. - case Instruction::BitCast: - if (AddressMightEscape(I)) - return true; - break; // next use - case Instruction::Ret: - // If returned, the address will escape to calling functions, but no - // callees could modify it. - break; // next use - case Instruction::Call: - // If the argument to the call has the nocapture attribute, then the call - // may store or load to the pointer, but it cannot escape. - if (cast(I)->paramHasAttr(UI.getOperandNo(), - Attribute::NoCapture)) - continue; - return true; - case Instruction::Invoke: - // If the argument to the call has the nocapture attribute, then the call - // may store or load to the pointer, but it cannot escape. - // Do compensate for the two BB operands, i.e. Arg1 is at index 3! - if (cast(I)->paramHasAttr(UI.getOperandNo()-2, - Attribute::NoCapture)) - continue; - return true; - default: - return true; - } - } - return false; -} - static const User *isGEP(const Value *V) { if (isa(V) || (isa(V) && @@ -158,7 +109,7 @@ static bool isKnownNonNull(const Value *V) { static bool isNonEscapingLocalObject(const Value *V) { // If this is a local allocation, check to see if it escapes. if (isa(V) || isNoAliasCall(V)) - return !AddressMightEscape(V); + return !PointerMayBeCaptured(V, false); // If this is an argument that corresponds to a byval or noalias argument, // then it has not escaped before entering the function. Check if it escapes @@ -168,7 +119,7 @@ static bool isNonEscapingLocalObject(const Value *V) { // Don't bother analyzing arguments already known not to escape. if (A->hasNoCaptureAttr()) return true; - return !AddressMightEscape(V); + return !PointerMayBeCaptured(V, false); } return false; } diff --git a/lib/Analysis/CaptureTracking.cpp b/lib/Analysis/CaptureTracking.cpp new file mode 100644 index 00000000000..ceb964619c5 --- /dev/null +++ b/lib/Analysis/CaptureTracking.cpp @@ -0,0 +1,110 @@ +//===--- CaptureTracking.cpp - Determine whether a pointer is captured ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains routines that help determine which pointers are captured. +// A pointer value is captured if the function makes a copy of any part of the +// pointer that outlives the call. Not being captured means, more or less, that +// the pointer is only dereferenced and not stored in a global. Returning part +// of the pointer as the function return value may or may not count as capturing +// the pointer, depending on the context. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Instructions.h" +#include "llvm/Value.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CallSite.h" +using namespace llvm; + +/// PointerMayBeCaptured - Return true if this pointer value may be captured +/// by the enclosing function (which is required to exist). This routine can +/// be expensive, so consider caching the results. The boolean ReturnCaptures +/// specifies whether returning the value (or part of it) from the function +/// counts as capturing it or not. +bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures) { + assert(isa(V->getType()) && "Capture is for pointers only!"); + SmallVector Worklist; + SmallSet Visited; + + for (Value::use_const_iterator UI = V->use_begin(), UE = V->use_end(); + UI != UE; ++UI) { + Use *U = &UI.getUse(); + Visited.insert(U); + Worklist.push_back(U); + } + + while (!Worklist.empty()) { + Use *U = Worklist.pop_back_val(); + Instruction *I = cast(U->getUser()); + V = U->get(); + + 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; + + // Not captured if only passed via 'nocapture' arguments. Note that + // calling a function pointer does not in itself cause the pointer to + // be captured. 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 not cause the pointer to be + // captured, even though the loaded value might be the pointer itself + // (think of self-referential objects). + 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. + break; + } + case Instruction::Free: + // Freeing a pointer does not cause it to be captured. + break; + case Instruction::Load: + // Loading from a pointer does not cause it to be captured. + break; + case Instruction::Ret: + if (ReturnCaptures) + return true; + break; + 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. + return true; + } + } + + // All uses examined - not captured. + return false; +} diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index e29e9149c26..47485737ab8 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -24,7 +24,7 @@ #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/Analysis/CallGraph.h" -#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Analysis/CaptureTracking.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Compiler.h" @@ -49,9 +49,6 @@ namespace { // AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. bool AddNoCaptureAttrs(const std::vector &SCC); - // isCaptured - Return true if this pointer value may be captured. - bool isCaptured(Function &F, Value *V); - virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); CallGraphSCCPass::getAnalysisUsage(AU); @@ -181,82 +178,6 @@ bool FunctionAttrs::AddReadAttrs(const std::vector &SCC) { return MadeChange; } -/// isCaptured - Return true if this pointer value may be captured. -bool FunctionAttrs::isCaptured(Function &F, Value *V) { - SmallVector Worklist; - SmallSet Visited; - - for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); UI != UE; - ++UI) { - Use *U = &UI.getUse(); - Visited.insert(U); - Worklist.push_back(U); - } - - while (!Worklist.empty()) { - Use *U = Worklist.pop_back_val(); - Instruction *I = cast(U->getUser()); - V = U->get(); - - 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; - - // Not captured if only passed via 'nocapture' arguments. Note that - // calling a function pointer does not in itself cause the pointer to - // be captured. 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 not cause the pointer to be - // captured, even though the loaded value might be the pointer itself - // (think of self-referential objects). - 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. - break; - } - case Instruction::Free: - // Freeing a pointer does not cause it to be captured. - break; - case Instruction::Load: - // Loading from a pointer does not cause it to be captured. - break; - 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. - return true; - } - } - - // All uses examined - not captured. - return false; -} - /// AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. bool FunctionAttrs::AddNoCaptureAttrs(const std::vector &SCC) { bool Changed = false; @@ -277,7 +198,7 @@ bool FunctionAttrs::AddNoCaptureAttrs(const std::vector &SCC) { for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A!=E; ++A) if (isa(A->getType()) && !A->hasNoCaptureAttr() && - !isCaptured(*F, A)) { + !PointerMayBeCaptured(A, true)) { A->addAttr(Attribute::NoCapture); ++NumNoCapture; Changed = true;