diff options
author | Duncan Sands <baldrick@free.fr> | 2008-12-31 16:14:43 +0000 |
---|---|---|
committer | Duncan Sands <baldrick@free.fr> | 2008-12-31 16:14:43 +0000 |
commit | 1410dfde5c04d0c94590baa0b86467e9153b4af6 (patch) | |
tree | 4b985f2525e7c6470e7a9d345b5c7eb7ffa889fe | |
parent | 250918eb177828db01fb92ba13152ddbc0d0ce92 (diff) | |
download | external_llvm-1410dfde5c04d0c94590baa0b86467e9153b4af6.zip external_llvm-1410dfde5c04d0c94590baa0b86467e9153b4af6.tar.gz external_llvm-1410dfde5c04d0c94590baa0b86467e9153b4af6.tar.bz2 |
Rename AddReadAttrs to FunctionAttrs, and teach it how
to work out (in a very simplistic way) which function
arguments (pointer arguments only) are only dereferenced
and so do not escape. Mark such arguments 'nocapture'.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@61525 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/LinkAllPasses.h | 2 | ||||
-rw-r--r-- | include/llvm/Transforms/IPO.h | 6 | ||||
-rw-r--r-- | lib/Transforms/IPO/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Transforms/IPO/FunctionAttrs.cpp (renamed from lib/Transforms/IPO/AddReadAttrs.cpp) | 138 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-09-03-Mutual.ll (renamed from test/Transforms/AddReadAttrs/2008-09-03-Mutual.ll) | 2 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll (renamed from test/Transforms/AddReadAttrs/2008-09-03-ReadNone.ll) | 2 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll (renamed from test/Transforms/AddReadAttrs/2008-09-03-ReadOnly.ll) | 2 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-09-13-VolatileRead.ll (renamed from test/Transforms/AddReadAttrs/2008-09-13-VolatileRead.ll) | 2 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll (renamed from test/Transforms/AddReadAttrs/2008-10-04-LocalMemory.ll) | 2 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-12-29-Constant.ll (renamed from test/Transforms/AddReadAttrs/2008-12-29-Constant.ll) | 2 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll | 34 | ||||
-rw-r--r-- | test/Transforms/FunctionAttrs/dg.exp (renamed from test/Transforms/AddReadAttrs/dg.exp) | 0 | ||||
-rw-r--r-- | tools/opt/opt.cpp | 4 | ||||
-rw-r--r-- | win32/Transforms/Transforms.vcproj | 2 |
14 files changed, 175 insertions, 25 deletions
diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index bc77c08..4113b16 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -122,7 +122,7 @@ namespace { (void) llvm::createPostDomFrontier(); (void) llvm::createInstructionNamerPass(); (void) llvm::createPartialSpecializationPass(); - (void) llvm::createAddReadAttrsPass(); + (void) llvm::createFunctionAttrsPass(); (void) llvm::createMergeFunctionsPass(); (void) llvm::createPrintModulePass(0); (void) llvm::createPrintFunctionPass("", 0); diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h index 0d4e33a..eeb2aa2 100644 --- a/include/llvm/Transforms/IPO.h +++ b/include/llvm/Transforms/IPO.h @@ -196,10 +196,12 @@ ModulePass *createStripDeadPrototypesPass(); ModulePass *createPartialSpecializationPass(); //===----------------------------------------------------------------------===// -/// createAddReadAttrsPass - This pass discovers functions that do not access +/// createFunctionAttrsPass - This pass discovers functions that do not access /// memory, or only read memory, and gives them the readnone/readonly attribute. +/// It also discovers function arguments that are not captured by the function +/// and marks them with the nocapture attribute. /// -Pass *createAddReadAttrsPass(); +Pass *createFunctionAttrsPass(); //===----------------------------------------------------------------------===// /// createMergeFunctionsPass - This pass discovers identical functions and diff --git a/lib/Transforms/IPO/CMakeLists.txt b/lib/Transforms/IPO/CMakeLists.txt index f168083..4b85e13 100644 --- a/lib/Transforms/IPO/CMakeLists.txt +++ b/lib/Transforms/IPO/CMakeLists.txt @@ -1,5 +1,5 @@ add_llvm_library(LLVMipo - AddReadAttrs.cpp + FunctionAttrs.cpp ArgumentPromotion.cpp ConstantMerge.cpp DeadArgumentElimination.cpp diff --git a/lib/Transforms/IPO/AddReadAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 96c1427..9ed605c 100644 --- a/lib/Transforms/IPO/AddReadAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1,4 +1,4 @@ -//===- AddReadAttrs.cpp - Pass which marks functions readnone or readonly -===// +//===- FunctionAttrs.cpp - Pass which marks functions readnone or readonly ===// // // The LLVM Compiler Infrastructure // @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "addreadattrs" +#define DEBUG_TYPE "functionattrs" #include "llvm/Transforms/IPO.h" #include "llvm/CallGraphSCCPass.h" #include "llvm/GlobalVariable.h" @@ -28,15 +28,25 @@ using namespace llvm; STATISTIC(NumReadNone, "Number of functions marked readnone"); STATISTIC(NumReadOnly, "Number of functions marked readonly"); +STATISTIC(NumNoCapture, "Number of arguments marked nocapture"); namespace { - struct VISIBILITY_HIDDEN AddReadAttrs : public CallGraphSCCPass { + struct VISIBILITY_HIDDEN FunctionAttrs : public CallGraphSCCPass { static char ID; // Pass identification, replacement for typeid - AddReadAttrs() : CallGraphSCCPass(&ID) {} + FunctionAttrs() : CallGraphSCCPass(&ID) {} // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(const std::vector<CallGraphNode *> &SCC); + // AddReadAttrs - Deduce readonly/readnone attributes for the SCC. + bool AddReadAttrs(const std::vector<CallGraphNode *> &SCC); + + // AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. + bool AddNoCaptureAttrs(const std::vector<CallGraphNode *> &SCC); + + // isCaptured - Returns whether this pointer value is captured. + bool isCaptured(Function &F, Value *V); + virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); CallGraphSCCPass::getAnalysisUsage(AU); @@ -46,17 +56,17 @@ namespace { }; } -char AddReadAttrs::ID = 0; -static RegisterPass<AddReadAttrs> -X("addreadattrs", "Mark functions readnone/readonly"); +char FunctionAttrs::ID = 0; +static RegisterPass<FunctionAttrs> +X("functionattrs", "Deduce function attributes"); -Pass *llvm::createAddReadAttrsPass() { return new AddReadAttrs(); } +Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); } /// PointsToLocalMemory - Returns whether the given pointer value points to /// memory that is local to the function. Global constants are considered /// local to all functions. -bool AddReadAttrs::PointsToLocalMemory(Value *V) { +bool FunctionAttrs::PointsToLocalMemory(Value *V) { V = V->getUnderlyingObject(); // An alloca instruction defines local memory. if (isa<AllocaInst>(V)) @@ -69,8 +79,9 @@ bool AddReadAttrs::PointsToLocalMemory(Value *V) { return false; } -bool AddReadAttrs::runOnSCC(const std::vector<CallGraphNode *> &SCC) { - SmallPtrSet<CallGraphNode *, 8> SCCNodes; +/// AddReadAttrs - Deduce readonly/readnone attributes for the SCC. +bool FunctionAttrs::AddReadAttrs(const std::vector<CallGraphNode *> &SCC) { + SmallPtrSet<CallGraphNode*, 8> SCCNodes; CallGraph &CG = getAnalysis<CallGraph>(); // Fill SCCNodes with the elements of the SCC. Used for quickly @@ -154,7 +165,7 @@ bool AddReadAttrs::runOnSCC(const std::vector<CallGraphNode *> &SCC) { F->removeAttribute(~0, Attribute::ReadOnly | Attribute::ReadNone); // Add in the new attribute. - F->addAttribute(~0, ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone); + F->addAttribute(~0, ReadsMemory? Attribute::ReadOnly : Attribute::ReadNone); if (ReadsMemory) NumReadOnly++; @@ -164,3 +175,106 @@ bool AddReadAttrs::runOnSCC(const std::vector<CallGraphNode *> &SCC) { return MadeChange; } + +/// isCaptured - Returns whether this pointer value is captured. +bool FunctionAttrs::isCaptured(Function &F, Value *V) { + SmallVector<Use*, 16> Worklist; + SmallPtrSet<Use*, 16> 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<Instruction>(U->getUser()); + V = U->get(); + + if (isa<LoadInst>(I)) { + // Loading a pointer does not cause it to escape. + continue; + } + + if (isa<StoreInst>(I)) { + if (V == I->getOperand(0)) + // Stored the pointer - escapes. TODO: improve this. + return true; + // Storing to the pointee does not cause the pointer 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 + // 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 + // not cause the pointer to escape, 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' - escapes. + return true; + // Only passed via 'nocapture' arguments, or is the called function. + // Does not escape. + continue; + } + + if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I)) { + // Type conversion or calculating an offset. Does not escape if the new + // value doesn'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); + } + continue; + } + + // Something else - be conservative and say it escapes. + return true; + } + + return false; +} + +/// AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. +bool FunctionAttrs::AddNoCaptureAttrs(const std::vector<CallGraphNode *> &SCC) { + bool Changed = false; + + // Check each function in turn, determining which pointer arguments are not + // captured. + for (unsigned i = 0, e = SCC.size(); i != e; ++i) { + Function *F = SCC[i]->getFunction(); + + if (F == 0) + // External node - skip it; + 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()) + continue; + + for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A!=E; ++A) + if (isa<PointerType>(A->getType()) && !isCaptured(*F, A)) { + A->addAttr(Attribute::NoCapture); + NumNoCapture++; + Changed = true; + } + } + + return Changed; +} + +bool FunctionAttrs::runOnSCC(const std::vector<CallGraphNode *> &SCC) { + bool Changed = AddReadAttrs(SCC); + Changed |= AddNoCaptureAttrs(SCC); + return Changed; +} diff --git a/test/Transforms/AddReadAttrs/2008-09-03-Mutual.ll b/test/Transforms/FunctionAttrs/2008-09-03-Mutual.ll index 0a4f085..5261ac4 100644 --- a/test/Transforms/AddReadAttrs/2008-09-03-Mutual.ll +++ b/test/Transforms/FunctionAttrs/2008-09-03-Mutual.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -addreadattrs | llvm-dis | grep readnone +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep readnone define i32 @a() { %tmp = call i32 @b( ) ; <i32> [#uses=1] diff --git a/test/Transforms/AddReadAttrs/2008-09-03-ReadNone.ll b/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll index 3c7b32d..a17d381 100644 --- a/test/Transforms/AddReadAttrs/2008-09-03-ReadNone.ll +++ b/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -addreadattrs | llvm-dis | grep readnone | count 4 +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep readnone | count 4 @x = global i32 0 declare i32 @e() readnone diff --git a/test/Transforms/AddReadAttrs/2008-09-03-ReadOnly.ll b/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll index c08e7b1..cebfdac 100644 --- a/test/Transforms/AddReadAttrs/2008-09-03-ReadOnly.ll +++ b/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -addreadattrs | llvm-dis | grep readonly | count 2 +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep readonly | count 2 define i32 @f() { entry: diff --git a/test/Transforms/AddReadAttrs/2008-09-13-VolatileRead.ll b/test/Transforms/FunctionAttrs/2008-09-13-VolatileRead.ll index 0690083..b6077fd 100644 --- a/test/Transforms/AddReadAttrs/2008-09-13-VolatileRead.ll +++ b/test/Transforms/FunctionAttrs/2008-09-13-VolatileRead.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -addreadattrs | llvm-dis | not grep read +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | not grep read ; PR2792 @g = global i32 0 ; <i32*> [#uses=1] diff --git a/test/Transforms/AddReadAttrs/2008-10-04-LocalMemory.ll b/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll index 0f63c1a..50ca641 100644 --- a/test/Transforms/AddReadAttrs/2008-10-04-LocalMemory.ll +++ b/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -addreadattrs | llvm-dis | grep readnone | count 2 +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep readnone | count 2 declare i32 @g(i32*) readnone diff --git a/test/Transforms/AddReadAttrs/2008-12-29-Constant.ll b/test/Transforms/FunctionAttrs/2008-12-29-Constant.ll index fe038c1..d9c0117 100644 --- a/test/Transforms/AddReadAttrs/2008-12-29-Constant.ll +++ b/test/Transforms/FunctionAttrs/2008-12-29-Constant.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -addreadattrs | llvm-dis | grep readnone +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep readnone @s = external constant i8 ; <i8*> [#uses=1] diff --git a/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll b/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll new file mode 100644 index 0000000..6d2ca1e --- /dev/null +++ b/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll @@ -0,0 +1,34 @@ +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | not grep {@c.*nocapture} +; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep nocapture | count 3 +@g = global i32* null ; <i32**> [#uses=1] + +define i32* @c1(i32* %p) { + ret i32* %p +} + +define void @c2(i32* %p) { + store i32* %p, i32** @g + ret void +} + +define void @c3(i32* %p) { + call void @c2(i32* %p) + ret void +} + +define i32 @nc1(i32* %p) { + %tmp = bitcast i32* %p to i32* ; <i32*> [#uses=2] + %val = load i32* %tmp ; <i32> [#uses=1] + store i32 0, i32* %tmp + ret i32 %val +} + +define void @nc2(i32* %p) { + %1 = call i32 @nc1(i32* %p) ; <i32> [#uses=0] + ret void +} + +define void @nc3(void ()* %f) { + call void %f() + ret void +} diff --git a/test/Transforms/AddReadAttrs/dg.exp b/test/Transforms/FunctionAttrs/dg.exp index f200589..f200589 100644 --- a/test/Transforms/AddReadAttrs/dg.exp +++ b/test/Transforms/FunctionAttrs/dg.exp diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 9039553..b46f7c9 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -291,7 +291,7 @@ void AddOptimizationPasses(PassManager &MPM, FunctionPassManager &FPM, MPM.add(createCFGSimplificationPass()); // Clean up after IPCP & DAE if (UnitAtATime) { MPM.add(createPruneEHPass()); // Remove dead EH info - MPM.add(createAddReadAttrsPass()); // Set readonly/readnone attrs + MPM.add(createFunctionAttrsPass()); // Deduce function attrs } if (OptLevel > 1) MPM.add(createFunctionInliningPass()); // Inline small functions @@ -363,7 +363,7 @@ void AddStandardCompilePasses(PassManager &PM) { addPass(PM, createCFGSimplificationPass()); // Clean up after IPCP & DAE addPass(PM, createPruneEHPass()); // Remove dead EH info - addPass(PM, createAddReadAttrsPass()); // Set readonly/readnone attrs + addPass(PM, createFunctionAttrsPass()); // Deduce function attrs if (!DisableInline) addPass(PM, createFunctionInliningPass()); // Inline small functions diff --git a/win32/Transforms/Transforms.vcproj b/win32/Transforms/Transforms.vcproj index 8a5e898..0bde3d8 100644 --- a/win32/Transforms/Transforms.vcproj +++ b/win32/Transforms/Transforms.vcproj @@ -344,7 +344,7 @@ Name="IPO" > <File - RelativePath="..\..\lib\Transforms\IPO\AddReadAttrs.cpp" + RelativePath="..\..\lib\Transforms\IPO\FunctionAttrs.cpp" > </File> <File |