50#define DEBUG_TYPE "objc-arc-contract"
52STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
53STATISTIC(NumStoreStrongs,
"Number objc_storeStrong calls formed");
65class ObjCARCContract {
87 bool tryToPeepholeInstruction(
89 bool &TailOkForStoreStrong,
97 void tryToContractReleaseIntoStoreStrong(
104 bool hasCFGChanged()
const {
return CFGChanged; }
145 dbgs() <<
"Transforming objc_retain => "
146 "objc_retainAutoreleasedReturnValue since the operand is a "
147 "return value.\nOld: "
152 Function *Decl = EP.get(ARCRuntimeEntryPointKind::RetainRV);
153 cast<CallInst>(
Retain)->setCalledFunction(Decl);
169 auto *
Retain = dyn_cast_or_null<CallInst>(
186 Function *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV
187 ? ARCRuntimeEntryPointKind::RetainAutoreleaseRV
188 : ARCRuntimeEntryPointKind::RetainAutorelease);
189 Retain->setCalledFunction(Decl);
202 bool SawRelease =
false;
210 E = Load->getParent()->end();
214 if (Store && SawRelease)
236 if (!
CanUse(Inst, Load, PA, Class)) {
259 Store = dyn_cast<StoreInst>(Inst);
265 if (!Store || !Store->isSimple())
270 if (Store->getPointerOperand()->stripPointerCasts() == LocPtr)
279 if (!Store || !SawRelease)
338void ObjCARCContract::tryToContractReleaseIntoStoreStrong(
343 if (!Load || !
Load->isSimple())
348 if (
Load->getParent() != BB)
375 llvm::dbgs() <<
" Contracting retain, release into objc_storeStrong.\n"
377 <<
" Store: " << *Store <<
"\n"
378 <<
" Release: " << *
Release <<
"\n"
379 <<
" Retain: " << *
Retain <<
"\n"
380 <<
" Load: " << *Load <<
"\n");
384 Type *I8XX = PointerType::getUnqual(I8X);
387 if (Args[0]->
getType() != I8XX)
391 Function *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong);
393 Decl, Args,
"",
Store->getIterator(), BlockColors);
405 if (&*Iter ==
Retain) ++Iter;
406 if (&*Iter == Store) ++Iter;
407 Store->eraseFromParent();
410 if (
Load->use_empty())
411 Load->eraseFromParent();
414bool ObjCARCContract::tryToPeepholeInstruction(
416 bool &TailOkForStoreStrongs,
422 case ARCInstKind::FusedRetainAutorelease:
423 case ARCInstKind::FusedRetainAutoreleaseRV:
425 case ARCInstKind::Autorelease:
426 case ARCInstKind::AutoreleaseRV:
427 return contractAutorelease(
F, Inst, Class);
428 case ARCInstKind::Retain:
431 if (!optimizeRetainCall(
F, Inst))
435 case ARCInstKind::RetainRV:
436 case ARCInstKind::UnsafeClaimRV: {
441 if (BundledInsts->contains(Inst))
458 if (BBI == InstParent->
begin()) {
461 goto decline_rv_optimization;
469 LLVM_DEBUG(
dbgs() <<
"Adding inline asm marker for the return value "
475 RVInstMarker->getString(),
481 decline_rv_optimization:
484 case ARCInstKind::InitWeak: {
486 CallInst *CI = cast<CallInst>(Inst);
493 <<
" New = " << *
Null <<
"\n");
500 case ARCInstKind::Release:
503 tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors);
505 case ARCInstKind::User:
509 if (isa<AllocaInst>(Inst))
510 TailOkForStoreStrongs =
false;
512 case ARCInstKind::IntrinsicUser:
518 if (
auto *CI = dyn_cast<CallInst>(Inst))
532bool ObjCARCContract::init(
Module &M) {
552 Changed = CFGChanged =
false;
559 std::pair<bool, bool>
R = BundledInsts->insertAfterInvokes(
F, DT);
561 CFGChanged |=
R.second;
564 if (
F.hasPersonalityFn() &&
575 bool TailOkForStoreStrongs =
576 !
F.isVarArg() && !
F.callsFunctionThatReturnsTwice();
586 if (
auto *CI = dyn_cast<CallInst>(Inst))
588 BundledInsts->insertRVCallWithColors(
I->getIterator(), CI, BlockColors);
595 if (tryToPeepholeInstruction(
F, Inst,
I, TailOkForStoreStrongs,
605 auto ReplaceArgUses = [Inst,
this](
Value *Arg) {
607 if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
615 unsigned OperandNo =
U.getOperandNo();
628 Type *UseTy =
U.get()->getType();
629 if (
PHINode *
PHI = dyn_cast<PHINode>(
U.getUser())) {
633 if (Replacement->
getType() != UseTy) {
643 "Invalid insertion point for bitcast");
644 Replacement =
new BitCastInst(Replacement, UseTy,
"",
651 for (
unsigned i = 0, e =
PHI->getNumIncomingValues(); i != e; ++i)
652 if (
PHI->getIncomingBlock(i) == IncomingBB) {
658 PHI->setIncomingValue(i, Replacement);
661 if (Replacement->
getType() != UseTy)
664 cast<Instruction>(
U.getUser())->getIterator());
670 Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
671 Value *OrigArg = Arg;
678 if (
const BitCastInst *BI = dyn_cast<BitCastInst>(Arg))
679 Arg = BI->getOperand(0);
680 else if (isa<GEPOperator>(Arg) &&
681 cast<GEPOperator>(Arg)->hasAllZeroIndices())
682 Arg = cast<GEPOperator>(Arg)->getPointerOperand();
683 else if (isa<GlobalAlias>(Arg) &&
684 !cast<GlobalAlias>(Arg)->isInterposable())
685 Arg = cast<GlobalAlias>(Arg)->getAliasee();
689 if (
PHINode *PN = dyn_cast<PHINode>(Arg)) {
704 if (
auto *BC = dyn_cast<BitCastInst>(U))
708 while (!BitCastUsers.
empty()) {
711 if (
auto *
B = dyn_cast<BitCastInst>(U))
720 if (TailOkForStoreStrongs)
721 for (
CallInst *CI : StoreStrongCalls)
723 StoreStrongCalls.clear();
732char ObjCARCContractLegacyPass::ID = 0;
734 "ObjC ARC contraction",
false,
false)
740void ObjCARCContractLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
749 return new ObjCARCContractLegacyPass();
752bool ObjCARCContractLegacyPass::runOnFunction(
Function &
F) {
753 ObjCARCContract OCARCC;
754 OCARCC.init(*
F.getParent());
755 auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
756 auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
757 return OCARCC.run(
F, AA, DT);
762 ObjCARCContract OCAC;
763 OCAC.init(*
F.getParent());
767 bool CFGChanged = OCAC.hasCFGChanged();
This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
This file declares special dependency analysis routines used in Objective C ARC Optimizations.
This header defines various interfaces for pass management in LLVM.
static StoreInst * findSafeStoreForStoreStrongContraction(LoadInst *Load, Instruction *Release, ProvenanceAnalysis &PA, AAResults *AA)
static Instruction * findRetainForStoreStrongContraction(Value *New, StoreInst *Store, Instruction *Release, ProvenanceAnalysis &PA)
objc arc ObjC ARC contraction
This file defines ARC utility functions which are used by various parts of the compiler.
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file declares a special form of Alias Analysis called Provenance Analysis''.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
ModRefInfo getModRefInfo(const Instruction *I, const std::optional< MemoryLocation > &OptLoc)
Check whether or not an instruction may read or write the optionally specified memory location.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
Legacy wrapper pass to provide the BasicAAResult object.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
InstListType::const_iterator const_iterator
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
const Instruction & back() const
This class represents a no-op cast from one type to another.
Represents analyses that only rely on functions' control flow.
Value * getArgOperand(unsigned i) const
Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
This class represents a function call, abstracting a target machine's calling convention.
void setTailCall(bool IsTc=true)
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
DomTreeNodeBase * getIDom() const
Analysis pass which computes a DominatorTree.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
static InlineAsm * get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack=false, AsmDialect asmDialect=AD_ATT, bool canThrow=false)
InlineAsm::get - Return the specified uniqued inline asm string.
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
Representation for a specific memory location.
static MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
const Value * Ptr
The address of the start of the location.
A Module instance is used to store all the information related to an LLVM module.
static unsigned getOperandNumForIncomingValue(unsigned i)
static unsigned getIncomingValueNumForOperand(unsigned i)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Pass interface - Implemented by all 'passes'.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserveSet()
Mark an analysis set as preserved.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
The instances of the Type class are immutable: once they are created, they are never changed.
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt8Ty(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
use_iterator_impl< Use > use_iterator
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVMContext & getContext() const
All values hold a context through their type.
const ParentTy * getParent() const
self_iterator getIterator()
Declarations for ObjC runtime functions and constants.
This is similar to BasicAliasAnalysis, and it uses many of the same techniques, except it uses specia...
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
bool ModuleHasARC(const Module &M)
Test if the given module looks interesting to run ARC optimization on.
bool IsRetain(ARCInstKind Class)
Test if the given class is objc_retain or equivalent.
DependenceKind
Defines different dependence kinds among various ARC constructs.
@ RetainAutoreleaseDep
Blocks objc_retainAutorelease.
@ RetainAutoreleaseRVDep
Blocks objc_retainAutoreleaseReturnValue.
bool IsNullOrUndef(const Value *V)
ARCInstKind
Equivalence classes of instructions in the ARC Model.
@ StoreStrong
objc_storeStrong (derived)
@ Autorelease
objc_autorelease
@ Call
could call objc_release
bool EnableARCOpts
A handy option to enable/disable all ARC Optimizations.
CallInst * createCallInstWithColors(FunctionCallee Func, ArrayRef< Value * > Args, const Twine &NameStr, BasicBlock::iterator InsertBefore, const DenseMap< BasicBlock *, ColorVector > &BlockColors)
Create a call instruction with the correct funclet token.
void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList)
Return the list of PHI nodes that are equivalent to PN.
bool IsNoopInstruction(const Instruction *I)
llvm::Instruction * findSingleDependency(DependenceKind Flavor, const Value *Arg, BasicBlock *StartBB, Instruction *StartInst, ProvenanceAnalysis &PA)
Find dependent instructions.
ARCInstKind GetBasicARCInstKind(const Value *V)
Determine which objc runtime call instruction class V belongs to.
Value * GetArgRCIdentityRoot(Value *Inst)
Assuming the given instruction is one of the special calls such as objc_retain or objc_release,...
bool CanDecrementRefCount(ARCInstKind Kind)
Returns false if conservatively we can prove that any instruction mapped to this kind can not decreme...
const Value * GetRCIdentityRoot(const Value *V)
The RCIdentity root of a value V is a dominating value U for which retaining or releasing U is equiva...
static MDString * getRVInstMarker(Module &M)
bool hasAttachedCallOpBundle(const CallBase *CB)
bool CanUse(const Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Test whether the given instruction can "use" the given pointer's object in a way that requires the re...
static void EraseInstruction(Instruction *CI)
Erase the given instruction.
This is an optimization pass for GlobalISel generic memory operations.
DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
inst_iterator inst_begin(Function *F)
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
bool isModSet(const ModRefInfo MRI)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
inst_iterator inst_end(Function *F)
void initializeObjCARCContractLegacyPassPass(PassRegistry &)
Pass * createObjCARCContractPass()
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)