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
47
48using namespace llvm;
50
51#define DEBUG_TYPE "objc-arc-contract"
52
53STATISTIC(NumPeeps, "Number of calls peephole-optimized");
54STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed");
55
57 "arc-contract-use-objc-claim-rv",
59 "Enable generation of calls to objc_claimAutoreleasedReturnValue"));
60
61
62
63
64
65namespace {
66
67
68
69
70
71class ObjCARCContract {
73 bool CFGChanged = false;
79
80
81 bool Run;
82
83
84 bool HasClaimRV = false;
85
86
87
89
90
91
92
94
95
96 bool tryToPeepholeInstruction(
98 bool &TailOkForStoreStrong,
100
102
105
106 void tryToContractReleaseIntoStoreStrong(
109
110public:
111 bool init(Module &M);
113 bool hasCFGChanged() const { return CFGChanged; }
114};
115
116class ObjCARCContractLegacyPass : public FunctionPass {
117public:
118 void getAnalysisUsage(AnalysisUsage &AU) const override;
120
121 static char ID;
122 ObjCARCContractLegacyPass() : FunctionPass(ID) {
124 }
125};
126}
127
128
129
130
131
132
133
134
138 return false;
140 return false;
141
142
145 ++I;
147 return false;
148
149
151 ++NumPeeps;
152
154 dbgs() << "Transforming objc_retain => "
155 "objc_retainAutoreleasedReturnValue since the operand is a "
156 "return value.\nOld: "
158
159
160
161 Function *Decl = EP.get(ARCRuntimeEntryPointKind::RetainRV);
163
165 return true;
166}
167
168
169bool ObjCARCContract::contractAutorelease(Function &F, Instruction *Autorelease,
172
173
174
180
183 return false;
184
186 ++NumPeeps;
187
189 " Autorelease:"
191 << "\n"
192 " Retain: "
194
195 Function *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV
196 ? ARCRuntimeEntryPointKind::RetainAutoreleaseRV
197 : ARCRuntimeEntryPointKind::RetainAutorelease);
199
201
203 return true;
204}
205
211 bool SawRelease = false;
212
213
215 auto *LocPtr = Loc.Ptr->stripPointerCasts();
216
217
219 E = Load->getParent()->end();
221
222
223 if (Store && SawRelease)
224 break;
225
226
227
230 SawRelease = true;
231 continue;
232 }
233
234
235
237
238
239 if (Store) {
240
241
242
243
244
245 if ((Inst, Load, PA, Class)) {
246 continue;
247 }
248
249
250 return nullptr;
251 }
252
253
254
255
256
257
258
259
261 continue;
262
263
264
266 continue;
267
269
270
271
272
273
274 if (!Store || !Store->isSimple())
275 return nullptr;
276
277
278
279 if (Store->getPointerOperand()->stripPointerCasts() == LocPtr)
280 continue;
281
282
283
284 return nullptr;
285 }
286
287
288 if (!Store || !SawRelease)
289 return nullptr;
290
291
292 return Store;
293}
294
299
304
305
306
307
309 return nullptr;
310 --I;
311 }
314 return nullptr;
316 return nullptr;
318}
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347void ObjCARCContract::tryToContractReleaseIntoStoreStrong(
349 const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
350
352 if (!Load || ->isSimple())
353 return;
354
355
357 if (Load->getParent() != BB)
358 return;
359
360
361
362 StoreInst *Store =
364
365 if (!Store)
366 return;
367
368
370
371
372
375
376
378 return;
379
381 ++NumStoreStrongs;
382
384 llvm::dbgs() << " Contracting retain, release into objc_storeStrong.\n"
385 << " Old:\n"
386 << " Store: " << *Store << "\n"
387 << " Release: " << *Release << "\n"
388 << " Retain: " << *Retain << "\n"
389 << " Load: " << *Load << "\n");
390
392 Function *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong);
394 Decl, Args, "", Store->getIterator(), BlockColors);
397
398
399
400
402
404 << "\n");
405
406 if (&*Iter == Retain) ++Iter;
407 if (&*Iter == Store) ++Iter;
408 Store->eraseFromParent();
409 Release->eraseFromParent();
411 if (Load->use_empty())
412 Load->eraseFromParent();
413}
414
415bool ObjCARCContract::tryToPeepholeInstruction(
417 bool &TailOkForStoreStrongs,
418 const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
419
420
422 switch (Class) {
423 case ARCInstKind::FusedRetainAutorelease:
424 case ARCInstKind::FusedRetainAutoreleaseRV:
425 return false;
426 case ARCInstKind::Autorelease:
427 case ARCInstKind::AutoreleaseRV:
428 return contractAutorelease(F, Inst, Class);
429 case ARCInstKind::Retain:
430
431
432 if (!optimizeRetainCall(F, Inst))
433 return false;
434
435 [[fallthrough]];
436 case ARCInstKind::RetainRV:
437 case ARCInstKind::UnsafeClaimRV: {
438
439
440
441
442 if (BundledInsts->contains(Inst))
443 return true;
444
445
446
447 if (!RVInstMarker)
448 return false;
449
450
451
454
455
456
457
458 do {
459 if (BBI == InstParent->begin()) {
461 if (!Pred)
462 goto decline_rv_optimization;
464 break;
465 }
466 --BBI;
468
470 LLVM_DEBUG(dbgs() << "Adding inline asm marker for the return value "
471 "optimization.\n");
473 InlineAsm *IA =
475 false),
477 "", true);
478
480 BlockColors);
481 }
482 decline_rv_optimization:
483 return false;
484 }
485 case ARCInstKind::InitWeak: {
486
492
493 LLVM_DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n"
494 << " New = " << *Null << "\n");
495
498 }
499 return true;
500 }
501 case ARCInstKind::Release:
502
503
504 tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors);
505 return true;
506 case ARCInstKind::User:
507
508
509
511 TailOkForStoreStrongs = false;
512 return true;
513 case ARCInstKind::IntrinsicUser:
514
517 return true;
518 default:
520 if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) {
521
524 }
525 return true;
526 }
527}
528
529
531
534
535 Triple TT(M.getTargetTriple());
536
537
538
539 if (!TT.isAArch64())
540 return false;
541
542 unsigned Major = TT.getOSMajorVersion();
543 switch (TT.getOS()) {
544 default:
545 return false;
548 return Major >= 16;
550 return Major >= 9;
552 return Major >= 7;
554 return Major >= 13;
556 return Major >= 21;
557 }
558
559 return false;
560}
561
562
563
564
565
566bool ObjCARCContract::init(Module &M) {
568 if (!Run)
569 return false;
570
572
574
575
577
578 return false;
579}
580
581bool ObjCARCContract::run(Function &F, AAResults *A, DominatorTree *D) {
582 if (!Run)
583 return false;
584
586 return false;
587
588 Changed = CFGChanged = false;
589 AA = A;
590 DT = D;
592 BundledRetainClaimRVs BRV(EP, true, HasClaimRV);
593 BundledInsts = &BRV;
594
597 CFGChanged |= R.second;
598
599 DenseMap<BasicBlock *, ColorVector> BlockColors;
600 if (F.hasPersonalityFn() &&
603
605
606
607
608
609
610
611 bool TailOkForStoreStrongs =
612 .isVarArg() &&
.callsFunctionThatReturnsTwice();
613
614
615
616
619
621
625 --I;
627 }
628
629
630
631 if (tryToPeepholeInstruction(F, Inst, I, TailOkForStoreStrongs,
632 BlockColors))
633 continue;
634
635
636
637
638
639
640
641 auto ReplaceArgUses = [Inst, this](Value *Arg) {
642
644 return;
645
646
647 for (Value::use_iterator UI = Arg->use_begin(), UE = Arg->use_end();
648 UI != UE; ) {
649
651 unsigned OperandNo = U.getOperandNo();
652
653
654
655
656
657
658
660 continue;
661
664 Type *UseTy = U.get()->getType();
666
668 BasicBlock *IncomingBB = PHI->getIncomingBlock(ValNo);
669 if (Replacement->getType() != UseTy) {
670
671
672
676 }
677
679 "Invalid insertion point for bitcast");
680 Replacement = new BitCastInst(Replacement, UseTy, "",
682 }
683
684
685
686
687 for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i)
688 if (PHI->getIncomingBlock(i) == IncomingBB) {
689
690 if (UI != UE &&
691 &PHI->getOperandUse(
693 ++UI;
694 PHI->setIncomingValue(i, Replacement);
695 }
696 } else {
697 if (Replacement->getType() != UseTy)
698 Replacement =
699 new BitCastInst(Replacement, UseTy, "",
701 U.set(Replacement);
702 }
703 }
704 };
705
707
708
709 for (;;) {
710 ReplaceArgUses(Arg);
711
712
714 Arg = BI->getOperand(0);
721 else {
722
723
728 ReplaceArgUses(PHI);
729 }
730 break;
731 }
732 }
733 }
734
735
736
737 if (TailOkForStoreStrongs)
738 for (CallInst *CI : StoreStrongCalls)
740 StoreStrongCalls.clear();
741
743}
744
745
746
747
748
749char ObjCARCContractLegacyPass::ID = 0;
751 "ObjC ARC contraction", false, false)
756
757void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
763}
764
766 return new ObjCARCContractLegacyPass();
767}
768
769bool ObjCARCContractLegacyPass::runOnFunction(Function &F) {
770 ObjCARCContract OCARCC;
771 OCARCC.init(*F.getParent());
772 auto *AA = &getAnalysis().getAAResults();
773 auto *DT = &getAnalysis().getDomTree();
774 return OCARCC.run(F, AA, DT);
775}
776
779 ObjCARCContract OCAC;
780 OCAC.init(*F.getParent());
781
784 bool CFGChanged = OCAC.hasCFGChanged();
787 if (!CFGChanged)
789 return PA;
790 }
792}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file declares special dependency analysis routines used in Objective C ARC Optimizations.
static bool runOnFunction(Function &F, bool PostInlining)
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
static StoreInst * findSafeStoreForStoreStrongContraction(LoadInst *Load, Instruction *Release, ProvenanceAnalysis &PA, AAResults *AA)
Definition ObjCARCContract.cpp:206
static bool useClaimRuntimeCall(Module &M)
Should we use objc_claimAutoreleasedReturnValue?
Definition ObjCARCContract.cpp:530
static Instruction * findRetainForStoreStrongContraction(Value *New, StoreInst *Store, Instruction *Release, ProvenanceAnalysis &PA)
Definition ObjCARCContract.cpp:296
static cl::opt< cl::boolOrDefault > UseObjCClaimRV("arc-contract-use-objc-claim-rv", cl::desc("Enable generation of calls to objc_claimAutoreleasedReturnValue"))
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''.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
void setAA(AAResults *aa)
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
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.
iterator begin()
Instruction iterator methods.
const Instruction & back() const
LLVM_ABI InstListType::const_iterator getFirstNonPHIIt() const
Returns an iterator to the first instruction in this block that is not a PHINode instruction.
InstListType::const_iterator const_iterator
LLVM_ABI 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...
Represents analyses that only rely on functions' control flow.
Value * getArgOperand(unsigned i) const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
void setTailCall(bool IsTc=true)
static LLVM_ABI 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.
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
LLVM_ABI 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.
static LLVM_ABI 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.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
An instruction for reading from memory.
LLVM_ABI StringRef getString() const
Representation for a specific memory location.
static LLVM_ABI MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
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 LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Pass interface - Implemented by all 'passes'.
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.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
An instruction for storing to memory.
Triple - Helper class for working with autoconf configuration names.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI 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.
Function * get(ARCRuntimeEntryPointKind kind)
bool contains(const Instruction *I) const
See if an instruction is a bundled retainRV/claimRV call.
std::pair< bool, bool > insertAfterInvokes(Function &F, DominatorTree *DT)
Insert a retainRV/claimRV call to the normal destination blocks of invokes with operand bundle "clang...
CallInst * insertRVCallWithColors(BasicBlock::iterator InsertPt, CallBase *AnnotatedCall, const DenseMap< BasicBlock *, ColorVector > &BlockColors)
Insert a retainRV/claimRV call with colors.
CallInst * Autorelease
Look for an `‘autorelease’' instruction dependent on Arg such that there are / no instructions depend...
This file defines common definitions/declarations used by the ObjC ARC Optimizer.
Abstract Attribute helper functions.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ BasicBlock
Various leaf nodes.
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)
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.
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
InstIterator< SymbolTableList< BasicBlock >, Function::iterator, BasicBlock::iterator, Instruction > inst_iterator
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
LLVM_ABI DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
LLVM_ABI void initializeObjCARCContractLegacyPassPass(PassRegistry &)
inst_iterator inst_begin(Function *F)
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
auto dyn_cast_or_null(const Y &Val)
bool isModSet(const ModRefInfo MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
inst_iterator inst_end(Function *F)
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI Pass * createObjCARCContractPass()
Definition ObjCARCContract.cpp:765
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Definition ObjCARCContract.cpp:777