[llvm] r246476 - [FunctionAttr] Infer nonnull attributes on returns
Philip Reames via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 31 15:52:42 PDT 2015
Sorry for the breakage. Hans, thanks for fixing this.
Philip
On 08/31/2015 02:08 PM, Yaron Keren wrote:
> This may be breaking the Visual C++ builders:
>
> http://lab.llvm.org:8011/builders/lldb-x86-win7-msvc/builds/8864/steps/build/logs/stdio
>
> dbgs() requiring llvm/Support/raw_ostream.h.
>
>
>
> 2015-08-31 22:44 GMT+03:00 Philip Reames via llvm-commits
> <llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>>:
>
> Author: reames
> Date: Mon Aug 31 14:44:38 2015
> New Revision: 246476
>
> URL: http://llvm.org/viewvc/llvm-project?rev=246476&view=rev
> Log:
> [FunctionAttr] Infer nonnull attributes on returns
>
> Teach FunctionAttr to infer the nonnull attribute on return values
> of functions which never return a potentially null value. This is
> done both via a conservative local analysis for the function
> itself and a optimistic per-SCC analysis. If no function in the
> SCC returns anything which could be null (other than values from
> other functions in the SCC), we can conclude no function returned
> a null pointer. Even if some function within the SCC returns a
> null pointer, we may be able to locally conclude that some don't.
>
> Differential Revision: http://reviews.llvm.org/D9688
>
>
> Added:
> llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
> Modified:
> llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
>
> Modified: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=246476&r1=246475&r2=246476&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp Mon Aug 31
> 14:44:38 2015
> @@ -27,10 +27,12 @@
> #include "llvm/Analysis/CallGraph.h"
> #include "llvm/Analysis/CallGraphSCCPass.h"
> #include "llvm/Analysis/CaptureTracking.h"
> +#include "llvm/Analysis/ValueTracking.h"
> #include "llvm/IR/GlobalVariable.h"
> #include "llvm/IR/InstIterator.h"
> #include "llvm/IR/IntrinsicInst.h"
> #include "llvm/IR/LLVMContext.h"
> +#include "llvm/Support/Debug.h"
> #include "llvm/Analysis/TargetLibraryInfo.h"
> using namespace llvm;
>
> @@ -42,6 +44,7 @@ STATISTIC(NumNoCapture, "Number of argum
> STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
> STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
> STATISTIC(NumNoAlias, "Number of function returns marked noalias");
> +STATISTIC(NumNonNullReturn, "Number of function returns marked
> nonnull");
> STATISTIC(NumAnnotated, "Number of attributes added to library
> functions");
>
> namespace {
> @@ -67,6 +70,13 @@ namespace {
> // AddNoAliasAttrs - Deduce noalias attributes for the SCC.
> bool AddNoAliasAttrs(const CallGraphSCC &SCC);
>
> + /// \brief Does this function return null?
> + bool ReturnsNonNull(Function *F, SmallPtrSet<Function*, 8> &,
> + bool &Speculative) const;
> +
> + /// \brief Deduce nonnull attributes for the SCC.
> + bool AddNonNullAttrs(const CallGraphSCC &SCC);
> +
> // Utility methods used by inferPrototypeAttributes to add
> attributes
> // and maintain annotation statistics.
>
> @@ -832,6 +842,143 @@ bool FunctionAttrs::AddNoAliasAttrs(cons
> return MadeChange;
> }
>
> +bool FunctionAttrs::ReturnsNonNull(Function *F,
> + SmallPtrSet<Function*, 8> &SCCNodes,
> + bool &Speculative) const {
> + assert(F->getReturnType()->isPointerTy() &&
> + "nonnull only meaningful on pointer types");
> + Speculative = false;
> +
> + SmallSetVector<Value *, 8> FlowsToReturn;
> + for (BasicBlock &BB : *F)
> + if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
> + FlowsToReturn.insert(Ret->getReturnValue());
> +
> + for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
> + Value *RetVal = FlowsToReturn[i];
> +
> + // If this value is locally known to be non-null, we're good
> + if (isKnownNonNull(RetVal, TLI))
> + continue;
> +
> + // Otherwise, we need to look upwards since we can't make any
> local
> + // conclusions.
> + Instruction *RVI = dyn_cast<Instruction>(RetVal);
> + if (!RVI)
> + return false;
> + switch (RVI->getOpcode()) {
> + // Extend the analysis by looking upwards.
> + case Instruction::BitCast:
> + case Instruction::GetElementPtr:
> + case Instruction::AddrSpaceCast:
> + FlowsToReturn.insert(RVI->getOperand(0));
> + continue;
> + case Instruction::Select: {
> + SelectInst *SI = cast<SelectInst>(RVI);
> + FlowsToReturn.insert(SI->getTrueValue());
> + FlowsToReturn.insert(SI->getFalseValue());
> + continue;
> + }
> + case Instruction::PHI: {
> + PHINode *PN = cast<PHINode>(RVI);
> + for (int i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
> + FlowsToReturn.insert(PN->getIncomingValue(i));
> + continue;
> + }
> + case Instruction::Call:
> + case Instruction::Invoke: {
> + CallSite CS(RVI);
> + Function *Callee = CS.getCalledFunction();
> + // A call to a node within the SCC is assumed to return
> null until
> + // proven otherwise
> + if (Callee && SCCNodes.count(Callee)) {
> + Speculative = true;
> + continue;
> + }
> + return false;
> + }
> + default:
> + return false; // Unknown source, may be null
> + };
> + llvm_unreachable("should have either continued or returned");
> + }
> +
> + return true;
> +}
> +
> +bool FunctionAttrs::AddNonNullAttrs(const CallGraphSCC &SCC) {
> + SmallPtrSet<Function*, 8> 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)
> + SCCNodes.insert((*I)->getFunction());
> +
> + // Speculative that all functions in the SCC return only nonnull
> + // pointers. We may refute this as we analyze functions.
> + bool SCCReturnsNonNull = true;
> +
> + bool MadeChange = false;
> +
> + // Check each function in turn, determining which functions
> return nonnull
> + // pointers.
> + for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I
> != E; ++I) {
> + Function *F = (*I)->getFunction();
> +
> + if (!F || F->hasFnAttribute(Attribute::OptimizeNone))
> + // External node or node we don't want to optimize - skip it;
> + return false;
> +
> + // Already nonnull.
> + if (F->getAttributes().hasAttribute(AttributeSet::ReturnIndex,
> + Attribute::NonNull))
> + continue;
> +
> + // Definitions with weak linkage may be overridden at
> linktime, so
> + // treat them like declarations.
> + if (F->isDeclaration() || F->mayBeOverridden())
> + return false;
> +
> + // We annotate nonnull return values, which are only
> applicable to
> + // pointer types.
> + if (!F->getReturnType()->isPointerTy())
> + continue;
> +
> + bool Speculative = false;
> + if (ReturnsNonNull(F, SCCNodes, Speculative)) {
> + if (!Speculative) {
> + // Mark the function eagerly since we may discover a function
> + // which prevents us from speculating about the entire SCC
> + DEBUG(dbgs() << "Eagerly marking " << F->getName() << "
> as nonnull\n");
> + F->addAttribute(AttributeSet::ReturnIndex,
> Attribute::NonNull);
> + ++NumNonNullReturn;
> + MadeChange = true;
> + }
> + continue;
> + }
> + // At least one function returns something which could be
> null, can't
> + // speculate any more.
> + SCCReturnsNonNull = false;
> + }
> +
> + if (SCCReturnsNonNull) {
> + for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I
> != E; ++I) {
> + Function *F = (*I)->getFunction();
> + if (F->getAttributes().hasAttribute(AttributeSet::ReturnIndex,
> + Attribute::NonNull) ||
> + !F->getReturnType()->isPointerTy())
> + continue;
> +
> + DEBUG(dbgs() << "SCC marking " << F->getName() << " as
> nonnull\n");
> + F->addAttribute(AttributeSet::ReturnIndex, Attribute::NonNull);
> + ++NumNonNullReturn;
> + MadeChange = true;
> + }
> + }
> +
> + return MadeChange;
> +}
> +
> /// inferPrototypeAttributes - Analyze the name and prototype of the
> /// given function and set any applicable attributes. Returns true
> /// if any attributes were set and false otherwise.
> @@ -1707,5 +1854,6 @@ bool FunctionAttrs::runOnSCC(CallGraphSC
> Changed |= AddReadAttrs(SCC);
> Changed |= AddArgumentAttrs(SCC);
> Changed |= AddNoAliasAttrs(SCC);
> + Changed |= AddNonNullAttrs(SCC);
> return Changed;
> }
>
> Added: llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll?rev=246476&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll (added)
> +++ llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll Mon Aug 31
> 14:44:38 2015
> @@ -0,0 +1,74 @@
> +; RUN: opt -S -functionattrs %s | FileCheck %s
> +declare nonnull i8* @ret_nonnull()
> +
> +; Return a pointer trivially nonnull (call return attribute)
> +define i8* @test1() {
> +; CHECK: define nonnull i8* @test1
> + %ret = call i8* @ret_nonnull()
> + ret i8* %ret
> +}
> +
> +; Return a pointer trivially nonnull (argument attribute)
> +define i8* @test2(i8* nonnull %p) {
> +; CHECK: define nonnull i8* @test2
> + ret i8* %p
> +}
> +
> +; Given an SCC where one of the functions can not be marked nonnull,
> +; can we still mark the other one which is trivially nonnull
> +define i8* @scc_binder() {
> +; CHECK: define i8* @scc_binder
> + call i8* @test3()
> + ret i8* null
> +}
> +
> +define i8* @test3() {
> +; CHECK: define nonnull i8* @test3
> + call i8* @scc_binder()
> + %ret = call i8* @ret_nonnull()
> + ret i8* %ret
> +}
> +
> +; Given a mutual recursive set of functions, we can mark them
> +; nonnull if neither can ever return null. (In this case, they
> +; just never return period.)
> +define i8* @test4_helper() {
> +; CHECK: define noalias nonnull i8* @test4_helper
> + %ret = call i8* @test4()
> + ret i8* %ret
> +}
> +
> +define i8* @test4() {
> +; CHECK: define noalias nonnull i8* @test4
> + %ret = call i8* @test4_helper()
> + ret i8* %ret
> +}
> +
> +; Given a mutual recursive set of functions which *can* return null
> +; make sure we haven't marked them as nonnull.
> +define i8* @test5_helper() {
> +; CHECK: define noalias i8* @test5_helper
> + %ret = call i8* @test5()
> + ret i8* null
> +}
> +
> +define i8* @test5() {
> +; CHECK: define noalias i8* @test5
> + %ret = call i8* @test5_helper()
> + ret i8* %ret
> +}
> +
> +; Local analysis, but going through a self recursive phi
> +define i8* @test6() {
> +entry:
> +; CHECK: define nonnull i8* @test6
> + %ret = call i8* @ret_nonnull()
> + br label %loop
> +loop:
> + %phi = phi i8* [%ret, %entry], [%phi, %loop]
> + br i1 undef, label %loop, label %exit
> +exit:
> + ret i8* %phi
> +}
> +
> +
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150831/99e065d3/attachment.html>
More information about the llvm-commits
mailing list