10b57cec5SDimitry Andric //===- ObjCARCContract.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 /// This file defines late ObjC ARC optimizations. ARC stands for Automatic 100b57cec5SDimitry Andric /// Reference Counting and is a system for managing reference counts for objects 110b57cec5SDimitry Andric /// in Objective C. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric /// This specific file mainly deals with ``contracting'' multiple lower level 140b57cec5SDimitry Andric /// operations into singular higher level operations through pattern matching. 150b57cec5SDimitry Andric /// 160b57cec5SDimitry Andric /// WARNING: This file knows about certain library functions. It recognizes them 170b57cec5SDimitry Andric /// by name, and hardwires knowledge of their semantics. 180b57cec5SDimitry Andric /// 190b57cec5SDimitry Andric /// WARNING: This file knows about how certain Objective-C library functions are 200b57cec5SDimitry Andric /// used. Naive LLVM IR transformations which would otherwise be 210b57cec5SDimitry Andric /// behavior-preserving may break these assumptions. 220b57cec5SDimitry Andric /// 230b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric // TODO: ObjCARCContract could insert PHI nodes when uses aren't 260b57cec5SDimitry Andric // dominated by single calls. 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #include "ARCRuntimeEntryPoints.h" 290b57cec5SDimitry Andric #include "DependencyAnalysis.h" 300b57cec5SDimitry Andric #include "ObjCARC.h" 310b57cec5SDimitry Andric #include "ProvenanceAnalysis.h" 320b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 33e8d8bef9SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 34fe6060f1SDimitry Andric #include "llvm/Analysis/ObjCARCUtil.h" 350b57cec5SDimitry Andric #include "llvm/IR/Dominators.h" 3606c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h" 370b57cec5SDimitry Andric #include "llvm/IR/InlineAsm.h" 385ffd83dbSDimitry Andric #include "llvm/IR/InstIterator.h" 390b57cec5SDimitry Andric #include "llvm/IR/Operator.h" 40e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h" 41480093f4SDimitry Andric #include "llvm/InitializePasses.h" 42480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 430b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 440b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 45e8d8bef9SDimitry Andric #include "llvm/Transforms/ObjCARC.h" 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric using namespace llvm; 480b57cec5SDimitry Andric using namespace llvm::objcarc; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric #define DEBUG_TYPE "objc-arc-contract" 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric STATISTIC(NumPeeps, "Number of calls peephole-optimized"); 530b57cec5SDimitry Andric STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed"); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 560b57cec5SDimitry Andric // Declarations 570b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric namespace { 600b57cec5SDimitry Andric /// Late ARC optimizations 610b57cec5SDimitry Andric /// 620b57cec5SDimitry Andric /// These change the IR in a way that makes it difficult to be analyzed by 630b57cec5SDimitry Andric /// ObjCARCOpt, so it's run late. 64e8d8bef9SDimitry Andric 65e8d8bef9SDimitry Andric class ObjCARCContract { 660b57cec5SDimitry Andric bool Changed; 67fe6060f1SDimitry Andric bool CFGChanged; 68e8d8bef9SDimitry Andric AAResults *AA; 690b57cec5SDimitry Andric DominatorTree *DT; 700b57cec5SDimitry Andric ProvenanceAnalysis PA; 710b57cec5SDimitry Andric ARCRuntimeEntryPoints EP; 72fe6060f1SDimitry Andric BundledRetainClaimRVs *BundledInsts = nullptr; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric /// The inline asm string to insert between calls and RetainRV calls to make 750b57cec5SDimitry Andric /// the optimization work on targets which need it. 760b57cec5SDimitry Andric const MDString *RVInstMarker; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric /// The set of inserted objc_storeStrong calls. If at the end of walking the 790b57cec5SDimitry Andric /// function we have found no alloca instructions, these calls can be marked 800b57cec5SDimitry Andric /// "tail". 810b57cec5SDimitry Andric SmallPtrSet<CallInst *, 8> StoreStrongCalls; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric /// Returns true if we eliminated Inst. 840b57cec5SDimitry Andric bool tryToPeepholeInstruction( 850b57cec5SDimitry Andric Function &F, Instruction *Inst, inst_iterator &Iter, 860b57cec5SDimitry Andric bool &TailOkForStoreStrong, 870b57cec5SDimitry Andric const DenseMap<BasicBlock *, ColorVector> &BlockColors); 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric bool optimizeRetainCall(Function &F, Instruction *Retain); 900b57cec5SDimitry Andric 91e8d8bef9SDimitry Andric bool contractAutorelease(Function &F, Instruction *Autorelease, 92e8d8bef9SDimitry Andric ARCInstKind Class); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric void tryToContractReleaseIntoStoreStrong( 950b57cec5SDimitry Andric Instruction *Release, inst_iterator &Iter, 960b57cec5SDimitry Andric const DenseMap<BasicBlock *, ColorVector> &BlockColors); 970b57cec5SDimitry Andric 98e8d8bef9SDimitry Andric public: 99e8d8bef9SDimitry Andric bool init(Module &M); 100e8d8bef9SDimitry Andric bool run(Function &F, AAResults *AA, DominatorTree *DT); 101fe6060f1SDimitry Andric bool hasCFGChanged() const { return CFGChanged; } 102e8d8bef9SDimitry Andric }; 103e8d8bef9SDimitry Andric 104e8d8bef9SDimitry Andric class ObjCARCContractLegacyPass : public FunctionPass { 105e8d8bef9SDimitry Andric public: 1060b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 1070b57cec5SDimitry Andric bool runOnFunction(Function &F) override; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric static char ID; 110e8d8bef9SDimitry Andric ObjCARCContractLegacyPass() : FunctionPass(ID) { 111e8d8bef9SDimitry Andric initializeObjCARCContractLegacyPassPass(*PassRegistry::getPassRegistry()); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric }; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1170b57cec5SDimitry Andric // Implementation 1180b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric /// Turn objc_retain into objc_retainAutoreleasedReturnValue if the operand is a 1210b57cec5SDimitry Andric /// return value. We do this late so we do not disrupt the dataflow analysis in 1220b57cec5SDimitry Andric /// ObjCARCOpt. 1230b57cec5SDimitry Andric bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) { 1245ffd83dbSDimitry Andric const auto *Call = dyn_cast<CallBase>(GetArgRCIdentityRoot(Retain)); 1250b57cec5SDimitry Andric if (!Call) 1260b57cec5SDimitry Andric return false; 1270b57cec5SDimitry Andric if (Call->getParent() != Retain->getParent()) 1280b57cec5SDimitry Andric return false; 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // Check that the call is next to the retain. 1310b57cec5SDimitry Andric BasicBlock::const_iterator I = ++Call->getIterator(); 1320b57cec5SDimitry Andric while (IsNoopInstruction(&*I)) 1330b57cec5SDimitry Andric ++I; 1340b57cec5SDimitry Andric if (&*I != Retain) 1350b57cec5SDimitry Andric return false; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric // Turn it to an objc_retainAutoreleasedReturnValue. 1380b57cec5SDimitry Andric Changed = true; 1390b57cec5SDimitry Andric ++NumPeeps; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric LLVM_DEBUG( 1420b57cec5SDimitry Andric dbgs() << "Transforming objc_retain => " 1430b57cec5SDimitry Andric "objc_retainAutoreleasedReturnValue since the operand is a " 1440b57cec5SDimitry Andric "return value.\nOld: " 1450b57cec5SDimitry Andric << *Retain << "\n"); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // We do not have to worry about tail calls/does not throw since 1480b57cec5SDimitry Andric // retain/retainRV have the same properties. 1490b57cec5SDimitry Andric Function *Decl = EP.get(ARCRuntimeEntryPointKind::RetainRV); 1500b57cec5SDimitry Andric cast<CallInst>(Retain)->setCalledFunction(Decl); 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "New: " << *Retain << "\n"); 1530b57cec5SDimitry Andric return true; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric /// Merge an autorelease with a retain into a fused call. 157e8d8bef9SDimitry Andric bool ObjCARCContract::contractAutorelease(Function &F, Instruction *Autorelease, 158e8d8bef9SDimitry Andric ARCInstKind Class) { 1590b57cec5SDimitry Andric const Value *Arg = GetArgRCIdentityRoot(Autorelease); 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // Check that there are no instructions between the retain and the autorelease 1620b57cec5SDimitry Andric // (such as an autorelease_pop) which may change the count. 163e8d8bef9SDimitry Andric DependenceKind DK = Class == ARCInstKind::AutoreleaseRV 164e8d8bef9SDimitry Andric ? RetainAutoreleaseRVDep 165e8d8bef9SDimitry Andric : RetainAutoreleaseDep; 166e8d8bef9SDimitry Andric auto *Retain = dyn_cast_or_null<CallInst>( 167e8d8bef9SDimitry Andric findSingleDependency(DK, Arg, Autorelease->getParent(), Autorelease, PA)); 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric if (!Retain || GetBasicARCInstKind(Retain) != ARCInstKind::Retain || 1700b57cec5SDimitry Andric GetArgRCIdentityRoot(Retain) != Arg) 1710b57cec5SDimitry Andric return false; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric Changed = true; 1740b57cec5SDimitry Andric ++NumPeeps; 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Fusing retain/autorelease!\n" 1770b57cec5SDimitry Andric " Autorelease:" 1780b57cec5SDimitry Andric << *Autorelease 1790b57cec5SDimitry Andric << "\n" 1800b57cec5SDimitry Andric " Retain: " 1810b57cec5SDimitry Andric << *Retain << "\n"); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric Function *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV 1840b57cec5SDimitry Andric ? ARCRuntimeEntryPointKind::RetainAutoreleaseRV 1850b57cec5SDimitry Andric : ARCRuntimeEntryPointKind::RetainAutorelease); 1860b57cec5SDimitry Andric Retain->setCalledFunction(Decl); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " New RetainAutorelease: " << *Retain << "\n"); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric EraseInstruction(Autorelease); 1910b57cec5SDimitry Andric return true; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric static StoreInst *findSafeStoreForStoreStrongContraction(LoadInst *Load, 1950b57cec5SDimitry Andric Instruction *Release, 1960b57cec5SDimitry Andric ProvenanceAnalysis &PA, 197e8d8bef9SDimitry Andric AAResults *AA) { 1980b57cec5SDimitry Andric StoreInst *Store = nullptr; 1990b57cec5SDimitry Andric bool SawRelease = false; 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric // Get the location associated with Load. 2020b57cec5SDimitry Andric MemoryLocation Loc = MemoryLocation::get(Load); 2030b57cec5SDimitry Andric auto *LocPtr = Loc.Ptr->stripPointerCasts(); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric // Walk down to find the store and the release, which may be in either order. 2060b57cec5SDimitry Andric for (auto I = std::next(BasicBlock::iterator(Load)), 2070b57cec5SDimitry Andric E = Load->getParent()->end(); 2080b57cec5SDimitry Andric I != E; ++I) { 2090b57cec5SDimitry Andric // If we found the store we were looking for and saw the release, 2100b57cec5SDimitry Andric // break. There is no more work to be done. 2110b57cec5SDimitry Andric if (Store && SawRelease) 2120b57cec5SDimitry Andric break; 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric // Now we know that we have not seen either the store or the release. If I 2150b57cec5SDimitry Andric // is the release, mark that we saw the release and continue. 2160b57cec5SDimitry Andric Instruction *Inst = &*I; 2170b57cec5SDimitry Andric if (Inst == Release) { 2180b57cec5SDimitry Andric SawRelease = true; 2190b57cec5SDimitry Andric continue; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric // Otherwise, we check if Inst is a "good" store. Grab the instruction class 2230b57cec5SDimitry Andric // of Inst. 2240b57cec5SDimitry Andric ARCInstKind Class = GetBasicARCInstKind(Inst); 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric // If we have seen the store, but not the release... 2270b57cec5SDimitry Andric if (Store) { 2280b57cec5SDimitry Andric // We need to make sure that it is safe to move the release from its 2290b57cec5SDimitry Andric // current position to the store. This implies proving that any 2300b57cec5SDimitry Andric // instruction in between Store and the Release conservatively can not use 2310b57cec5SDimitry Andric // the RCIdentityRoot of Release. If we can prove we can ignore Inst, so 2320b57cec5SDimitry Andric // continue... 2330b57cec5SDimitry Andric if (!CanUse(Inst, Load, PA, Class)) { 2340b57cec5SDimitry Andric continue; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // Otherwise, be conservative and return nullptr. 2380b57cec5SDimitry Andric return nullptr; 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 241349cc55cSDimitry Andric // Ok, now we know we have not seen a store yet. 242349cc55cSDimitry Andric 243349cc55cSDimitry Andric // If Inst is a retain, we don't care about it as it doesn't prevent moving 244349cc55cSDimitry Andric // the load to the store. 245349cc55cSDimitry Andric // 246349cc55cSDimitry Andric // TODO: This is one area where the optimization could be made more 247349cc55cSDimitry Andric // aggressive. 248349cc55cSDimitry Andric if (IsRetain(Class)) 249349cc55cSDimitry Andric continue; 250349cc55cSDimitry Andric 251349cc55cSDimitry Andric // See if Inst can write to our load location, if it can not, just ignore 252349cc55cSDimitry Andric // the instruction. 2530b57cec5SDimitry Andric if (!isModSet(AA->getModRefInfo(Inst, Loc))) 2540b57cec5SDimitry Andric continue; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric Store = dyn_cast<StoreInst>(Inst); 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric // If Inst can, then check if Inst is a simple store. If Inst is not a 2590b57cec5SDimitry Andric // store or a store that is not simple, then we have some we do not 2600b57cec5SDimitry Andric // understand writing to this memory implying we can not move the load 2610b57cec5SDimitry Andric // over the write to any subsequent store that we may find. 2620b57cec5SDimitry Andric if (!Store || !Store->isSimple()) 2630b57cec5SDimitry Andric return nullptr; 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric // Then make sure that the pointer we are storing to is Ptr. If so, we 2660b57cec5SDimitry Andric // found our Store! 2670b57cec5SDimitry Andric if (Store->getPointerOperand()->stripPointerCasts() == LocPtr) 2680b57cec5SDimitry Andric continue; 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // Otherwise, we have an unknown store to some other ptr that clobbers 2710b57cec5SDimitry Andric // Loc.Ptr. Bail! 2720b57cec5SDimitry Andric return nullptr; 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric // If we did not find the store or did not see the release, fail. 2760b57cec5SDimitry Andric if (!Store || !SawRelease) 2770b57cec5SDimitry Andric return nullptr; 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric // We succeeded! 2800b57cec5SDimitry Andric return Store; 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric static Instruction * 2840b57cec5SDimitry Andric findRetainForStoreStrongContraction(Value *New, StoreInst *Store, 2850b57cec5SDimitry Andric Instruction *Release, 2860b57cec5SDimitry Andric ProvenanceAnalysis &PA) { 2870b57cec5SDimitry Andric // Walk up from the Store to find the retain. 2880b57cec5SDimitry Andric BasicBlock::iterator I = Store->getIterator(); 2890b57cec5SDimitry Andric BasicBlock::iterator Begin = Store->getParent()->begin(); 2900b57cec5SDimitry Andric while (I != Begin && GetBasicARCInstKind(&*I) != ARCInstKind::Retain) { 2910b57cec5SDimitry Andric Instruction *Inst = &*I; 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric // It is only safe to move the retain to the store if we can prove 2940b57cec5SDimitry Andric // conservatively that nothing besides the release can decrement reference 2950b57cec5SDimitry Andric // counts in between the retain and the store. 2960b57cec5SDimitry Andric if (CanDecrementRefCount(Inst, New, PA) && Inst != Release) 2970b57cec5SDimitry Andric return nullptr; 2980b57cec5SDimitry Andric --I; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric Instruction *Retain = &*I; 3010b57cec5SDimitry Andric if (GetBasicARCInstKind(Retain) != ARCInstKind::Retain) 3020b57cec5SDimitry Andric return nullptr; 3030b57cec5SDimitry Andric if (GetArgRCIdentityRoot(Retain) != New) 3040b57cec5SDimitry Andric return nullptr; 3050b57cec5SDimitry Andric return Retain; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric /// Attempt to merge an objc_release with a store, load, and objc_retain to form 3090b57cec5SDimitry Andric /// an objc_storeStrong. An objc_storeStrong: 3100b57cec5SDimitry Andric /// 3110b57cec5SDimitry Andric /// objc_storeStrong(i8** %old_ptr, i8* new_value) 3120b57cec5SDimitry Andric /// 3130b57cec5SDimitry Andric /// is equivalent to the following IR sequence: 3140b57cec5SDimitry Andric /// 3150b57cec5SDimitry Andric /// ; Load old value. 3160b57cec5SDimitry Andric /// %old_value = load i8** %old_ptr (1) 3170b57cec5SDimitry Andric /// 3180b57cec5SDimitry Andric /// ; Increment the new value and then release the old value. This must occur 3190b57cec5SDimitry Andric /// ; in order in case old_value releases new_value in its destructor causing 3200b57cec5SDimitry Andric /// ; us to potentially have a dangling ptr. 3210b57cec5SDimitry Andric /// tail call i8* @objc_retain(i8* %new_value) (2) 3220b57cec5SDimitry Andric /// tail call void @objc_release(i8* %old_value) (3) 3230b57cec5SDimitry Andric /// 3240b57cec5SDimitry Andric /// ; Store the new_value into old_ptr 3250b57cec5SDimitry Andric /// store i8* %new_value, i8** %old_ptr (4) 3260b57cec5SDimitry Andric /// 3270b57cec5SDimitry Andric /// The safety of this optimization is based around the following 3280b57cec5SDimitry Andric /// considerations: 3290b57cec5SDimitry Andric /// 3300b57cec5SDimitry Andric /// 1. We are forming the store strong at the store. Thus to perform this 3310b57cec5SDimitry Andric /// optimization it must be safe to move the retain, load, and release to 3320b57cec5SDimitry Andric /// (4). 3330b57cec5SDimitry Andric /// 2. We need to make sure that any re-orderings of (1), (2), (3), (4) are 3340b57cec5SDimitry Andric /// safe. 3350b57cec5SDimitry Andric void ObjCARCContract::tryToContractReleaseIntoStoreStrong( 3360b57cec5SDimitry Andric Instruction *Release, inst_iterator &Iter, 3370b57cec5SDimitry Andric const DenseMap<BasicBlock *, ColorVector> &BlockColors) { 3380b57cec5SDimitry Andric // See if we are releasing something that we just loaded. 3390b57cec5SDimitry Andric auto *Load = dyn_cast<LoadInst>(GetArgRCIdentityRoot(Release)); 3400b57cec5SDimitry Andric if (!Load || !Load->isSimple()) 3410b57cec5SDimitry Andric return; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric // For now, require everything to be in one basic block. 3440b57cec5SDimitry Andric BasicBlock *BB = Release->getParent(); 3450b57cec5SDimitry Andric if (Load->getParent() != BB) 3460b57cec5SDimitry Andric return; 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric // First scan down the BB from Load, looking for a store of the RCIdentityRoot 3490b57cec5SDimitry Andric // of Load's 3500b57cec5SDimitry Andric StoreInst *Store = 3510b57cec5SDimitry Andric findSafeStoreForStoreStrongContraction(Load, Release, PA, AA); 3520b57cec5SDimitry Andric // If we fail, bail. 3530b57cec5SDimitry Andric if (!Store) 3540b57cec5SDimitry Andric return; 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric // Then find what new_value's RCIdentity Root is. 3570b57cec5SDimitry Andric Value *New = GetRCIdentityRoot(Store->getValueOperand()); 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric // Then walk up the BB and look for a retain on New without any intervening 3600b57cec5SDimitry Andric // instructions which conservatively might decrement ref counts. 3610b57cec5SDimitry Andric Instruction *Retain = 3620b57cec5SDimitry Andric findRetainForStoreStrongContraction(New, Store, Release, PA); 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric // If we fail, bail. 3650b57cec5SDimitry Andric if (!Retain) 3660b57cec5SDimitry Andric return; 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric Changed = true; 3690b57cec5SDimitry Andric ++NumStoreStrongs; 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric LLVM_DEBUG( 3720b57cec5SDimitry Andric llvm::dbgs() << " Contracting retain, release into objc_storeStrong.\n" 3730b57cec5SDimitry Andric << " Old:\n" 3740b57cec5SDimitry Andric << " Store: " << *Store << "\n" 3750b57cec5SDimitry Andric << " Release: " << *Release << "\n" 3760b57cec5SDimitry Andric << " Retain: " << *Retain << "\n" 3770b57cec5SDimitry Andric << " Load: " << *Load << "\n"); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric LLVMContext &C = Release->getContext(); 3800b57cec5SDimitry Andric Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C)); 3810b57cec5SDimitry Andric Type *I8XX = PointerType::getUnqual(I8X); 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric Value *Args[] = { Load->getPointerOperand(), New }; 3840b57cec5SDimitry Andric if (Args[0]->getType() != I8XX) 385*0fca6ea1SDimitry Andric Args[0] = new BitCastInst(Args[0], I8XX, "", Store->getIterator()); 3860b57cec5SDimitry Andric if (Args[1]->getType() != I8X) 387*0fca6ea1SDimitry Andric Args[1] = new BitCastInst(Args[1], I8X, "", Store->getIterator()); 3880b57cec5SDimitry Andric Function *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong); 389*0fca6ea1SDimitry Andric CallInst *StoreStrong = objcarc::createCallInstWithColors( 390*0fca6ea1SDimitry Andric Decl, Args, "", Store->getIterator(), BlockColors); 3910b57cec5SDimitry Andric StoreStrong->setDoesNotThrow(); 3920b57cec5SDimitry Andric StoreStrong->setDebugLoc(Store->getDebugLoc()); 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric // We can't set the tail flag yet, because we haven't yet determined 3950b57cec5SDimitry Andric // whether there are any escaping allocas. Remember this call, so that 3960b57cec5SDimitry Andric // we can set the tail flag once we know it's safe. 3970b57cec5SDimitry Andric StoreStrongCalls.insert(StoreStrong); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << " New Store Strong: " << *StoreStrong 4000b57cec5SDimitry Andric << "\n"); 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric if (&*Iter == Retain) ++Iter; 4030b57cec5SDimitry Andric if (&*Iter == Store) ++Iter; 4040b57cec5SDimitry Andric Store->eraseFromParent(); 4050b57cec5SDimitry Andric Release->eraseFromParent(); 4060b57cec5SDimitry Andric EraseInstruction(Retain); 4070b57cec5SDimitry Andric if (Load->use_empty()) 4080b57cec5SDimitry Andric Load->eraseFromParent(); 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric bool ObjCARCContract::tryToPeepholeInstruction( 4120b57cec5SDimitry Andric Function &F, Instruction *Inst, inst_iterator &Iter, 413e8d8bef9SDimitry Andric bool &TailOkForStoreStrongs, 4140b57cec5SDimitry Andric const DenseMap<BasicBlock *, ColorVector> &BlockColors) { 4150b57cec5SDimitry Andric // Only these library routines return their argument. In particular, 4160b57cec5SDimitry Andric // objc_retainBlock does not necessarily return its argument. 4170b57cec5SDimitry Andric ARCInstKind Class = GetBasicARCInstKind(Inst); 4180b57cec5SDimitry Andric switch (Class) { 4190b57cec5SDimitry Andric case ARCInstKind::FusedRetainAutorelease: 4200b57cec5SDimitry Andric case ARCInstKind::FusedRetainAutoreleaseRV: 4210b57cec5SDimitry Andric return false; 4220b57cec5SDimitry Andric case ARCInstKind::Autorelease: 4230b57cec5SDimitry Andric case ARCInstKind::AutoreleaseRV: 424e8d8bef9SDimitry Andric return contractAutorelease(F, Inst, Class); 4250b57cec5SDimitry Andric case ARCInstKind::Retain: 4260b57cec5SDimitry Andric // Attempt to convert retains to retainrvs if they are next to function 4270b57cec5SDimitry Andric // calls. 4280b57cec5SDimitry Andric if (!optimizeRetainCall(F, Inst)) 4290b57cec5SDimitry Andric return false; 4300b57cec5SDimitry Andric // If we succeed in our optimization, fall through. 431bdd1243dSDimitry Andric [[fallthrough]]; 4320b57cec5SDimitry Andric case ARCInstKind::RetainRV: 43304eeddc0SDimitry Andric case ARCInstKind::UnsafeClaimRV: { 4341fd87a68SDimitry Andric // Return true if this is a bundled retainRV/claimRV call, which is always 4351fd87a68SDimitry Andric // redundant with the attachedcall in the bundle, and is going to be erased 4361fd87a68SDimitry Andric // at the end of this pass. This avoids undoing objc-arc-expand and 437349cc55cSDimitry Andric // replacing uses of the retainRV/claimRV call's argument with its result. 4381fd87a68SDimitry Andric if (BundledInsts->contains(Inst)) 4391fd87a68SDimitry Andric return true; 4401fd87a68SDimitry Andric 4411fd87a68SDimitry Andric // If this isn't a bundled call, and the target doesn't need a special 4421fd87a68SDimitry Andric // inline-asm marker, we're done: return now, and undo objc-arc-expand. 443349cc55cSDimitry Andric if (!RVInstMarker) 444fe6060f1SDimitry Andric return false; 445fe6060f1SDimitry Andric 4461fd87a68SDimitry Andric // The target needs a special inline-asm marker. Insert it. 4471fd87a68SDimitry Andric 4480b57cec5SDimitry Andric BasicBlock::iterator BBI = Inst->getIterator(); 4490b57cec5SDimitry Andric BasicBlock *InstParent = Inst->getParent(); 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric // Step up to see if the call immediately precedes the RV call. 4520b57cec5SDimitry Andric // If it's an invoke, we have to cross a block boundary. And we have 4530b57cec5SDimitry Andric // to carefully dodge no-op instructions. 4540b57cec5SDimitry Andric do { 4550b57cec5SDimitry Andric if (BBI == InstParent->begin()) { 4560b57cec5SDimitry Andric BasicBlock *Pred = InstParent->getSinglePredecessor(); 4570b57cec5SDimitry Andric if (!Pred) 4580b57cec5SDimitry Andric goto decline_rv_optimization; 4590b57cec5SDimitry Andric BBI = Pred->getTerminator()->getIterator(); 4600b57cec5SDimitry Andric break; 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric --BBI; 4630b57cec5SDimitry Andric } while (IsNoopInstruction(&*BBI)); 4640b57cec5SDimitry Andric 465e8d8bef9SDimitry Andric if (GetRCIdentityRoot(&*BBI) == GetArgRCIdentityRoot(Inst)) { 4660b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Adding inline asm marker for the return value " 4670b57cec5SDimitry Andric "optimization.\n"); 4680b57cec5SDimitry Andric Changed = true; 4690b57cec5SDimitry Andric InlineAsm *IA = 4700b57cec5SDimitry Andric InlineAsm::get(FunctionType::get(Type::getVoidTy(Inst->getContext()), 4710b57cec5SDimitry Andric /*isVarArg=*/false), 4720b57cec5SDimitry Andric RVInstMarker->getString(), 4730b57cec5SDimitry Andric /*Constraints=*/"", /*hasSideEffects=*/true); 4740b57cec5SDimitry Andric 475*0fca6ea1SDimitry Andric objcarc::createCallInstWithColors(IA, std::nullopt, "", 476*0fca6ea1SDimitry Andric Inst->getIterator(), BlockColors); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric decline_rv_optimization: 4790b57cec5SDimitry Andric return false; 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric case ARCInstKind::InitWeak: { 4820b57cec5SDimitry Andric // objc_initWeak(p, null) => *p = null 4830b57cec5SDimitry Andric CallInst *CI = cast<CallInst>(Inst); 4840b57cec5SDimitry Andric if (IsNullOrUndef(CI->getArgOperand(1))) { 4850b57cec5SDimitry Andric Value *Null = ConstantPointerNull::get(cast<PointerType>(CI->getType())); 4860b57cec5SDimitry Andric Changed = true; 487*0fca6ea1SDimitry Andric new StoreInst(Null, CI->getArgOperand(0), CI->getIterator()); 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n" 4900b57cec5SDimitry Andric << " New = " << *Null << "\n"); 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric CI->replaceAllUsesWith(Null); 4930b57cec5SDimitry Andric CI->eraseFromParent(); 4940b57cec5SDimitry Andric } 4950b57cec5SDimitry Andric return true; 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric case ARCInstKind::Release: 4980b57cec5SDimitry Andric // Try to form an objc store strong from our release. If we fail, there is 4990b57cec5SDimitry Andric // nothing further to do below, so continue. 5000b57cec5SDimitry Andric tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors); 5010b57cec5SDimitry Andric return true; 5020b57cec5SDimitry Andric case ARCInstKind::User: 5030b57cec5SDimitry Andric // Be conservative if the function has any alloca instructions. 5040b57cec5SDimitry Andric // Technically we only care about escaping alloca instructions, 5050b57cec5SDimitry Andric // but this is sufficient to handle some interesting cases. 5060b57cec5SDimitry Andric if (isa<AllocaInst>(Inst)) 5070b57cec5SDimitry Andric TailOkForStoreStrongs = false; 5080b57cec5SDimitry Andric return true; 5090b57cec5SDimitry Andric case ARCInstKind::IntrinsicUser: 5100b57cec5SDimitry Andric // Remove calls to @llvm.objc.clang.arc.use(...). 5115ffd83dbSDimitry Andric Changed = true; 5120b57cec5SDimitry Andric Inst->eraseFromParent(); 5130b57cec5SDimitry Andric return true; 5140b57cec5SDimitry Andric default: 515fe6060f1SDimitry Andric if (auto *CI = dyn_cast<CallInst>(Inst)) 516fe6060f1SDimitry Andric if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) { 517fe6060f1SDimitry Andric // Remove calls to @llvm.objc.clang.arc.noop.use(...). 518fe6060f1SDimitry Andric Changed = true; 519fe6060f1SDimitry Andric CI->eraseFromParent(); 520fe6060f1SDimitry Andric } 5210b57cec5SDimitry Andric return true; 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5260b57cec5SDimitry Andric // Top Level Driver 5270b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5280b57cec5SDimitry Andric 529e8d8bef9SDimitry Andric bool ObjCARCContract::init(Module &M) { 530e8d8bef9SDimitry Andric EP.init(&M); 531e8d8bef9SDimitry Andric 532e8d8bef9SDimitry Andric // Initialize RVInstMarker. 533fe6060f1SDimitry Andric RVInstMarker = getRVInstMarker(M); 534e8d8bef9SDimitry Andric 535e8d8bef9SDimitry Andric return false; 536e8d8bef9SDimitry Andric } 537e8d8bef9SDimitry Andric 538e8d8bef9SDimitry Andric bool ObjCARCContract::run(Function &F, AAResults *A, DominatorTree *D) { 5390b57cec5SDimitry Andric if (!EnableARCOpts) 5400b57cec5SDimitry Andric return false; 5410b57cec5SDimitry Andric 542fe6060f1SDimitry Andric Changed = CFGChanged = false; 543e8d8bef9SDimitry Andric AA = A; 544e8d8bef9SDimitry Andric DT = D; 545e8d8bef9SDimitry Andric PA.setAA(A); 5461fd87a68SDimitry Andric BundledRetainClaimRVs BRV(/*ContractPass=*/true); 547fe6060f1SDimitry Andric BundledInsts = &BRV; 548fe6060f1SDimitry Andric 549fe6060f1SDimitry Andric std::pair<bool, bool> R = BundledInsts->insertAfterInvokes(F, DT); 550fe6060f1SDimitry Andric Changed |= R.first; 551fe6060f1SDimitry Andric CFGChanged |= R.second; 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric DenseMap<BasicBlock *, ColorVector> BlockColors; 5540b57cec5SDimitry Andric if (F.hasPersonalityFn() && 5550b57cec5SDimitry Andric isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) 5560b57cec5SDimitry Andric BlockColors = colorEHFunclets(F); 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "**** ObjCARC Contract ****\n"); 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric // Track whether it's ok to mark objc_storeStrong calls with the "tail" 5610b57cec5SDimitry Andric // keyword. Be conservative if the function has variadic arguments. 5620b57cec5SDimitry Andric // It seems that functions which "return twice" are also unsafe for the 5630b57cec5SDimitry Andric // "tail" argument, because they are setjmp, which could need to 5640b57cec5SDimitry Andric // return to an earlier stack state. 5650b57cec5SDimitry Andric bool TailOkForStoreStrongs = 5660b57cec5SDimitry Andric !F.isVarArg() && !F.callsFunctionThatReturnsTwice(); 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric // For ObjC library calls which return their argument, replace uses of the 5690b57cec5SDimitry Andric // argument with uses of the call return value, if it dominates the use. This 5700b57cec5SDimitry Andric // reduces register pressure. 5710b57cec5SDimitry Andric for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) { 5720b57cec5SDimitry Andric Instruction *Inst = &*I++; 5730b57cec5SDimitry Andric 5740b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Visiting: " << *Inst << "\n"); 5750b57cec5SDimitry Andric 576fe6060f1SDimitry Andric if (auto *CI = dyn_cast<CallInst>(Inst)) 577fe6060f1SDimitry Andric if (objcarc::hasAttachedCallOpBundle(CI)) { 578*0fca6ea1SDimitry Andric BundledInsts->insertRVCallWithColors(I->getIterator(), CI, BlockColors); 579fe6060f1SDimitry Andric --I; 580fe6060f1SDimitry Andric Changed = true; 581fe6060f1SDimitry Andric } 582fe6060f1SDimitry Andric 5830b57cec5SDimitry Andric // First try to peephole Inst. If there is nothing further we can do in 5840b57cec5SDimitry Andric // terms of undoing objc-arc-expand, process the next inst. 585e8d8bef9SDimitry Andric if (tryToPeepholeInstruction(F, Inst, I, TailOkForStoreStrongs, 586e8d8bef9SDimitry Andric BlockColors)) 5870b57cec5SDimitry Andric continue; 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric // Otherwise, try to undo objc-arc-expand. 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric // Don't use GetArgRCIdentityRoot because we don't want to look through bitcasts 5920b57cec5SDimitry Andric // and such; to do the replacement, the argument must have type i8*. 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric // Function for replacing uses of Arg dominated by Inst. 5955ffd83dbSDimitry Andric auto ReplaceArgUses = [Inst, this](Value *Arg) { 5960b57cec5SDimitry Andric // If we're compiling bugpointed code, don't get in trouble. 5970b57cec5SDimitry Andric if (!isa<Instruction>(Arg) && !isa<Argument>(Arg)) 5980b57cec5SDimitry Andric return; 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric // Look through the uses of the pointer. 6010b57cec5SDimitry Andric for (Value::use_iterator UI = Arg->use_begin(), UE = Arg->use_end(); 6020b57cec5SDimitry Andric UI != UE; ) { 6030b57cec5SDimitry Andric // Increment UI now, because we may unlink its element. 6040b57cec5SDimitry Andric Use &U = *UI++; 6050b57cec5SDimitry Andric unsigned OperandNo = U.getOperandNo(); 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric // If the call's return value dominates a use of the call's argument 6080b57cec5SDimitry Andric // value, rewrite the use to use the return value. We check for 6090b57cec5SDimitry Andric // reachability here because an unreachable call is considered to 6100b57cec5SDimitry Andric // trivially dominate itself, which would lead us to rewriting its 6110b57cec5SDimitry Andric // argument in terms of its return value, which would lead to 6120b57cec5SDimitry Andric // infinite loops in GetArgRCIdentityRoot. 6130b57cec5SDimitry Andric if (!DT->isReachableFromEntry(U) || !DT->dominates(Inst, U)) 6140b57cec5SDimitry Andric continue; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric Changed = true; 6170b57cec5SDimitry Andric Instruction *Replacement = Inst; 6180b57cec5SDimitry Andric Type *UseTy = U.get()->getType(); 6190b57cec5SDimitry Andric if (PHINode *PHI = dyn_cast<PHINode>(U.getUser())) { 6200b57cec5SDimitry Andric // For PHI nodes, insert the bitcast in the predecessor block. 6210b57cec5SDimitry Andric unsigned ValNo = PHINode::getIncomingValueNumForOperand(OperandNo); 6220b57cec5SDimitry Andric BasicBlock *IncomingBB = PHI->getIncomingBlock(ValNo); 6230b57cec5SDimitry Andric if (Replacement->getType() != UseTy) { 6240b57cec5SDimitry Andric // A catchswitch is both a pad and a terminator, meaning a basic 6250b57cec5SDimitry Andric // block with a catchswitch has no insertion point. Keep going up 6260b57cec5SDimitry Andric // the dominator tree until we find a non-catchswitch. 6270b57cec5SDimitry Andric BasicBlock *InsertBB = IncomingBB; 6280b57cec5SDimitry Andric while (isa<CatchSwitchInst>(InsertBB->getFirstNonPHI())) { 6290b57cec5SDimitry Andric InsertBB = DT->getNode(InsertBB)->getIDom()->getBlock(); 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric assert(DT->dominates(Inst, &InsertBB->back()) && 6330b57cec5SDimitry Andric "Invalid insertion point for bitcast"); 634*0fca6ea1SDimitry Andric Replacement = new BitCastInst(Replacement, UseTy, "", 635*0fca6ea1SDimitry Andric InsertBB->back().getIterator()); 6360b57cec5SDimitry Andric } 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric // While we're here, rewrite all edges for this PHI, rather 6390b57cec5SDimitry Andric // than just one use at a time, to minimize the number of 6400b57cec5SDimitry Andric // bitcasts we emit. 6410b57cec5SDimitry Andric for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) 6420b57cec5SDimitry Andric if (PHI->getIncomingBlock(i) == IncomingBB) { 6430b57cec5SDimitry Andric // Keep the UI iterator valid. 6440b57cec5SDimitry Andric if (UI != UE && 6450b57cec5SDimitry Andric &PHI->getOperandUse( 6460b57cec5SDimitry Andric PHINode::getOperandNumForIncomingValue(i)) == &*UI) 6470b57cec5SDimitry Andric ++UI; 6480b57cec5SDimitry Andric PHI->setIncomingValue(i, Replacement); 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric } else { 6510b57cec5SDimitry Andric if (Replacement->getType() != UseTy) 652*0fca6ea1SDimitry Andric Replacement = 653*0fca6ea1SDimitry Andric new BitCastInst(Replacement, UseTy, "", 654*0fca6ea1SDimitry Andric cast<Instruction>(U.getUser())->getIterator()); 6550b57cec5SDimitry Andric U.set(Replacement); 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric }; 6590b57cec5SDimitry Andric 6600b57cec5SDimitry Andric Value *Arg = cast<CallInst>(Inst)->getArgOperand(0); 6610b57cec5SDimitry Andric Value *OrigArg = Arg; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric // TODO: Change this to a do-while. 6640b57cec5SDimitry Andric for (;;) { 6650b57cec5SDimitry Andric ReplaceArgUses(Arg); 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric // If Arg is a no-op casted pointer, strip one level of casts and iterate. 6680b57cec5SDimitry Andric if (const BitCastInst *BI = dyn_cast<BitCastInst>(Arg)) 6690b57cec5SDimitry Andric Arg = BI->getOperand(0); 6700b57cec5SDimitry Andric else if (isa<GEPOperator>(Arg) && 6710b57cec5SDimitry Andric cast<GEPOperator>(Arg)->hasAllZeroIndices()) 6720b57cec5SDimitry Andric Arg = cast<GEPOperator>(Arg)->getPointerOperand(); 6730b57cec5SDimitry Andric else if (isa<GlobalAlias>(Arg) && 6740b57cec5SDimitry Andric !cast<GlobalAlias>(Arg)->isInterposable()) 6750b57cec5SDimitry Andric Arg = cast<GlobalAlias>(Arg)->getAliasee(); 6760b57cec5SDimitry Andric else { 6770b57cec5SDimitry Andric // If Arg is a PHI node, get PHIs that are equivalent to it and replace 6780b57cec5SDimitry Andric // their uses. 6790b57cec5SDimitry Andric if (PHINode *PN = dyn_cast<PHINode>(Arg)) { 6800b57cec5SDimitry Andric SmallVector<Value *, 1> PHIList; 6810b57cec5SDimitry Andric getEquivalentPHIs(*PN, PHIList); 6820b57cec5SDimitry Andric for (Value *PHI : PHIList) 6830b57cec5SDimitry Andric ReplaceArgUses(PHI); 6840b57cec5SDimitry Andric } 6850b57cec5SDimitry Andric break; 6860b57cec5SDimitry Andric } 6870b57cec5SDimitry Andric } 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric // Replace bitcast users of Arg that are dominated by Inst. 6900b57cec5SDimitry Andric SmallVector<BitCastInst *, 2> BitCastUsers; 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric // Add all bitcast users of the function argument first. 6930b57cec5SDimitry Andric for (User *U : OrigArg->users()) 6940b57cec5SDimitry Andric if (auto *BC = dyn_cast<BitCastInst>(U)) 6950b57cec5SDimitry Andric BitCastUsers.push_back(BC); 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric // Replace the bitcasts with the call return. Iterate until list is empty. 6980b57cec5SDimitry Andric while (!BitCastUsers.empty()) { 6990b57cec5SDimitry Andric auto *BC = BitCastUsers.pop_back_val(); 7000b57cec5SDimitry Andric for (User *U : BC->users()) 7010b57cec5SDimitry Andric if (auto *B = dyn_cast<BitCastInst>(U)) 7020b57cec5SDimitry Andric BitCastUsers.push_back(B); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric ReplaceArgUses(BC); 7050b57cec5SDimitry Andric } 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric // If this function has no escaping allocas or suspicious vararg usage, 7090b57cec5SDimitry Andric // objc_storeStrong calls can be marked with the "tail" keyword. 7100b57cec5SDimitry Andric if (TailOkForStoreStrongs) 7110b57cec5SDimitry Andric for (CallInst *CI : StoreStrongCalls) 7120b57cec5SDimitry Andric CI->setTailCall(); 7130b57cec5SDimitry Andric StoreStrongCalls.clear(); 7140b57cec5SDimitry Andric 7150b57cec5SDimitry Andric return Changed; 7160b57cec5SDimitry Andric } 7170b57cec5SDimitry Andric 7180b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7190b57cec5SDimitry Andric // Misc Pass Manager 7200b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7210b57cec5SDimitry Andric 722e8d8bef9SDimitry Andric char ObjCARCContractLegacyPass::ID = 0; 723e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(ObjCARCContractLegacyPass, "objc-arc-contract", 7240b57cec5SDimitry Andric "ObjC ARC contraction", false, false) 7250b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) 7260b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 727e8d8bef9SDimitry Andric INITIALIZE_PASS_END(ObjCARCContractLegacyPass, "objc-arc-contract", 7280b57cec5SDimitry Andric "ObjC ARC contraction", false, false) 7290b57cec5SDimitry Andric 730e8d8bef9SDimitry Andric void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const { 7310b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 7320b57cec5SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>(); 7330b57cec5SDimitry Andric } 7340b57cec5SDimitry Andric 735e8d8bef9SDimitry Andric Pass *llvm::createObjCARCContractPass() { 736e8d8bef9SDimitry Andric return new ObjCARCContractLegacyPass(); 737e8d8bef9SDimitry Andric } 7380b57cec5SDimitry Andric 739e8d8bef9SDimitry Andric bool ObjCARCContractLegacyPass::runOnFunction(Function &F) { 74081ad6265SDimitry Andric ObjCARCContract OCARCC; 74181ad6265SDimitry Andric OCARCC.init(*F.getParent()); 742e8d8bef9SDimitry Andric auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); 743e8d8bef9SDimitry Andric auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 744e8d8bef9SDimitry Andric return OCARCC.run(F, AA, DT); 745e8d8bef9SDimitry Andric } 7460b57cec5SDimitry Andric 747e8d8bef9SDimitry Andric PreservedAnalyses ObjCARCContractPass::run(Function &F, 748e8d8bef9SDimitry Andric FunctionAnalysisManager &AM) { 749e8d8bef9SDimitry Andric ObjCARCContract OCAC; 750e8d8bef9SDimitry Andric OCAC.init(*F.getParent()); 7510b57cec5SDimitry Andric 752e8d8bef9SDimitry Andric bool Changed = OCAC.run(F, &AM.getResult<AAManager>(F), 753e8d8bef9SDimitry Andric &AM.getResult<DominatorTreeAnalysis>(F)); 754fe6060f1SDimitry Andric bool CFGChanged = OCAC.hasCFGChanged(); 755e8d8bef9SDimitry Andric if (Changed) { 756e8d8bef9SDimitry Andric PreservedAnalyses PA; 757fe6060f1SDimitry Andric if (!CFGChanged) 758e8d8bef9SDimitry Andric PA.preserveSet<CFGAnalyses>(); 759e8d8bef9SDimitry Andric return PA; 760e8d8bef9SDimitry Andric } 761e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 7620b57cec5SDimitry Andric } 763