diff options
Diffstat (limited to 'contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp')
| -rw-r--r-- | contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 73 | 
1 files changed, 61 insertions, 12 deletions
diff --git a/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 4e2a82b56eec..5ccd8bc4b0fb 100644 --- a/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1,9 +1,8 @@  //===- FunctionAttrs.cpp - Pass which marks functions attributes ----------===//  // -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception  //  //===----------------------------------------------------------------------===//  // @@ -28,6 +27,7 @@  #include "llvm/Analysis/CallGraphSCCPass.h"  #include "llvm/Analysis/CaptureTracking.h"  #include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/MemoryBuiltins.h"  #include "llvm/Analysis/MemoryLocation.h"  #include "llvm/Analysis/ValueTracking.h"  #include "llvm/IR/Argument.h" @@ -76,6 +76,7 @@ STATISTIC(NumNoAlias, "Number of function returns marked noalias");  STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");  STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");  STATISTIC(NumNoUnwind, "Number of functions marked as nounwind"); +STATISTIC(NumNoFree, "Number of functions marked as nofree");  // FIXME: This is disabled by default to avoid exposing security vulnerabilities  // in C/C++ code compiled by clang: @@ -89,6 +90,10 @@ static cl::opt<bool> DisableNoUnwindInference(      "disable-nounwind-inference", cl::Hidden,      cl::desc("Stop inferring nounwind attribute during function-attrs pass")); +static cl::opt<bool> DisableNoFreeInference( +    "disable-nofree-inference", cl::Hidden, +    cl::desc("Stop inferring nofree attribute during function-attrs pass")); +  namespace {  using SCCNodeSet = SmallSetVector<Function *, 8>; @@ -256,12 +261,15 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {      }    } +  // If the SCC contains both functions that read and functions that write, then +  // we cannot add readonly attributes. +  if (ReadsMemory && WritesMemory) +    return false; +    // 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! @@ -1228,6 +1236,25 @@ static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes) {    return true;  } +/// Helper for NoFree inference predicate InstrBreaksAttribute. +static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) { +  CallSite CS(&I); +  if (!CS) +    return false; + +  Function *Callee = CS.getCalledFunction(); +  if (!Callee) +    return true; + +  if (Callee->doesNotFreeMemory()) +    return false; + +  if (SCCNodes.count(Callee) > 0) +    return false; + +  return true; +} +  /// Infer attributes from all functions in the SCC by scanning every  /// instruction for compliance to the attribute assumptions. Currently it  /// does: @@ -1281,6 +1308,29 @@ static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) {          },          /* RequiresExactDefinition= */ true}); +  if (!DisableNoFreeInference) +    // Request to infer nofree attribute for all the functions in the SCC if +    // every callsite within the SCC does not directly or indirectly free +    // memory (except for calls to functions within the SCC). Note that nofree +    // attribute suffers from derefinement - results may change depending on +    // how functions are optimized. Thus it can be inferred only from exact +    // definitions. +    AI.registerAttrInference(AttributeInferer::InferenceDescriptor{ +        Attribute::NoFree, +        // Skip functions known not to free memory. +        [](const Function &F) { return F.doesNotFreeMemory(); }, +        // Instructions that break non-deallocating assumption. +        [SCCNodes](Instruction &I) { +          return InstrBreaksNoFree(I, SCCNodes); +        }, +        [](Function &F) { +          LLVM_DEBUG(dbgs() +                     << "Adding nofree attr to fn " << F.getName() << "\n"); +          F.setDoesNotFreeMemory(); +          ++NumNoFree; +        }, +        /* RequiresExactDefinition= */ true}); +    // Perform all the requested attribute inference actions.    return AI.run(SCCNodes);  } @@ -1301,7 +1351,7 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {      return false;    Function *F = *SCCNodes.begin(); -  if (!F || F->isDeclaration() || F->doesNotRecurse()) +  if (!F || !F->hasExactDefinition() || F->doesNotRecurse())      return false;    // If all of the calls in F are identifiable and are to norecurse functions, F @@ -1323,7 +1373,8 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {  }  template <typename AARGetterT> -static bool deriveAttrsInPostOrder(SCCNodeSet &SCCNodes, AARGetterT &&AARGetter, +static bool deriveAttrsInPostOrder(SCCNodeSet &SCCNodes, +                                   AARGetterT &&AARGetter,                                     bool HasUnknownCall) {    bool Changed = false; @@ -1367,8 +1418,7 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,    bool HasUnknownCall = false;    for (LazyCallGraph::Node &N : C) {      Function &F = N.getFunction(); -    if (F.hasFnAttribute(Attribute::OptimizeNone) || -        F.hasFnAttribute(Attribute::Naked)) { +    if (F.hasOptNone() || F.hasFnAttribute(Attribute::Naked)) {        // Treat any function we're trying not to optimize as if it were an        // indirect call and omit it from the node set used below.        HasUnknownCall = true; @@ -1441,8 +1491,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {    bool ExternalNode = false;    for (CallGraphNode *I : SCC) {      Function *F = I->getFunction(); -    if (!F || F->hasFnAttribute(Attribute::OptimizeNone) || -        F->hasFnAttribute(Attribute::Naked)) { +    if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked)) {        // External node or function we're trying not to optimize - we both avoid        // transform them and avoid leveraging information they provide.        ExternalNode = true;  | 
