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

211 I != E; ++I) {

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

614 Use &U = *UI++;

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)