LLVM: lib/CodeGen/ImplicitNullChecks.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

56#include

57#include

58#include

59

60using namespace llvm;

61

63 cl::desc("The page size of the target in bytes"),

65

67 "imp-null-max-insts-to-consider",

68 cl::desc("The max number of instructions to consider hoisting loads over "

69 "(the algorithm is quadratic over this number)"),

71

72#define DEBUG_TYPE "implicit-null-checks"

73

75 "Number of explicit null checks made implicit");

76

77namespace {

78

80

82

83

84

85

87

88

89

90

91

92 struct DependenceResult {

93

94

95 bool CanReorder;

96

97

98

99 std::optional<ArrayRef<MachineInstr *>::iterator> PotentialDependence;

100

101 DependenceResult(

102 bool CanReorder,

104 : CanReorder(CanReorder), PotentialDependence(PotentialDependence) {

105 assert((!PotentialDependence || CanReorder) &&

106 "!CanReorder && PotentialDependence.hasValue() not allowed!");

107 }

108 };

109

110

111

112

113

114

115 DependenceResult computeDependence(const MachineInstr *MI,

117

118

119 class NullCheck {

120

121 MachineInstr *MemOperation;

122

123

124 MachineInstr *CheckOperation;

125

126

127 MachineBasicBlock *CheckBlock;

128

129

130 MachineBasicBlock *NotNullSucc;

131

132

133 MachineBasicBlock *NullSucc;

134

135

136

137 MachineInstr *OnlyDependency;

138

139 public:

140 explicit NullCheck(MachineInstr *memOperation, MachineInstr *checkOperation,

141 MachineBasicBlock *checkBlock,

142 MachineBasicBlock *notNullSucc,

143 MachineBasicBlock *nullSucc,

144 MachineInstr *onlyDependency)

145 : MemOperation(memOperation), CheckOperation(checkOperation),

146 CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc),

147 OnlyDependency(onlyDependency) {}

148

149 MachineInstr *getMemOperation() const { return MemOperation; }

150

151 MachineInstr *getCheckOperation() const { return CheckOperation; }

152

153 MachineBasicBlock *getCheckBlock() const { return CheckBlock; }

154

155 MachineBasicBlock *getNotNullSucc() const { return NotNullSucc; }

156

157 MachineBasicBlock *getNullSucc() const { return NullSucc; }

158

159 MachineInstr *getOnlyDependency() const { return OnlyDependency; }

160 };

161

162 const TargetInstrInfo *TII = nullptr;

163 const TargetRegisterInfo *TRI = nullptr;

165 MachineFrameInfo *MFI = nullptr;

166

167 bool analyzeBlockForNullChecks(MachineBasicBlock &MBB,

168 SmallVectorImpl &NullCheckList);

169 MachineInstr *insertFaultingInstr(MachineInstr *MI, MachineBasicBlock *MBB,

170 MachineBasicBlock *HandlerMBB);

172

173 enum AliasResult {

174 AR_NoAlias,

175 AR_MayAlias,

176 AR_WillAliasEverything

177 };

178

179

180

181

182 AliasResult areMemoryOpsAliased(const MachineInstr &MI,

183 const MachineInstr *PrevMI) const;

184

185 enum SuitabilityResult {

186 SR_Suitable,

187 SR_Unsuitable,

188 SR_Impossible

189 };

190

191

192

193

194

195

196

197 SuitabilityResult isSuitableMemoryOp(const MachineInstr &MI,

200

201

202

203

204 bool canDependenceHoistingClobberLiveIns(MachineInstr *DependenceMI,

205 MachineBasicBlock *NullSucc);

206

207

208

209

210 bool canHoistInst(MachineInstr *FaultingMI,

212 MachineBasicBlock *NullSucc, MachineInstr *&Dependence);

213

214public:

215 static char ID;

216

217 ImplicitNullChecks() : MachineFunctionPass(ID) {

219 }

220

221 bool runOnMachineFunction(MachineFunction &MF) override;

222

223 void getAnalysisUsage(AnalysisUsage &AU) const override {

226 }

227

228 MachineFunctionProperties getRequiredProperties() const override {

229 return MachineFunctionProperties().setNoVRegs();

230 }

231};

232

233}

234

235bool ImplicitNullChecks::canHandle(const MachineInstr *MI) {

236 if (MI->isCall() || MI->mayRaiseFPException() ||

237 MI->hasUnmodeledSideEffects())

238 return false;

239 auto IsRegMask = [](const MachineOperand &MO) { return MO.isRegMask(); };

240 (void)IsRegMask;

241

243 "Calls were filtered out above!");

244

245 auto IsUnordered = [](MachineMemOperand *MMO) { return MMO->isUnordered(); };

247}

248

249ImplicitNullChecks::DependenceResult

250ImplicitNullChecks::computeDependence(const MachineInstr *MI,

254

255 std::optional<ArrayRef<MachineInstr *>::iterator> Dep;

256

257 for (auto I = Block.begin(), E = Block.end(); I != E; ++I) {

258 if (canReorder(*I, MI))

259 continue;

260

261 if (Dep == std::nullopt) {

262

263 Dep = I;

264 } else {

265

266 return {false, std::nullopt};

267 }

268 }

269

270 return {true, Dep};

271}

272

273bool ImplicitNullChecks::canReorder(const MachineInstr *A,

274 const MachineInstr *B) {

275 assert(canHandle(A) && canHandle(B) && "Precondition!");

276

277

278

279

280

281 for (const auto &MOA : A->operands()) {

282 if (!(MOA.isReg() && MOA.getReg()))

283 continue;

284

285 Register RegA = MOA.getReg();

286 for (const auto &MOB : B->operands()) {

287 if (!(MOB.isReg() && MOB.getReg()))

288 continue;

289

290 Register RegB = MOB.getReg();

291

292 if (TRI->regsOverlap(RegA, RegB) && (MOA.isDef() || MOB.isDef()))

293 return false;

294 }

295 }

296

297 return true;

298}

299

300bool ImplicitNullChecks::runOnMachineFunction(MachineFunction &MF) {

304 AA = &getAnalysis().getAAResults();

305

307

308 for (auto &MBB : MF)

309 analyzeBlockForNullChecks(MBB, NullCheckList);

310

311 if (!NullCheckList.empty())

312 rewriteNullChecks(NullCheckList);

313

314 return !NullCheckList.empty();

315}

316

317

321 ++AR)

322 if (MBB->isLiveIn(*AR))

323 return true;

324 return false;

325}

326

327ImplicitNullChecks::AliasResult

328ImplicitNullChecks::areMemoryOpsAliased(const MachineInstr &MI,

329 const MachineInstr *PrevMI) const {

330

332 return AR_NoAlias;

333

334 if (!(MI.mayStore() || PrevMI->mayStore()))

335 return AR_NoAlias;

336

337

338 if (MI.memoperands_empty())

339 return MI.mayStore() ? AR_WillAliasEverything : AR_MayAlias;

341 return PrevMI->mayStore() ? AR_WillAliasEverything : AR_MayAlias;

342

343 for (MachineMemOperand *MMO1 : MI.memoperands()) {

344

345

346 assert(MMO1->getValue() && "MMO1 should have a Value!");

347 for (MachineMemOperand *MMO2 : PrevMI->memoperands()) {

348 if (const PseudoSourceValue *PSV = MMO2->getPseudoValue()) {

349 if (PSV->mayAlias(MFI))

350 return AR_MayAlias;

351 continue;

352 }

356 return AR_MayAlias;

357 }

358 }

359 return AR_NoAlias;

360}

361

362ImplicitNullChecks::SuitabilityResult

363ImplicitNullChecks::isSuitableMemoryOp(const MachineInstr &MI,

366

367

368 if (MI.getDesc().getNumDefs() > 1)

369 return SR_Unsuitable;

370

371 if (MI.mayLoadOrStore() || MI.isPredicable())

372 return SR_Unsuitable;

373 auto AM = TII->getAddrModeFromMemoryOp(MI, TRI);

374 if (!AM || AM->Form != ExtAddrMode::Formula::Basic)

375 return SR_Unsuitable;

378 int64_t Displacement = AddrMode.Displacement;

379

380

381

382 if (BaseReg != PointerReg && ScaledReg != PointerReg)

383 return SR_Unsuitable;

384 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();

385 unsigned PointerRegSizeInBits = TRI->getRegSizeInBits(PointerReg, MRI);

386

387

388 if ((BaseReg &&

389 TRI->getRegSizeInBits(BaseReg, MRI) != PointerRegSizeInBits) ||

390 (ScaledReg &&

391 TRI->getRegSizeInBits(ScaledReg, MRI) != PointerRegSizeInBits))

392 return SR_Unsuitable;

393

394

395

396 auto CalculateDisplacementFromAddrMode = [&](Register RegUsedInAddr,

397 int64_t Multiplier) {

398

399

400

401 if (!RegUsedInAddr)

402 return false;

403 assert(Multiplier && "expected to be non-zero!");

404 MachineInstr *ModifyingMI = nullptr;

406 It != MI.getParent()->rend(); It++) {

407 const MachineInstr *CurrMI = &*It;

409 ModifyingMI = const_cast<MachineInstr *>(CurrMI);

410 break;

411 }

412 }

413 if (!ModifyingMI)

414 return false;

415

416

417 int64_t ImmVal;

418 if (TII->getConstValDefinedInReg(*ModifyingMI, RegUsedInAddr, ImmVal))

419 return false;

420

421

423 APInt ImmValC(RegSizeInBits, ImmVal, true );

425 assert(MultiplierC.isStrictlyPositive() &&

426 "expected to be a positive value!");

427 bool IsOverflow;

428

429

430 APInt Product = ImmValC.smul_ov(MultiplierC, IsOverflow);

431 if (IsOverflow)

432 return false;

433 APInt DisplacementC(64, Displacement, true );

434 DisplacementC = Product.sadd_ov(DisplacementC, IsOverflow);

435 if (IsOverflow)

436 return false;

437

438

439 if (DisplacementC.getActiveBits() > 64)

440 return false;

441 Displacement = DisplacementC.getSExtValue();

442 return true;

443 };

444

445

446

447 bool BaseRegIsConstVal = false, ScaledRegIsConstVal = false;

448 if (CalculateDisplacementFromAddrMode(BaseReg, 1))

449 BaseRegIsConstVal = true;

450 if (CalculateDisplacementFromAddrMode(ScaledReg, AddrMode.Scale))

451 ScaledRegIsConstVal = true;

452

453

454

455

456

457

458 if ((BaseReg && BaseReg != PointerReg && !BaseRegIsConstVal) ||

459 (ScaledReg && ScaledReg != PointerReg && !ScaledRegIsConstVal))

460 return SR_Unsuitable;

461

462

463

465 return SR_Unsuitable;

466

467

468 for (auto *PrevMI : PrevInsts) {

469 AliasResult AR = areMemoryOpsAliased(MI, PrevMI);

470 if (AR == AR_WillAliasEverything)

471 return SR_Impossible;

472 if (AR == AR_MayAlias)

473 return SR_Unsuitable;

474 }

475 return SR_Suitable;

476}

477

478bool ImplicitNullChecks::canDependenceHoistingClobberLiveIns(

479 MachineInstr *DependenceMI, MachineBasicBlock *NullSucc) {

480 for (const auto &DependenceMO : DependenceMI->operands()) {

481 if (!(DependenceMO.isReg() && DependenceMO.getReg()))

482 continue;

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

502 return true;

503

504 }

505

506

507 return false;

508}

509

510bool ImplicitNullChecks::canHoistInst(MachineInstr *FaultingMI,

512 MachineBasicBlock *NullSucc,

513 MachineInstr *&Dependence) {

514 auto DepResult = computeDependence(FaultingMI, InstsSeenSoFar);

515 if (!DepResult.CanReorder)

516 return false;

517

518 if (!DepResult.PotentialDependence) {

519 Dependence = nullptr;

520 return true;

521 }

522

523 auto DependenceItr = *DepResult.PotentialDependence;

524 auto *DependenceMI = *DependenceItr;

525

526

527

528

529

530

531 assert(canHandle(DependenceMI) && "Should never have reached here!");

533 return false;

534

535 if (canDependenceHoistingClobberLiveIns(DependenceMI, NullSucc))

536 return false;

537

538 auto DepDepResult =

539 computeDependence(DependenceMI, {InstsSeenSoFar.begin(), DependenceItr});

540

541 if (!DepDepResult.CanReorder || DepDepResult.PotentialDependence)

542 return false;

543

544 Dependence = DependenceMI;

545 return true;

546}

547

548

549

550

551bool ImplicitNullChecks::analyzeBlockForNullChecks(

552 MachineBasicBlock &MBB, SmallVectorImpl &NullCheckList) {

553 using MachineBranchPredicate = TargetInstrInfo::MachineBranchPredicate;

554

555 MDNode *BranchMD = nullptr;

557 BranchMD = BB->getTerminator()->getMetadata(LLVMContext::MD_make_implicit);

558

559 if (!BranchMD)

560 return false;

561

562 MachineBranchPredicate MBP;

563

564 if (TII->analyzeBranchPredicate(MBB, MBP, true))

565 return false;

566

567

568 if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&

569 (MBP.Predicate == MachineBranchPredicate::PRED_NE ||

570 MBP.Predicate == MachineBranchPredicate::PRED_EQ)))

571 return false;

572

573

574

575 if (MBP.ConditionDef && !MBP.SingleUseCondition)

576 return false;

577

578 MachineBasicBlock *NotNullSucc, *NullSucc;

579

580 if (MBP.Predicate == MachineBranchPredicate::PRED_NE) {

581 NotNullSucc = MBP.TrueDest;

582 NullSucc = MBP.FalseDest;

583 } else {

584 NotNullSucc = MBP.FalseDest;

585 NullSucc = MBP.TrueDest;

586 }

587

588

589

590 if (NotNullSucc->pred_size() != 1)

591 return false;

592

593 const Register PointerReg = MBP.LHS.getReg();

594

595 if (MBP.ConditionDef) {

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614 assert(MBP.ConditionDef->getParent() == &MBB &&

615 "Should be in basic block");

616

617 for (auto I = MBB.rbegin(); MBP.ConditionDef != &*I; ++I)

618 if (I->modifiesRegister(PointerReg, TRI))

619 return false;

620 }

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

657

658

659

660

661

662

663

664

665

666

667

668

669

670

671

672

673

674

675 SmallVector<MachineInstr *, 8> InstsSeenSoFar;

676

677 for (auto &MI : *NotNullSucc) {

679 return false;

680

681 MachineInstr *Dependence;

682 SuitabilityResult SR = isSuitableMemoryOp(MI, PointerReg, InstsSeenSoFar);

683 if (SR == SR_Impossible)

684 return false;

685 if (SR == SR_Suitable &&

686 canHoistInst(&MI, InstsSeenSoFar, NullSucc, Dependence)) {

687 NullCheckList.emplace_back(&MI, MBP.ConditionDef, &MBB, NotNullSucc,

688 NullSucc, Dependence);

689 return true;

690 }

691

692

693

694 if (TII->preservesZeroValueInReg(&MI, PointerReg, TRI))

695 return false;

697 }

698

699 return false;

700}

701

702

703

704

705

706MachineInstr *ImplicitNullChecks::insertFaultingInstr(

707 MachineInstr *MI, MachineBasicBlock *MBB, MachineBasicBlock *HandlerMBB) {

709 unsigned NumDefs = MI->getDesc().getNumDefs();

710 assert(NumDefs <= 1 && "other cases unhandled!");

711

713 if (NumDefs != 0) {

714 DefReg = MI->getOperand(0).getReg();

715 assert(NumDefs == 1 && "expected exactly one def!");

716 }

717

719 if (MI->mayLoad())

720 FK =

722 else

724

725 auto MIB = BuildMI(MBB, DL, TII->get(TargetOpcode::FAULTING_OP), DefReg)

729

730 for (auto &MO : MI->uses()) {

731 if (MO.isReg()) {

732 MachineOperand NewMO = MO;

733 if (MO.isUse()) {

735 } else {

736 assert(MO.isDef() && "Expected def or use");

738 }

739 MIB.add(NewMO);

740 } else {

741 MIB.add(MO);

742 }

743 }

744

746

747 return MIB;

748}

749

750

751void ImplicitNullChecks::rewriteNullChecks(

754

755 for (const auto &NC : NullCheckList) {

756

757 unsigned BranchesRemoved = TII->removeBranch(*NC.getCheckBlock());

758 (void)BranchesRemoved;

759 assert(BranchesRemoved > 0 && "expected at least one branch!");

760

761 if (auto *DepMI = NC.getOnlyDependency()) {

762 DepMI->removeFromParent();

763 NC.getCheckBlock()->insert(NC.getCheckBlock()->end(), DepMI);

764 }

765

766

767

768

769

770 MachineInstr *FaultingInstr = insertFaultingInstr(

771 NC.getMemOperation(), NC.getCheckBlock(), NC.getNullSucc());

772

773

774

775

776 MachineBasicBlock *MBB = NC.getMemOperation()->getParent();

777 for (const MachineOperand &MO : FaultingInstr->all_defs()) {

780 continue;

782 }

783

784 if (auto *DepMI = NC.getOnlyDependency()) {

785 for (auto &MO : DepMI->all_defs()) {

786 if (!MO.getReg() || MO.isDead())

787 continue;

788 if (NC.getNotNullSucc()->isLiveIn(MO.getReg()))

789 NC.getNotNullSucc()->addLiveIn(MO.getReg());

790 }

791 }

792

793 NC.getMemOperation()->eraseFromParent();

794 if (auto *CheckOp = NC.getCheckOperation())

795 CheckOp->eraseFromParent();

796

797

798

800 {}, DL);

801

802 NumImplicitNullChecks++;

803 }

804}

805

806char ImplicitNullChecks::ID = 0;

807

809

811 "Implicit null checks", false, false)

unsigned const MachineRegisterInfo * MRI

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

const HexagonInstrInfo * TII

static bool AnyAliasLiveIn(const TargetRegisterInfo *TRI, MachineBasicBlock *MBB, Register Reg)

Definition ImplicitNullChecks.cpp:318

static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)

static cl::opt< unsigned > MaxInstsToConsider("imp-null-max-insts-to-consider", cl::desc("The max number of instructions to consider hoisting loads over " "(the algorithm is quadratic over this number)"), cl::Hidden, cl::init(8))

Register const TargetRegisterInfo * TRI

Promote Memory to Register

This file provides utility analysis objects describing memory locations.

#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 defines the SmallVector class.

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

uint16_t RegSizeInBits(const MCRegisterInfo &MRI, MCRegister RegNo)

A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.

bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)

A trivial helper function to check to see if the specified pointers are no-alias.

LLVM_ABI APInt sadd_ov(const APInt &RHS, bool &Overflow) const

AnalysisUsage & addRequired()

unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override

Remove the branching code at the end of the specific MBB.

unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &DL, int *BytesAdded=nullptr) const override

Insert branch code into the end of the specified MachineBasicBlock.

MCRegAliasIterator enumerates all registers aliasing Reg.

unsigned pred_size() const

const BasicBlock * getBasicBlock() const

Return the LLVM basic block that this instance corresponded to originally.

void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())

Adds the specified register as a live in.

const MachineFunction * getParent() const

Return the MachineFunction containing this basic block.

reverse_iterator rbegin()

MachineInstrBundleIterator< const MachineInstr, true > const_reverse_iterator

LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const

Return true if the specified register is in the live in set.

MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...

void getAnalysisUsage(AnalysisUsage &AU) const override

getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.

const TargetSubtargetInfo & getSubtarget() const

getSubtarget - Return the subtarget for which this machine code is being compiled.

MachineFrameInfo & getFrameInfo()

getFrameInfo - Return the frame info object for the current function.

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const

Representation of each machine instruction.

bool mayLoadOrStore(QueryType Type=AnyInBundle) const

Return true if this instruction could possibly read or modify memory.

filtered_mop_range all_defs()

Returns an iterator range over all operands that are (explicit or implicit) register defs.

bool memoperands_empty() const

Return true if we don't have any memory operands which described the memory access done by this instr...

bool modifiesRegister(Register Reg, const TargetRegisterInfo *TRI) const

Return true if the MachineInstr modifies (fully define or partially define) the specified register.

bool mayLoad(QueryType Type=AnyInBundle) const

Return true if this instruction could possibly read memory.

ArrayRef< MachineMemOperand * > memoperands() const

Access to memory operands of the instruction.

bool mayStore(QueryType Type=AnyInBundle) const

Return true if this instruction could possibly modify memory.

void setIsDead(bool Val=true)

void setIsKill(bool Val=true)

const TargetRegisterInfo * getTargetRegisterInfo() const

static MemoryLocation getAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())

Return a location that may access any location after Ptr, while remaining within the underlying objec...

static LLVM_ABI PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

Wrapper class representing virtual and physical registers.

reference emplace_back(ArgTypes &&... Args)

void push_back(const T &Elt)

TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...

virtual const TargetInstrInfo * getInstrInfo() const

initializer< Ty > init(const Ty &Val)

std::reverse_iterator< iterator > rend() const

BaseReg

Stack frame base register. Bit 0 of FREInfo.Info.

This is an optimization pass for GlobalISel generic memory operations.

bool all_of(R &&range, UnaryPredicate P)

Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.

MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)

Builder interface. Specify how to create the initial instruction itself.

LLVM_ABI char & ImplicitNullChecksID

ImplicitNullChecks - This pass folds null pointer checks into nearby memory operations.

Definition ImplicitNullChecks.cpp:808

bool none_of(R &&Range, UnaryPredicate P)

Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

ArrayRef(const T &OneElt) -> ArrayRef< T >

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.

LLVM_ABI void initializeImplicitNullChecksPass(PassRegistry &)

AAResults AliasAnalysis

Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.