summaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/FunctionAttrs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/IPO/FunctionAttrs.cpp')
-rw-r--r--lib/Transforms/IPO/FunctionAttrs.cpp146
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) {