50#define DEBUG_TYPE "objc-arc-contract"
52STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
53STATISTIC(NumStoreStrongs,
"Number objc_storeStrong calls formed");
65class ObjCARCContract {
84 bool tryToPeepholeInstruction(
86 bool &TailOkForStoreStrong,
94 void tryToContractReleaseIntoStoreStrong(
101 bool hasCFGChanged()
const {
return CFGChanged; }
142 dbgs() <<
"Transforming objc_retain => "
143 "objc_retainAutoreleasedReturnValue since the operand is a "
144 "return value.\nOld: "
149 Function *Decl = EP.get(ARCRuntimeEntryPointKind::RetainRV);
150 cast<CallInst>(
Retain)->setCalledFunction(Decl);
166 auto *
Retain = dyn_cast_or_null<CallInst>(
183 Function *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV
184 ? ARCRuntimeEntryPointKind::RetainAutoreleaseRV
185 : ARCRuntimeEntryPointKind::RetainAutorelease);
186 Retain->setCalledFunction(Decl);
199 bool SawRelease =
false;
207 E = Load->getParent()->end();
211 if (Store && SawRelease)
233 if (!
CanUse(Inst, Load, PA, Class)) {
256 Store = dyn_cast<StoreInst>(Inst);
262 if (!Store || !Store->isSimple())
267 if (Store->getPointerOperand()->stripPointerCasts() == LocPtr)
276 if (!Store || !SawRelease)
335void ObjCARCContract::tryToContractReleaseIntoStoreStrong(
340 if (!Load || !
Load->isSimple())
345 if (
Load->getParent() != BB)
372 llvm::dbgs() <<
" Contracting retain, release into objc_storeStrong.\n"
374 <<
" Store: " << *Store <<
"\n"
375 <<
" Release: " << *
Release <<
"\n"
376 <<
" Retain: " << *
Retain <<
"\n"
377 <<
" Load: " << *Load <<
"\n");
381 Type *I8XX = PointerType::getUnqual(I8X);
384 if (Args[0]->
getType() != I8XX)
388 Function *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong);
390 Decl, Args,
"",
Store->getIterator(), BlockColors);
402 if (&*Iter ==
Retain) ++Iter;
403 if (&*Iter == Store) ++Iter;
404 Store->eraseFromParent();
407 if (
Load->use_empty())
408 Load->eraseFromParent();
411bool ObjCARCContract::tryToPeepholeInstruction(
413 bool &TailOkForStoreStrongs,
419 case ARCInstKind::FusedRetainAutorelease:
420 case ARCInstKind::FusedRetainAutoreleaseRV:
422 case ARCInstKind::Autorelease:
423 case ARCInstKind::AutoreleaseRV:
424 return contractAutorelease(
F, Inst, Class);
425 case ARCInstKind::Retain:
428 if (!optimizeRetainCall(
F, Inst))
432 case ARCInstKind::RetainRV:
433 case ARCInstKind::UnsafeClaimRV: {
438 if (BundledInsts->contains(Inst))
455 if (BBI == InstParent->
begin()) {
458 goto decline_rv_optimization;
466 LLVM_DEBUG(
dbgs() <<
"Adding inline asm marker for the return value "
472 RVInstMarker->getString(),
478 decline_rv_optimization:
481 case ARCInstKind::InitWeak: {
483 CallInst *CI = cast<CallInst>(Inst);
490 <<
" New = " << *
Null <<
"\n");
497 case ARCInstKind::Release:
500 tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors);
502 case ARCInstKind::User:
506 if (isa<AllocaInst>(Inst))
507 TailOkForStoreStrongs =
false;
509 case ARCInstKind::IntrinsicUser:
515 if (
auto *CI = dyn_cast<CallInst>(Inst))
529bool ObjCARCContract::init(
Module &M) {
542 Changed = CFGChanged =
false;
549 std::pair<bool, bool>
R = BundledInsts->insertAfterInvokes(
F, DT);
551 CFGChanged |=
R.second;
554 if (
F.hasPersonalityFn() &&
565 bool TailOkForStoreStrongs =
566 !
F.isVarArg() && !
F.callsFunctionThatReturnsTwice();
576 if (
auto *CI = dyn_cast<CallInst>(Inst))
578 BundledInsts->insertRVCallWithColors(
I->getIterator(), CI, BlockColors);
585 if (tryToPeepholeInstruction(
F, Inst,
I, TailOkForStoreStrongs,
595 auto ReplaceArgUses = [Inst,
this](
Value *Arg) {
597 if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
605 unsigned OperandNo =
U.getOperandNo();
613 if (!DT->isReachableFromEntry(U) || !DT->dominates(Inst, U))
618 Type *UseTy =
U.get()->getType();
619 if (
PHINode *
PHI = dyn_cast<PHINode>(
U.getUser())) {
623 if (Replacement->
getType() != UseTy) {
629 InsertBB = DT->getNode(InsertBB)->getIDom()->getBlock();
632 assert(DT->dominates(Inst, &InsertBB->
back()) &&
633 "Invalid insertion point for bitcast");
634 Replacement =
new BitCastInst(Replacement, UseTy,
"",
641 for (
unsigned i = 0, e =
PHI->getNumIncomingValues(); i != e; ++i)
642 if (
PHI->getIncomingBlock(i) == IncomingBB) {
648 PHI->setIncomingValue(i, Replacement);
651 if (Replacement->
getType() != UseTy)
654 cast<Instruction>(
U.getUser())->getIterator());
660 Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
661 Value *OrigArg = Arg;
668 if (
const BitCastInst *BI = dyn_cast<BitCastInst>(Arg))
669 Arg = BI->getOperand(0);
670 else if (isa<GEPOperator>(Arg) &&
671 cast<GEPOperator>(Arg)->hasAllZeroIndices())
672 Arg = cast<GEPOperator>(Arg)->getPointerOperand();
673 else if (isa<GlobalAlias>(Arg) &&
674 !cast<GlobalAlias>(Arg)->isInterposable())
675 Arg = cast<GlobalAlias>(Arg)->getAliasee();
679 if (
PHINode *PN = dyn_cast<PHINode>(Arg)) {
694 if (
auto *BC = dyn_cast<BitCastInst>(U))
698 while (!BitCastUsers.
empty()) {
701 if (
auto *
B = dyn_cast<BitCastInst>(U))
710 if (TailOkForStoreStrongs)
711 for (
CallInst *CI : StoreStrongCalls)
713 StoreStrongCalls.clear();
722char ObjCARCContractLegacyPass::ID = 0;
724 "ObjC ARC contraction",
false,
false)
730void ObjCARCContractLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
736 return new ObjCARCContractLegacyPass();
739bool ObjCARCContractLegacyPass::runOnFunction(
Function &
F) {
740 ObjCARCContract OCARCC;
741 OCARCC.init(*
F.getParent());
742 auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
743 auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
744 return OCARCC.run(
F, AA, DT);
749 ObjCARCContract OCAC;
750 OCAC.init(*
F.getParent());
754 bool CFGChanged = OCAC.hasCFGChanged();
This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...
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.
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.
This header defines various interfaces for pass management in LLVM.
#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.
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.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
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 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)