[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