diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/IPO/FunctionAttrs.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/contrib/llvm-project/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 7c277518b21d..7ebf265e17ba 100644 --- a/contrib/llvm-project/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/contrib/llvm-project/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -76,6 +76,7 @@ STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly"); STATISTIC(NumWriteOnlyArg, "Number of arguments marked writeonly"); STATISTIC(NumNoAlias, "Number of function returns marked noalias"); STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull"); +STATISTIC(NumNoUndefReturn, "Number of function returns marked noundef"); STATISTIC(NumNoRecurse, "Number of functions marked as norecurse"); STATISTIC(NumNoUnwind, "Number of functions marked as nounwind"); STATISTIC(NumNoFree, "Number of functions marked as nofree"); @@ -1279,6 +1280,45 @@ static void addNonNullAttrs(const SCCNodeSet &SCCNodes, } } +/// Deduce noundef attributes for the SCC. +static void addNoUndefAttrs(const SCCNodeSet &SCCNodes, + SmallSet<Function *, 8> &Changed) { + // Check each function in turn, determining which functions return noundef + // values. + for (Function *F : SCCNodes) { + // Already noundef. + if (F->getAttributes().hasRetAttr(Attribute::NoUndef)) + continue; + + // We can infer and propagate function attributes only when we know that the + // definition we'll get at link time is *exactly* the definition we see now. + // For more details, see GlobalValue::mayBeDerefined. + if (!F->hasExactDefinition()) + return; + + // MemorySanitizer assumes that the definition and declaration of a + // function will be consistent. A function with sanitize_memory attribute + // should be skipped from inference. + if (F->hasFnAttribute(Attribute::SanitizeMemory)) + continue; + + if (F->getReturnType()->isVoidTy()) + continue; + + if (all_of(*F, [](BasicBlock &BB) { + if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) { + // TODO: perform context-sensitive analysis? + return isGuaranteedNotToBeUndefOrPoison(Ret->getReturnValue()); + } + return true; + })) { + F->addRetAttr(Attribute::NoUndef); + ++NumNoUndefReturn; + Changed.insert(F); + } + } +} + namespace { /// Collects a set of attribute inference requests and performs them all in one @@ -1629,7 +1669,10 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes, for (auto &I : BB.instructionsWithoutDebug()) if (auto *CB = dyn_cast<CallBase>(&I)) { Function *Callee = CB->getCalledFunction(); - if (!Callee || Callee == F || !Callee->doesNotRecurse()) + if (!Callee || Callee == F || + (!Callee->doesNotRecurse() && + !(Callee->isDeclaration() && + Callee->hasFnAttribute(Attribute::NoCallback)))) // Function calls a potentially recursive function. return; } @@ -1785,6 +1828,7 @@ deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter, inferConvergent(Nodes.SCCNodes, Changed); addNoReturnAttrs(Nodes.SCCNodes, Changed); addWillReturn(Nodes.SCCNodes, Changed); + addNoUndefAttrs(Nodes.SCCNodes, Changed); // If we have no external nodes participating in the SCC, we can deduce some // more precise attributes as well. |
