LLVM: lib/Transforms/ObjCARC/ObjCARCContract.cpp Source File (original) (raw)
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
46
47using namespace llvm;
49
50#define DEBUG_TYPE "objc-arc-contract"
51
52STATISTIC(NumPeeps, "Number of calls peephole-optimized");
53STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed");
54
55
56
57
58
59namespace {
60
61
62
63
64
65class ObjCARCContract {
66 bool Changed;
67 bool CFGChanged;
73
74
75 bool Run;
76
77
78
80
81
82
83
85
86
87 bool tryToPeepholeInstruction(
89 bool &TailOkForStoreStrong,
91
93
96
97 void tryToContractReleaseIntoStoreStrong(
100
101public:
102 bool init(Module &M);
104 bool hasCFGChanged() const { return CFGChanged; }
105};
106
107class ObjCARCContractLegacyPass : public FunctionPass {
108public:
111
112 static char ID;
115 }
116};
117}
118
119
120
121
122
123
124
125
129 return false;
130 if (Call->getParent() != Retain->getParent())
131 return false;
132
133
136 ++I;
138 return false;
139
140
141 Changed = true;
142 ++NumPeeps;
143
145 dbgs() << "Transforming objc_retain => "
146 "objc_retainAutoreleasedReturnValue since the operand is a "
147 "return value.\nOld: "
149
150
151
152 Function *Decl = EP.get(ARCRuntimeEntryPointKind::RetainRV);
153 cast(Retain)->setCalledFunction(Decl);
154
156 return true;
157}
158
159
163
164
165
169 auto *Retain = dyn_cast_or_null(
171
174 return false;
175
176 Changed = true;
177 ++NumPeeps;
178
180 " Autorelease:"
182 << "\n"
183 " Retain: "
185
186 Function *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV
187 ? ARCRuntimeEntryPointKind::RetainAutoreleaseRV
188 : ARCRuntimeEntryPointKind::RetainAutorelease);
189 Retain->setCalledFunction(Decl);
190
192
194 return true;
195}
196
202 bool SawRelease = false;
203
204
207
208
210 E = Load->getParent()->end();
212
213
214 if (Store && SawRelease)
215 break;
216
217
218
221 SawRelease = true;
222 continue;
223 }
224
225
226
228
229
230 if (Store) {
231
232
233
234
235
236 if ((Inst, Load, PA, Class)) {
237 continue;
238 }
239
240
241 return nullptr;
242 }
243
244
245
246
247
248
249
250
252 continue;
253
254
255
257 continue;
258
259 Store = dyn_cast(Inst);
260
261
262
263
264
265 if (!Store || !Store->isSimple())
266 return nullptr;
267
268
269
270 if (Store->getPointerOperand()->stripPointerCasts() == LocPtr)
271 continue;
272
273
274
275 return nullptr;
276 }
277
278
279 if (!Store || !SawRelease)
280 return nullptr;
281
282
283 return Store;
284}
285
290
295
296
297
298
300 return nullptr;
301 --I;
302 }
305 return nullptr;
307 return nullptr;
309}
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338void ObjCARCContract::tryToContractReleaseIntoStoreStrong(
341
343 if (!Load || ->isSimple())
344 return;
345
346
348 if (Load->getParent() != BB)
349 return;
350
351
352
355
356 if (!Store)
357 return;
358
359
361
362
363
366
367
369 return;
370
371 Changed = true;
372 ++NumStoreStrongs;
373
375 llvm::dbgs() << " Contracting retain, release into objc_storeStrong.\n"
376 << " Old:\n"
377 << " Store: " << *Store << "\n"
378 << " Release: " << *Release << "\n"
379 << " Retain: " << *Retain << "\n"
380 << " Load: " << *Load << "\n");
381
384 Type *I8XX = PointerType::getUnqual(I8X);
385
387 if (Args[0]->getType() != I8XX)
389 if (Args[1]->getType() != I8X)
391 Function *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong);
393 Decl, Args, "", Store->getIterator(), BlockColors);
396
397
398
399
401
403 << "\n");
404
405 if (&*Iter == Retain) ++Iter;
406 if (&*Iter == Store) ++Iter;
407 Store->eraseFromParent();
408 Release->eraseFromParent();
410 if (Load->use_empty())
411 Load->eraseFromParent();
412}
413
414bool ObjCARCContract::tryToPeepholeInstruction(
416 bool &TailOkForStoreStrongs,
418
419
421 switch (Class) {
422 case ARCInstKind::FusedRetainAutorelease:
423 case ARCInstKind::FusedRetainAutoreleaseRV:
424 return false;
425 case ARCInstKind::Autorelease:
426 case ARCInstKind::AutoreleaseRV:
427 return contractAutorelease(F, Inst, Class);
428 case ARCInstKind::Retain:
429
430
431 if (!optimizeRetainCall(F, Inst))
432 return false;
433
434 [[fallthrough]];
435 case ARCInstKind::RetainRV:
436 case ARCInstKind::UnsafeClaimRV: {
437
438
439
440
441 if (BundledInsts->contains(Inst))
442 return true;
443
444
445
446 if (!RVInstMarker)
447 return false;
448
449
450
453
454
455
456
457 do {
458 if (BBI == InstParent->begin()) {
460 if (!Pred)
461 goto decline_rv_optimization;
463 break;
464 }
465 --BBI;
467
469 LLVM_DEBUG(dbgs() << "Adding inline asm marker for the return value "
470 "optimization.\n");
471 Changed = true;
474 false),
475 RVInstMarker->getString(),
476 "", true);
477
479 BlockColors);
480 }
481 decline_rv_optimization:
482 return false;
483 }
484 case ARCInstKind::InitWeak: {
485
486 CallInst *CI = cast(Inst);
489 Changed = true;
491
492 LLVM_DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n"
493 << " New = " << *Null << "\n");
494
497 }
498 return true;
499 }
500 case ARCInstKind::Release:
501
502
503 tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors);
504 return true;
505 case ARCInstKind::User:
506
507
508
509 if (isa(Inst))
510 TailOkForStoreStrongs = false;
511 return true;
512 case ARCInstKind::IntrinsicUser:
513
514 Changed = true;
516 return true;
517 default:
518 if (auto *CI = dyn_cast(Inst))
519 if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) {
520
521 Changed = true;
523 }
524 return true;
525 }
526}
527
528
529
530
531
532bool ObjCARCContract::init(Module &M) {
534 if (!Run)
535 return false;
536
537 EP.init(&M);
538
539
541
542 return false;
543}
544
546 if (!Run)
547 return false;
548
550 return false;
551
552 Changed = CFGChanged = false;
553 AA = A;
554 DT = D;
555 PA.setAA(A);
557 BundledInsts = &BRV;
558
559 std::pair<bool, bool> R = BundledInsts->insertAfterInvokes(F, DT);
560 Changed |= R.first;
561 CFGChanged |= R.second;
562
564 if (F.hasPersonalityFn() &&
567
569
570
571
572
573
574
575 bool TailOkForStoreStrongs =
576 .isVarArg() &&
.callsFunctionThatReturnsTwice();
577
578
579
580
583
585
586 if (auto *CI = dyn_cast(Inst))
588 BundledInsts->insertRVCallWithColors(I->getIterator(), CI, BlockColors);
589 --I;
590 Changed = true;
591 }
592
593
594
595 if (tryToPeepholeInstruction(F, Inst, I, TailOkForStoreStrongs,
596 BlockColors))
597 continue;
598
599
600
601
602
603
604
605 auto ReplaceArgUses = [Inst, this](Value *Arg) {
606
607 if (!isa(Arg) && !isa(Arg))
608 return;
609
610
612 UI != UE; ) {
613
615 unsigned OperandNo = U.getOperandNo();
616
617
618
619
620
621
622
624 continue;
625
626 Changed = true;
628 Type *UseTy = U.get()->getType();
629 if (PHINode *PHI = dyn_cast(U.getUser())) {
630
632 BasicBlock *IncomingBB = PHI->getIncomingBlock(ValNo);
633 if (Replacement->getType() != UseTy) {
634
635
636
638 while (isa(InsertBB->getFirstNonPHI())) {
640 }
641
643 "Invalid insertion point for bitcast");
644 Replacement = new BitCastInst(Replacement, UseTy, "",
646 }
647
648
649
650
651 for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i)
652 if (PHI->getIncomingBlock(i) == IncomingBB) {
653
654 if (UI != UE &&
655 &PHI->getOperandUse(
657 ++UI;
658 PHI->setIncomingValue(i, Replacement);
659 }
660 } else {
661 if (Replacement->getType() != UseTy)
662 Replacement =
664 cast(U.getUser())->getIterator());
665 U.set(Replacement);
666 }
667 }
668 };
669
670 Value *Arg = cast(Inst)->getArgOperand(0);
671 Value *OrigArg = Arg;
672
673
674 for (;;) {
675 ReplaceArgUses(Arg);
676
677
678 if (const BitCastInst *BI = dyn_cast(Arg))
679 Arg = BI->getOperand(0);
680 else if (isa(Arg) &&
681 cast(Arg)->hasAllZeroIndices())
682 Arg = cast(Arg)->getPointerOperand();
683 else if (isa(Arg) &&
684 !cast(Arg)->isInterposable())
685 Arg = cast(Arg)->getAliasee();
686 else {
687
688
689 if (PHINode *PN = dyn_cast(Arg)) {
693 ReplaceArgUses(PHI);
694 }
695 break;
696 }
697 }
698
699
701
702
704 if (auto *BC = dyn_cast(U))
706
707
708 while (!BitCastUsers.empty()) {
711 if (auto *B = dyn_cast(U))
713
714 ReplaceArgUses(BC);
715 }
716 }
717
718
719
720 if (TailOkForStoreStrongs)
721 for (CallInst *CI : StoreStrongCalls)
723 StoreStrongCalls.clear();
724
725 return Changed;
726}
727
728
729
730
731
732char ObjCARCContractLegacyPass::ID = 0;
734 "ObjC ARC contraction", false, false)
739
740void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
746}
747
749 return new ObjCARCContractLegacyPass();
750}
751
752bool ObjCARCContractLegacyPass::runOnFunction(Function &F) {
753 ObjCARCContract OCARCC;
754 OCARCC.init(*F.getParent());
755 auto *AA = &getAnalysis().getAAResults();
756 auto *DT = &getAnalysis().getDomTree();
757 return OCARCC.run(F, AA, DT);
758}
759
762 ObjCARCContract OCAC;
763 OCAC.init(*F.getParent());
764
767 bool CFGChanged = OCAC.hasCFGChanged();
768 if (Changed) {
770 if (!CFGChanged)
772 return PA;
773 }
775}
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...
This file defines common definitions/declarations used by the ObjC ARC Optimizer.
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)