diff options
Diffstat (limited to 'lib/Transforms/IPO/FunctionAttrs.cpp')
-rw-r--r-- | lib/Transforms/IPO/FunctionAttrs.cpp | 146 |
1 files changed, 89 insertions, 57 deletions
diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 010b0a29807d..4e2a82b56eec 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -41,6 +41,7 @@ #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" @@ -66,6 +67,7 @@ using namespace llvm; STATISTIC(NumReadNone, "Number of functions marked readnone"); STATISTIC(NumReadOnly, "Number of functions marked readonly"); +STATISTIC(NumWriteOnly, "Number of functions marked writeonly"); STATISTIC(NumNoCapture, "Number of arguments marked nocapture"); STATISTIC(NumReturned, "Number of arguments marked returned"); STATISTIC(NumReadNoneArg, "Number of arguments marked readnone"); @@ -113,27 +115,30 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, if (AliasAnalysis::onlyReadsMemory(MRB)) return MAK_ReadOnly; - // Conservatively assume it writes to memory. + if (AliasAnalysis::doesNotReadMemory(MRB)) + return MAK_WriteOnly; + + // Conservatively assume it reads and writes to memory. return MAK_MayWrite; } // Scan the function body for instructions that may read or write memory. bool ReadsMemory = false; + bool WritesMemory = false; for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) { Instruction *I = &*II; // Some instructions can be ignored even if they read or write memory. // Detect these now, skipping to the next instruction if one is found. - CallSite CS(cast<Value>(I)); - if (CS) { + if (auto *Call = dyn_cast<CallBase>(I)) { // Ignore calls to functions in the same SCC, as long as the call sites // don't have operand bundles. Calls with operand bundles are allowed to // have memory effects not described by the memory effects of the call // target. - if (!CS.hasOperandBundles() && CS.getCalledFunction() && - SCCNodes.count(CS.getCalledFunction())) + if (!Call->hasOperandBundles() && Call->getCalledFunction() && + SCCNodes.count(Call->getCalledFunction())) continue; - FunctionModRefBehavior MRB = AAR.getModRefBehavior(CS); + FunctionModRefBehavior MRB = AAR.getModRefBehavior(Call); ModRefInfo MRI = createModRefInfo(MRB); // If the call doesn't access memory, we're done. @@ -141,9 +146,9 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, continue; if (!AliasAnalysis::onlyAccessesArgPointees(MRB)) { - // The call could access any memory. If that includes writes, give up. + // The call could access any memory. If that includes writes, note it. if (isModSet(MRI)) - return MAK_MayWrite; + WritesMemory = true; // If it reads, note it. if (isRefSet(MRI)) ReadsMemory = true; @@ -152,7 +157,7 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, // Check whether all pointer arguments point to local memory, and // ignore calls that only access local memory. - for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); + for (CallSite::arg_iterator CI = Call->arg_begin(), CE = Call->arg_end(); CI != CE; ++CI) { Value *Arg = *CI; if (!Arg->getType()->isPtrOrPtrVectorTy()) @@ -160,7 +165,7 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, AAMDNodes AAInfo; I->getAAMetadata(AAInfo); - MemoryLocation Loc(Arg, MemoryLocation::UnknownSize, AAInfo); + MemoryLocation Loc(Arg, LocationSize::unknown(), AAInfo); // Skip accesses to local or constant memory as they don't impact the // externally visible mod/ref behavior. @@ -168,8 +173,8 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, continue; if (isModSet(MRI)) - // Writes non-local memory. Give up. - return MAK_MayWrite; + // Writes non-local memory. + WritesMemory = true; if (isRefSet(MRI)) // Ok, it reads non-local memory. ReadsMemory = true; @@ -198,14 +203,21 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, // Any remaining instructions need to be taken seriously! Check if they // read or write memory. - if (I->mayWriteToMemory()) - // Writes memory. Just give up. - return MAK_MayWrite; + // + // Writes memory, remember that. + WritesMemory |= I->mayWriteToMemory(); // If this instruction may read memory, remember that. ReadsMemory |= I->mayReadFromMemory(); } + if (WritesMemory) { + if (!ReadsMemory) + return MAK_WriteOnly; + else + return MAK_MayWrite; + } + return ReadsMemory ? MAK_ReadOnly : MAK_ReadNone; } @@ -220,6 +232,7 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) { // Check if any of the functions in the SCC read or write memory. If they // write memory then they can't be marked readnone or readonly. bool ReadsMemory = false; + bool WritesMemory = false; for (Function *F : SCCNodes) { // Call the callable parameter to look up AA results for this function. AAResults &AAR = AARGetter(*F); @@ -234,6 +247,9 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) { case MAK_ReadOnly: ReadsMemory = true; break; + case MAK_WriteOnly: + WritesMemory = true; + break; case MAK_ReadNone: // Nothing to do! break; @@ -243,6 +259,9 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) { // Success! Functions in this SCC do not access memory, or only read memory. // Give them the appropriate attribute. bool MadeChange = false; + + assert(!(ReadsMemory && WritesMemory) && + "Function marked read-only and write-only"); for (Function *F : SCCNodes) { if (F->doesNotAccessMemory()) // Already perfect! @@ -252,16 +271,32 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) { // No change. continue; + if (F->doesNotReadMemory() && WritesMemory) + continue; + MadeChange = true; // Clear out any existing attributes. F->removeFnAttr(Attribute::ReadOnly); F->removeFnAttr(Attribute::ReadNone); + F->removeFnAttr(Attribute::WriteOnly); + + if (!WritesMemory && !ReadsMemory) { + // Clear out any "access range attributes" if readnone was deduced. + F->removeFnAttr(Attribute::ArgMemOnly); + F->removeFnAttr(Attribute::InaccessibleMemOnly); + F->removeFnAttr(Attribute::InaccessibleMemOrArgMemOnly); + } // Add in the new attribute. - F->addFnAttr(ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone); + if (WritesMemory && !ReadsMemory) + F->addFnAttr(Attribute::WriteOnly); + else + F->addFnAttr(ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone); - if (ReadsMemory) + if (WritesMemory && !ReadsMemory) + ++NumWriteOnly; + else if (ReadsMemory) ++NumReadOnly; else ++NumReadNone; @@ -1272,13 +1307,14 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) { // If all of the calls in F are identifiable and are to norecurse functions, F // is norecurse. This check also detects self-recursion as F is not currently // marked norecurse, so any called from F to F will not be marked norecurse. - for (Instruction &I : instructions(*F)) - if (auto CS = CallSite(&I)) { - Function *Callee = CS.getCalledFunction(); - if (!Callee || Callee == F || !Callee->doesNotRecurse()) - // Function calls a potentially recursive function. - return false; - } + for (auto &BB : *F) + for (auto &I : BB.instructionsWithoutDebug()) + if (auto CS = CallSite(&I)) { + Function *Callee = CS.getCalledFunction(); + if (!Callee || Callee == F || !Callee->doesNotRecurse()) + // Function calls a potentially recursive function. + return false; + } // Every call was to a non-recursive function other than this function, and // we have no indirect recursion as the SCC size is one. This function cannot @@ -1286,6 +1322,31 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) { return setDoesNotRecurse(*F); } +template <typename AARGetterT> +static bool deriveAttrsInPostOrder(SCCNodeSet &SCCNodes, AARGetterT &&AARGetter, + bool HasUnknownCall) { + bool Changed = false; + + // Bail if the SCC only contains optnone functions. + if (SCCNodes.empty()) + return Changed; + + Changed |= addArgumentReturnedAttrs(SCCNodes); + Changed |= addReadAttrs(SCCNodes, AARGetter); + Changed |= addArgumentAttrs(SCCNodes); + + // If we have no external nodes participating in the SCC, we can deduce some + // more precise attributes as well. + if (!HasUnknownCall) { + Changed |= addNoAliasAttrs(SCCNodes); + Changed |= addNonNullAttrs(SCCNodes); + Changed |= inferAttrsFromFunctionBodies(SCCNodes); + Changed |= addNoRecurseAttrs(SCCNodes); + } + + return Changed; +} + PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, @@ -1328,21 +1389,10 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C, SCCNodes.insert(&F); } - bool Changed = false; - Changed |= addArgumentReturnedAttrs(SCCNodes); - Changed |= addReadAttrs(SCCNodes, AARGetter); - Changed |= addArgumentAttrs(SCCNodes); - - // If we have no external nodes participating in the SCC, we can deduce some - // more precise attributes as well. - if (!HasUnknownCall) { - Changed |= addNoAliasAttrs(SCCNodes); - Changed |= addNonNullAttrs(SCCNodes); - Changed |= inferAttrsFromFunctionBodies(SCCNodes); - Changed |= addNoRecurseAttrs(SCCNodes); - } + if (deriveAttrsInPostOrder(SCCNodes, AARGetter, HasUnknownCall)) + return PreservedAnalyses::none(); - return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); + return PreservedAnalyses::all(); } namespace { @@ -1382,7 +1432,6 @@ Pass *llvm::createPostOrderFunctionAttrsLegacyPass() { template <typename AARGetterT> static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) { - bool Changed = false; // Fill SCCNodes with the elements of the SCC. Used for quickly looking up // whether a given CallGraphNode is in this SCC. Also track whether there are @@ -1403,24 +1452,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) { SCCNodes.insert(F); } - // Skip it if the SCC only contains optnone functions. - if (SCCNodes.empty()) - return Changed; - - Changed |= addArgumentReturnedAttrs(SCCNodes); - Changed |= addReadAttrs(SCCNodes, AARGetter); - Changed |= addArgumentAttrs(SCCNodes); - - // If we have no external nodes participating in the SCC, we can deduce some - // more precise attributes as well. - if (!ExternalNode) { - Changed |= addNoAliasAttrs(SCCNodes); - Changed |= addNonNullAttrs(SCCNodes); - Changed |= inferAttrsFromFunctionBodies(SCCNodes); - Changed |= addNoRecurseAttrs(SCCNodes); - } - - return Changed; + return deriveAttrsInPostOrder(SCCNodes, AARGetter, ExternalNode); } bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) { |