reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
//===- ObjCARCAPElim.cpp - ObjC ARC Optimization --------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines ObjC ARC optimizations. ARC stands for Automatic
/// Reference Counting and is a system for managing reference counts for objects
/// in Objective C.
///
/// This specific file implements optimizations which remove extraneous
/// autorelease pools.
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//

#include "ObjCARC.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace llvm::objcarc;

#define DEBUG_TYPE "objc-arc-ap-elim"

namespace {
  /// Autorelease pool elimination.
  class ObjCARCAPElim : public ModulePass {
    void getAnalysisUsage(AnalysisUsage &AU) const override;
    bool runOnModule(Module &M) override;

    static bool MayAutorelease(ImmutableCallSite CS, unsigned Depth = 0);
    static bool OptimizeBB(BasicBlock *BB);

  public:
    static char ID;
    ObjCARCAPElim() : ModulePass(ID) {
      initializeObjCARCAPElimPass(*PassRegistry::getPassRegistry());
    }
  };
}

char ObjCARCAPElim::ID = 0;
INITIALIZE_PASS(ObjCARCAPElim,
                "objc-arc-apelim",
                "ObjC ARC autorelease pool elimination",
                false, false)

Pass *llvm::createObjCARCAPElimPass() {
  return new ObjCARCAPElim();
}

void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesCFG();
}

/// Interprocedurally determine if calls made by the given call site can
/// possibly produce autoreleases.
bool ObjCARCAPElim::MayAutorelease(ImmutableCallSite CS, unsigned Depth) {
  if (const Function *Callee = CS.getCalledFunction()) {
    if (!Callee->hasExactDefinition())
      return true;
    for (const BasicBlock &BB : *Callee) {
      for (const Instruction &I : BB)
        if (ImmutableCallSite JCS = ImmutableCallSite(&I))
          // This recursion depth limit is arbitrary. It's just great
          // enough to cover known interesting testcases.
          if (Depth < 3 &&
              !JCS.onlyReadsMemory() &&
              MayAutorelease(JCS, Depth + 1))
            return true;
    }
    return false;
  }

  return true;
}

bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) {
  bool Changed = false;

  Instruction *Push = nullptr;
  for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
    Instruction *Inst = &*I++;
    switch (GetBasicARCInstKind(Inst)) {
    case ARCInstKind::AutoreleasepoolPush:
      Push = Inst;
      break;
    case ARCInstKind::AutoreleasepoolPop:
      // If this pop matches a push and nothing in between can autorelease,
      // zap the pair.
      if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push) {
        Changed = true;
        LLVM_DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop "
                             "autorelease pair:\n"
                             "                           Pop: "
                          << *Inst << "\n"
                          << "                           Push: " << *Push
                          << "\n");
        Inst->eraseFromParent();
        Push->eraseFromParent();
      }
      Push = nullptr;
      break;
    case ARCInstKind::CallOrUser:
      if (MayAutorelease(ImmutableCallSite(Inst)))
        Push = nullptr;
      break;
    default:
      break;
    }
  }

  return Changed;
}

bool ObjCARCAPElim::runOnModule(Module &M) {
  if (!EnableARCOpts)
    return false;

  // If nothing in the Module uses ARC, don't do anything.
  if (!ModuleHasARC(M))
    return false;

  if (skipModule(M))
    return false;

  // Find the llvm.global_ctors variable, as the first step in
  // identifying the global constructors. In theory, unnecessary autorelease
  // pools could occur anywhere, but in practice it's pretty rare. Global
  // ctors are a place where autorelease pools get inserted automatically,
  // so it's pretty common for them to be unnecessary, and it's pretty
  // profitable to eliminate them.
  GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors");
  if (!GV)
    return false;

  assert(GV->hasDefinitiveInitializer() &&
         "llvm.global_ctors is uncooperative!");

  bool Changed = false;

  // Dig the constructor functions out of GV's initializer.
  ConstantArray *Init = cast<ConstantArray>(GV->getInitializer());
  for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end();
       OI != OE; ++OI) {
    Value *Op = *OI;
    // llvm.global_ctors is an array of three-field structs where the second
    // members are constructor functions.
    Function *F = dyn_cast<Function>(cast<ConstantStruct>(Op)->getOperand(1));
    // If the user used a constructor function with the wrong signature and
    // it got bitcasted or whatever, look the other way.
    if (!F)
      continue;
    // Only look at function definitions.
    if (F->isDeclaration())
      continue;
    // Only look at functions with one basic block.
    if (std::next(F->begin()) != F->end())
      continue;
    // Ok, a single-block constructor function definition. Try to optimize it.
    Changed |= OptimizeBB(&F->front());
  }

  return Changed;
}