xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- ObjCARCAPElim.cpp - ObjC ARC Optimization --------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file defines ObjC ARC optimizations. ARC stands for Automatic
110b57cec5SDimitry Andric /// Reference Counting and is a system for managing reference counts for objects
120b57cec5SDimitry Andric /// in Objective C.
130b57cec5SDimitry Andric ///
140b57cec5SDimitry Andric /// This specific file implements optimizations which remove extraneous
150b57cec5SDimitry Andric /// autorelease pools.
160b57cec5SDimitry Andric ///
170b57cec5SDimitry Andric /// WARNING: This file knows about certain library functions. It recognizes them
180b57cec5SDimitry Andric /// by name, and hardwires knowledge of their semantics.
190b57cec5SDimitry Andric ///
200b57cec5SDimitry Andric /// WARNING: This file knows about how certain Objective-C library functions are
210b57cec5SDimitry Andric /// used. Naive LLVM IR transformations which would otherwise be
220b57cec5SDimitry Andric /// behavior-preserving may break these assumptions.
230b57cec5SDimitry Andric ///
240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
27*81ad6265SDimitry Andric #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
28*81ad6265SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h"
290b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
30*81ad6265SDimitry Andric #include "llvm/IR/InstrTypes.h"
31e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
320b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
330b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
34e8d8bef9SDimitry Andric #include "llvm/Transforms/ObjCARC.h"
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric using namespace llvm::objcarc;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric #define DEBUG_TYPE "objc-arc-ap-elim"
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric namespace {
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric /// Interprocedurally determine if calls made by the given call site can
440b57cec5SDimitry Andric /// possibly produce autoreleases.
MayAutorelease(const CallBase & CB,unsigned Depth=0)45e8d8bef9SDimitry Andric bool MayAutorelease(const CallBase &CB, unsigned Depth = 0) {
465ffd83dbSDimitry Andric   if (const Function *Callee = CB.getCalledFunction()) {
470b57cec5SDimitry Andric     if (!Callee->hasExactDefinition())
480b57cec5SDimitry Andric       return true;
490b57cec5SDimitry Andric     for (const BasicBlock &BB : *Callee) {
500b57cec5SDimitry Andric       for (const Instruction &I : BB)
515ffd83dbSDimitry Andric         if (const CallBase *JCB = dyn_cast<CallBase>(&I))
520b57cec5SDimitry Andric           // This recursion depth limit is arbitrary. It's just great
530b57cec5SDimitry Andric           // enough to cover known interesting testcases.
545ffd83dbSDimitry Andric           if (Depth < 3 && !JCB->onlyReadsMemory() &&
555ffd83dbSDimitry Andric               MayAutorelease(*JCB, Depth + 1))
560b57cec5SDimitry Andric             return true;
570b57cec5SDimitry Andric     }
580b57cec5SDimitry Andric     return false;
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   return true;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
OptimizeBB(BasicBlock * BB)64e8d8bef9SDimitry Andric bool OptimizeBB(BasicBlock *BB) {
650b57cec5SDimitry Andric   bool Changed = false;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   Instruction *Push = nullptr;
68349cc55cSDimitry Andric   for (Instruction &Inst : llvm::make_early_inc_range(*BB)) {
69349cc55cSDimitry Andric     switch (GetBasicARCInstKind(&Inst)) {
700b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPush:
71349cc55cSDimitry Andric       Push = &Inst;
720b57cec5SDimitry Andric       break;
730b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPop:
740b57cec5SDimitry Andric       // If this pop matches a push and nothing in between can autorelease,
750b57cec5SDimitry Andric       // zap the pair.
76349cc55cSDimitry Andric       if (Push && cast<CallInst>(&Inst)->getArgOperand(0) == Push) {
770b57cec5SDimitry Andric         Changed = true;
780b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop "
790b57cec5SDimitry Andric                              "autorelease pair:\n"
800b57cec5SDimitry Andric                              "                           Pop: "
81349cc55cSDimitry Andric                           << Inst << "\n"
820b57cec5SDimitry Andric                           << "                           Push: " << *Push
830b57cec5SDimitry Andric                           << "\n");
84349cc55cSDimitry Andric         Inst.eraseFromParent();
850b57cec5SDimitry Andric         Push->eraseFromParent();
860b57cec5SDimitry Andric       }
870b57cec5SDimitry Andric       Push = nullptr;
880b57cec5SDimitry Andric       break;
890b57cec5SDimitry Andric     case ARCInstKind::CallOrUser:
90349cc55cSDimitry Andric       if (MayAutorelease(cast<CallBase>(Inst)))
910b57cec5SDimitry Andric         Push = nullptr;
920b57cec5SDimitry Andric       break;
930b57cec5SDimitry Andric     default:
940b57cec5SDimitry Andric       break;
950b57cec5SDimitry Andric     }
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   return Changed;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
runImpl(Module & M)101e8d8bef9SDimitry Andric bool runImpl(Module &M) {
1020b57cec5SDimitry Andric   if (!EnableARCOpts)
1030b57cec5SDimitry Andric     return false;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   // If nothing in the Module uses ARC, don't do anything.
1060b57cec5SDimitry Andric   if (!ModuleHasARC(M))
1070b57cec5SDimitry Andric     return false;
1080b57cec5SDimitry Andric   // Find the llvm.global_ctors variable, as the first step in
1090b57cec5SDimitry Andric   // identifying the global constructors. In theory, unnecessary autorelease
1100b57cec5SDimitry Andric   // pools could occur anywhere, but in practice it's pretty rare. Global
1110b57cec5SDimitry Andric   // ctors are a place where autorelease pools get inserted automatically,
1120b57cec5SDimitry Andric   // so it's pretty common for them to be unnecessary, and it's pretty
1130b57cec5SDimitry Andric   // profitable to eliminate them.
1140b57cec5SDimitry Andric   GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors");
1150b57cec5SDimitry Andric   if (!GV)
1160b57cec5SDimitry Andric     return false;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   assert(GV->hasDefinitiveInitializer() &&
1190b57cec5SDimitry Andric          "llvm.global_ctors is uncooperative!");
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   bool Changed = false;
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   // Dig the constructor functions out of GV's initializer.
1240b57cec5SDimitry Andric   ConstantArray *Init = cast<ConstantArray>(GV->getInitializer());
1250b57cec5SDimitry Andric   for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end();
1260b57cec5SDimitry Andric        OI != OE; ++OI) {
1270b57cec5SDimitry Andric     Value *Op = *OI;
1280b57cec5SDimitry Andric     // llvm.global_ctors is an array of three-field structs where the second
1290b57cec5SDimitry Andric     // members are constructor functions.
1300b57cec5SDimitry Andric     Function *F = dyn_cast<Function>(cast<ConstantStruct>(Op)->getOperand(1));
1310b57cec5SDimitry Andric     // If the user used a constructor function with the wrong signature and
1320b57cec5SDimitry Andric     // it got bitcasted or whatever, look the other way.
1330b57cec5SDimitry Andric     if (!F)
1340b57cec5SDimitry Andric       continue;
1350b57cec5SDimitry Andric     // Only look at function definitions.
1360b57cec5SDimitry Andric     if (F->isDeclaration())
1370b57cec5SDimitry Andric       continue;
1380b57cec5SDimitry Andric     // Only look at functions with one basic block.
1390b57cec5SDimitry Andric     if (std::next(F->begin()) != F->end())
1400b57cec5SDimitry Andric       continue;
1410b57cec5SDimitry Andric     // Ok, a single-block constructor function definition. Try to optimize it.
1420b57cec5SDimitry Andric     Changed |= OptimizeBB(&F->front());
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   return Changed;
1460b57cec5SDimitry Andric }
147e8d8bef9SDimitry Andric 
148e8d8bef9SDimitry Andric } // namespace
149e8d8bef9SDimitry Andric 
run(Module & M,ModuleAnalysisManager & AM)150e8d8bef9SDimitry Andric PreservedAnalyses ObjCARCAPElimPass::run(Module &M, ModuleAnalysisManager &AM) {
151e8d8bef9SDimitry Andric   if (!runImpl(M))
152e8d8bef9SDimitry Andric     return PreservedAnalyses::all();
153e8d8bef9SDimitry Andric   PreservedAnalyses PA;
154e8d8bef9SDimitry Andric   PA.preserveSet<CFGAnalyses>();
155e8d8bef9SDimitry Andric   return PA;
156e8d8bef9SDimitry Andric }
157