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();

220 I != E; ++I) {

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 (CanUse(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 || 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 F.isVarArg() && F.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

650 Use &U = *UI++;

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