diff --git a/include/llvm/Analysis/CaptureTracking.h b/include/llvm/Analysis/CaptureTracking.h index 01eca6041ea..f2e72535cda 100644 --- a/include/llvm/Analysis/CaptureTracking.h +++ b/include/llvm/Analysis/CaptureTracking.h @@ -50,10 +50,10 @@ namespace llvm { /// U->getUser() is always an Instruction. virtual bool shouldExplore(Use *U) = 0; - /// captured - The instruction I captured the pointer. Return true to - /// stop the traversal or false to continue looking for more capturing - /// instructions. - virtual bool captured(Instruction *I) = 0; + /// captured - Information about the pointer was captured by the user of + /// use U. Return true to stop the traversal or false to continue looking + /// for more capturing instructions. + virtual bool captured(Use *U) = 0; }; /// PointerMayBeCaptured - Visit the value and the values derived from it and diff --git a/lib/Analysis/CaptureTracking.cpp b/lib/Analysis/CaptureTracking.cpp index 9a7992e38d5..68993ead2c8 100644 --- a/lib/Analysis/CaptureTracking.cpp +++ b/lib/Analysis/CaptureTracking.cpp @@ -30,8 +30,8 @@ namespace { bool shouldExplore(Use *U) { return true; } - bool captured(Instruction *I) { - if (isa(I) && !ReturnCaptures) + bool captured(Use *U) { + if (isa(U->getUser()) && !ReturnCaptures) return false; Captured = true; @@ -117,7 +117,7 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) { for (CallSite::arg_iterator A = B; A != E; ++A) if (A->get() == V && !CS.doesNotCapture(A - B)) // The parameter is not marked 'nocapture' - captured. - if (Tracker->captured(I)) + if (Tracker->captured(U)) return; break; } @@ -130,7 +130,7 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) { case Instruction::Store: if (V == I->getOperand(0)) // Stored the pointer - conservatively assume it may be captured. - if (Tracker->captured(I)) + if (Tracker->captured(U)) return; // Storing to the pointee does not cause the pointer to be captured. break; @@ -158,12 +158,12 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) { break; // Otherwise, be conservative. There are crazy ways to capture pointers // using comparisons. - if (Tracker->captured(I)) + if (Tracker->captured(U)) return; break; default: // Something else - be conservative and say it is captured. - if (Tracker->captured(I)) + if (Tracker->captured(U)) return; break; } diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index 704e27b5ce6..53d666078ed 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -349,7 +349,8 @@ namespace { return true; } - bool captured(Instruction *I) { + bool captured(Use *U) { + Instruction *I = cast(U->getUser()); if (BeforeHere != I && DT->dominates(BeforeHere, I)) return false; Captured = true; diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 0edf3427507..9e30c40e20c 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -27,6 +27,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/UniqueVector.h" @@ -225,31 +226,247 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { return MadeChange; } +namespace { + // For a given pointer Argument, this retains a list of Arguments of functions + // in the same SCC that the pointer data flows into. We use this to build an + // SCC of the arguments. + struct ArgumentGraphNode { + Argument *Definition; + SmallVector Uses; + }; + + class ArgumentGraph { + // We store pointers to ArgumentGraphNode objects, so it's important that + // that they not move around upon insert. + typedef std::map ArgumentMapTy; + + ArgumentMapTy ArgumentMap; + + // There is no root node for the argument graph, in fact: + // void f(int *x, int *y) { if (...) f(x, y); } + // is an example where the graph is disconnected. The SCCIterator requires a + // single entry point, so we maintain a fake ("synthetic") root node that + // uses every node. Because the graph is directed and nothing points into + // the root, it will not participate in any SCCs (except for its own). + ArgumentGraphNode SyntheticRoot; + + public: + ArgumentGraph() { SyntheticRoot.Definition = 0; } + + typedef SmallVectorImpl::iterator iterator; + + iterator begin() { return SyntheticRoot.Uses.begin(); } + iterator end() { return SyntheticRoot.Uses.end(); } + ArgumentGraphNode *getEntryNode() { return &SyntheticRoot; } + + ArgumentGraphNode *operator[](Argument *A) { + ArgumentGraphNode &Node = ArgumentMap[A]; + Node.Definition = A; + SyntheticRoot.Uses.push_back(&Node); + return &Node; + } + }; + + // This tracker checks whether callees are in the SCC, and if so it does not + // consider that a capture, instead adding it to the "Uses" list and + // continuing with the analysis. + struct ArgumentUsesTracker : public CaptureTracker { + ArgumentUsesTracker(const SmallPtrSet &SCCNodes) + : Captured(false), SCCNodes(SCCNodes) {} + + void tooManyUses() { Captured = true; } + + bool shouldExplore(Use *U) { return true; } + + bool captured(Use *U) { + CallSite CS(U->getUser()); + if (!CS.getInstruction()) { Captured = true; return true; } + + Function *F = CS.getCalledFunction(); + if (!F || !SCCNodes.count(F)) { Captured = true; return true; } + + Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); + for (CallSite::arg_iterator PI = CS.arg_begin(), PE = CS.arg_end(); + PI != PE; ++PI, ++AI) { + if (AI == AE) { + assert(F->isVarArg() && "More params than args in non-varargs call"); + Captured = true; + return true; + } + if (PI == U) { + Uses.push_back(AI); + break; + } + } + assert(!Uses.empty() && "Capturing call-site captured nothing?"); + return false; + } + + bool Captured; // True only if certainly captured (used outside our SCC). + SmallVector Uses; // Uses within our SCC. + + const SmallPtrSet &SCCNodes; + }; +} + +namespace llvm { + template<> struct GraphTraits { + typedef ArgumentGraphNode NodeType; + typedef SmallVectorImpl::iterator ChildIteratorType; + + static inline NodeType *getEntryNode(NodeType *A) { return A; } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->Uses.begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->Uses.end(); + } + }; + template<> struct GraphTraits + : public GraphTraits { + static NodeType *getEntryNode(ArgumentGraph *AG) { + return AG->getEntryNode(); + } + static ChildIteratorType nodes_begin(ArgumentGraph *AG) { + return AG->begin(); + } + static ChildIteratorType nodes_end(ArgumentGraph *AG) { + return AG->end(); + } + }; +} + /// AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) { bool Changed = false; + SmallPtrSet SCCNodes; + + // Fill SCCNodes with the elements of the SCC. Used for quickly + // looking up whether a given CallGraphNode is in this SCC. + for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { + Function *F = (*I)->getFunction(); + if (F && !F->isDeclaration() && !F->mayBeOverridden()) + SCCNodes.insert(F); + } + + ArgumentGraph AG; + // Check each function in turn, determining which pointer arguments are not // captured. for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { Function *F = (*I)->getFunction(); if (F == 0) - // External node - skip it; + // External node - only a problem for arguments that we pass to it. continue; // Definitions with weak linkage may be overridden at linktime with - // something that writes memory, so treat them like declarations. + // something that captures pointers, so treat them like declarations. if (F->isDeclaration() || F->mayBeOverridden()) continue; + // Functions that are readonly (or readnone) and nounwind and don't return + // a value can't capture arguments. Don't analyze them. + if (F->onlyReadsMemory() && F->doesNotThrow() && + F->getReturnType()->isVoidTy()) { + for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); + A != E; ++A) { + if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { + A->addAttr(Attribute::NoCapture); + ++NumNoCapture; + Changed = true; + } + } + continue; + } + for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A!=E; ++A) - if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr() && - !PointerMayBeCaptured(A, true, /*StoreCaptures=*/false)) { - A->addAttr(Attribute::NoCapture); + if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { + ArgumentUsesTracker Tracker(SCCNodes); + PointerMayBeCaptured(A, &Tracker); + if (!Tracker.Captured) { + if (Tracker.Uses.empty()) { + // If it's trivially not captured, mark it nocapture now. + A->addAttr(Attribute::NoCapture); + ++NumNoCapture; + Changed = true; + } else { + // If it's not trivially captured and not trivially not captured, + // then it must be calling into another function in our SCC. Save + // its particulars for Argument-SCC analysis later. + ArgumentGraphNode *Node = AG[A]; + for (SmallVectorImpl::iterator UI = Tracker.Uses.begin(), + UE = Tracker.Uses.end(); UI != UE; ++UI) + Node->Uses.push_back(AG[*UI]); + } + } + // Otherwise, it's captured. Don't bother doing SCC analysis on it. + } + } + + // The graph we've collected is partial because we stopped scanning for + // argument uses once we solved the argument trivially. These partial nodes + // show up as ArgumentGraphNode objects with an empty Uses list, and for + // these nodes the final decision about whether they capture has already been + // made. If the definition doesn't have a 'nocapture' attribute by now, it + // captures. + + for (scc_iterator I = scc_begin(&AG), E = scc_end(&AG); + I != E; ++I) { + std::vector &ArgumentSCC = *I; + if (ArgumentSCC.size() == 1) { + if (!ArgumentSCC[0]->Definition) continue; // synthetic root node + + // eg. "void f(int* x) { if (...) f(x); }" + if (ArgumentSCC[0]->Uses.size() == 1 && + ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) { + ArgumentSCC[0]->Definition->addAttr(Attribute::NoCapture); ++NumNoCapture; Changed = true; } + continue; + } + + bool SCCCaptured = false; + for (std::vector::iterator I = ArgumentSCC.begin(), + E = ArgumentSCC.end(); I != E && !SCCCaptured; ++I) { + ArgumentGraphNode *Node = *I; + if (Node->Uses.empty()) { + if (!Node->Definition->hasNoCaptureAttr()) + SCCCaptured = true; + } + } + if (SCCCaptured) continue; + + SmallPtrSet ArgumentSCCNodes; + // Fill ArgumentSCCNodes with the elements of the ArgumentSCC. Used for + // quickly looking up whether a given Argument is in this ArgumentSCC. + for (std::vector::iterator I = ArgumentSCC.begin(), + E = ArgumentSCC.end(); I != E; ++I) { + ArgumentSCCNodes.insert((*I)->Definition); + } + + for (std::vector::iterator I = ArgumentSCC.begin(), + E = ArgumentSCC.end(); I != E && !SCCCaptured; ++I) { + ArgumentGraphNode *N = *I; + for (SmallVectorImpl::iterator UI = N->Uses.begin(), + UE = N->Uses.end(); UI != UE; ++UI) { + Argument *A = (*UI)->Definition; + if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A)) + continue; + SCCCaptured = true; + break; + } + } + if (SCCCaptured) continue; + + for (unsigned i = 0, e = ArgumentSCC.size(); i != e && !SCCCaptured; ++i) { + Argument *A = ArgumentSCC[i]->Definition; + A->addAttr(Attribute::NoCapture); + ++NumNoCapture; + Changed = true; + } } return Changed; diff --git a/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll b/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll index 8fb5ffffbae..1ac59278e7e 100644 --- a/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll +++ b/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll @@ -24,7 +24,7 @@ define void @test0_no(i32* %p) nounwind { ; Add the readonly attribute, since there's just a call to a function which ; TBAA says doesn't modify any memory. -; CHECK: define void @test1_yes(i32* %p) nounwind readonly { +; CHECK: define void @test1_yes(i32* nocapture %p) nounwind readonly { define void @test1_yes(i32* %p) nounwind { call void @callee(i32* %p), !tbaa !1 ret void diff --git a/test/Transforms/FunctionAttrs/nocapture.ll b/test/Transforms/FunctionAttrs/nocapture.ll index fa699b4deb7..3027acd35c7 100644 --- a/test/Transforms/FunctionAttrs/nocapture.ll +++ b/test/Transforms/FunctionAttrs/nocapture.ll @@ -115,3 +115,64 @@ define void @nc5(void (i8*)* %f, i8* %p) { call void %f(i8* nocapture %p) ret void } + +; CHECK: define void @test1_1(i8* nocapture %x1_1, i8* %y1_1) +define void @test1_1(i8* %x1_1, i8* %y1_1) { + call i8* @test1_2(i8* %x1_1, i8* %y1_1) + store i32* null, i32** @g + ret void +} + +; CHECK: define i8* @test1_2(i8* nocapture %x1_2, i8* %y1_2) +define i8* @test1_2(i8* %x1_2, i8* %y1_2) { + call void @test1_1(i8* %x1_2, i8* %y1_2) + store i32* null, i32** @g + ret i8* %y1_2 +} + +; CHECK: define void @test2(i8* nocapture %x2) +define void @test2(i8* %x2) { + call void @test2(i8* %x2) + store i32* null, i32** @g + ret void +} + +; CHECK: define void @test3(i8* nocapture %x3, i8* nocapture %y3, i8* nocapture %z3) +define void @test3(i8* %x3, i8* %y3, i8* %z3) { + call void @test3(i8* %z3, i8* %y3, i8* %x3) + store i32* null, i32** @g + ret void +} + +; CHECK: define void @test4_1(i8* %x4_1) +define void @test4_1(i8* %x4_1) { + call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1) + store i32* null, i32** @g + ret void +} + +; CHECK: define i8* @test4_2(i8* nocapture %x4_2, i8* %y4_2, i8* nocapture %z4_2) +define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2) { + call void @test4_1(i8* null) + store i32* null, i32** @g + ret i8* %y4_2 +} + +declare i8* @test5_1(i8* %x5_1) + +; CHECK: define void @test5_2(i8* %x5_2) +define void @test5_2(i8* %x5_2) { + call i8* @test5_1(i8* %x5_2) + store i32* null, i32** @g + ret void +} + +declare void @test6_1(i8* %x6_1, i8* nocapture %y6_1, ...) + +; CHECK: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2) +define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) { + call void (i8*, i8*, ...)* @test6_1(i8* %x6_2, i8* %y6_2, i8* %z6_2) + store i32* null, i32** @g + ret void +} +