LLVM: lib/Analysis/LoopCacheAnalysis.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

40

41using namespace llvm;

42

43#define DEBUG_TYPE "loop-cache-cost"

44

47 cl::desc("Use this to specify the default trip count of a loop"));

48

49

50

51

54 cl::desc("Use this to specify the max. distance between array elements "

55 "accessed in a loop so that the elements are classified to have "

56 "temporal reuse"));

57

58

59

60

61

63 assert(Loops.empty() && "Expecting a non-empy loop vector");

64

67

68 if (ParentLoop == nullptr) {

69 assert(Loops.size() == 1 && "Expecting a single loop");

70 return LastLoop;

71 }

72

74 [](const Loop *L1, const Loop *L2) {

76 }))

77 ? LastLoop

78 : nullptr;

79}

80

83 const SCEVAddRecExpr *AR = dyn_cast(&AccessFn);

85 return false;

86

88

89

92 if (isa(Start) || isa(Step))

93 return false;

94

95

97 return false;

98

102

103 return StepRec == &ElemSize;

104}

105

106

107

108

112 const SCEV *TripCount = (!isa(BackedgeTakenCount) &&

113 isa(BackedgeTakenCount))

115 : nullptr;

116

117 if (!TripCount) {

118 LLVM_DEBUG(dbgs() << "Trip count of loop " << L.getName()

119 << " could not be computed, using DefaultTripCount\n");

121 }

122

123 return TripCount;

124}

125

126

127

128

130 if (!R.IsValid) {

131 OS << R.StoreOrLoadInst;

132 OS << ", IsValid=false.";

133 return OS;

134 }

135

136 OS << *R.BasePointer;

137 for (const SCEV *Subscript : R.Subscripts)

138 OS << "[" << *Subscript << "]";

139

140 OS << ", Sizes: ";

141 for (const SCEV *Size : R.Sizes)

142 OS << "[" << *Size << "]";

143

144 return OS;

145}

146

149 : StoreOrLoadInst(StoreOrLoadInst), SE(SE) {

150 assert((isa(StoreOrLoadInst) || isa(StoreOrLoadInst)) &&

151 "Expecting a load or store instruction");

152

153 IsValid = delinearize(LI);

154 if (IsValid)

156 << "\n");

157}

158

159std::optional

162 assert(IsValid && "Expecting a valid reference");

163

164 if (BasePointer != Other.getBasePointer() && !isAliased(Other, AA)) {

166 << "No spacial reuse: different base pointers\n");

167 return false;

168 }

169

171 if (NumSubscripts != Other.getNumSubscripts()) {

173 << "No spacial reuse: different number of subscripts\n");

174 return false;

175 }

176

177

178 for (auto SubNum : seq(0, NumSubscripts - 1)) {

182 << *Other.getSubscript(SubNum) << "\n");

183 return false;

184 }

185 }

186

187

188

190 const SCEV *OtherLastSubscript = Other.getLastSubscript();

191 const SCEVConstant *Diff = dyn_cast(

192 SE.getMinusSCEV(LastSubscript, OtherLastSubscript));

193

194 if (Diff == nullptr) {

196 << "No spacial reuse, difference between subscript:\n\t"

197 << *LastSubscript << "\n\t" << OtherLastSubscript

198 << "\nis not constant.\n");

199 return std::nullopt;

200 }

201

203

205 if (InSameCacheLine)

206 dbgs().indent(2) << "Found spacial reuse.\n";

207 else

208 dbgs().indent(2) << "No spacial reuse.\n";

209 });

210

211 return InSameCacheLine;

212}

213

214std::optional

216 unsigned MaxDistance, const Loop &L,

218 assert(IsValid && "Expecting a valid reference");

219

220 if (BasePointer != Other.getBasePointer() && !isAliased(Other, AA)) {

222 << "No temporal reuse: different base pointer\n");

223 return false;

224 }

225

226 std::unique_ptr D =

227 DI.depends(&StoreOrLoadInst, &Other.StoreOrLoadInst, true);

228

229 if (D == nullptr) {

231 return false;

232 }

233

234 if (D->isLoopIndependent()) {

236 return true;

237 }

238

239

240

241

242 int LoopDepth = L.getLoopDepth();

243 int Levels = D->getLevels();

244 for (int Level = 1; Level <= Levels; ++Level) {

245 const SCEV *Distance = D->getDistance(Level);

246 const SCEVConstant *SCEVConst = dyn_cast_or_null(Distance);

247

248 if (SCEVConst == nullptr) {

250 return std::nullopt;

251 }

252

254 if (Level != LoopDepth && !CI.isZero()) {

256 << "No temporal reuse: distance is not zero at depth=" << Level

257 << "\n");

258 return false;

259 } else if (Level == LoopDepth && CI.getSExtValue() > MaxDistance) {

262 << "No temporal reuse: distance is greater than MaxDistance at depth="

263 << Level << "\n");

264 return false;

265 }

266 }

267

269 return true;

270}

271

273 unsigned CLS) const {

274 assert(IsValid && "Expecting a valid reference");

276 dbgs().indent(2) << "Computing cache cost for:\n";

278 });

279

280

281 if (isLoopInvariant(L)) {

283 return 1;

284 }

285

287 assert(TripCount && "Expecting valid TripCount");

288 LLVM_DEBUG(dbgs() << "TripCount=" << *TripCount << "\n");

289

290 const SCEV *RefCost = nullptr;

291 const SCEV *Stride = nullptr;

292 if (isConsecutive(L, Stride, CLS)) {

293

294

295 assert(Stride != nullptr &&

296 "Stride should not be null for consecutive access!");

301 const SCEV *Numerator = SE.getMulExpr(Stride, TripCount);

302

303

304

305

306

308

310 << "Access is consecutive: RefCost=(TripCount*Stride)/CLS="

311 << *RefCost << "\n");

312 } else {

313

314

315

316

317

318

319

320 RefCost = TripCount;

321

322 int Index = getSubscriptIndex(L);

323 assert(Index >= 0 && "Could not locate a valid Index");

324

327 assert(AR && AR->getLoop() && "Expecting valid loop");

328 const SCEV *TripCount =

331

335 }

336

338 << "Access is not consecutive: RefCost=" << *RefCost << "\n");

339 }

340 assert(RefCost && "Expecting a valid RefCost");

341

342

343

344

345

346 if (auto ConstantCost = dyn_cast(RefCost))

347 return ConstantCost->getValue()->getLimitedValue(

348 std::numeric_limits<int64_t>::max());

349

351 << "RefCost is not a constant! Setting to RefCost=InvalidCost "

352 "(invalid value).\n");

353

355}

356

357bool IndexedReference::tryDelinearizeFixedSize(

361 ArraySizes))

362 return false;

363

364

365 for (auto Idx : seq(1, Subscripts.size()))

366 Sizes.push_back(

367 SE.getConstant(Subscripts[Idx]->getType(), ArraySizes[Idx - 1]));

368

370 dbgs() << "Delinearized subscripts of fixed-size array\n"

372 << "\n";

373 });

374 return true;

375}

376

377bool IndexedReference::delinearize(const LoopInfo &LI) {

378 assert(Subscripts.empty() && "Subscripts should be empty");

379 assert(Sizes.empty() && "Sizes should be empty");

380 assert(!IsValid && "Should be called once from the constructor");

381 LLVM_DEBUG(dbgs() << "Delinearizing: " << StoreOrLoadInst << "\n");

382

385

387 const SCEV *AccessFn =

389

390 BasePointer = dyn_cast(SE.getPointerBase(AccessFn));

391 if (BasePointer == nullptr) {

394 << "ERROR: failed to delinearize, can't identify base pointer\n");

395 return false;

396 }

397

398 bool IsFixedSize = false;

399

400 if (tryDelinearizeFixedSize(AccessFn, Subscripts)) {

401 IsFixedSize = true;

402

403 Sizes.push_back(ElemSize);

405 << "', AccessFn: " << *AccessFn << "\n");

406 }

407

408 AccessFn = SE.getMinusSCEV(AccessFn, BasePointer);

409

410

411 if (!IsFixedSize) {

413 << "', AccessFn: " << *AccessFn << "\n");

416 }

417

418 if (Subscripts.empty() || Sizes.empty() ||

419 Subscripts.size() != Sizes.size()) {

420

421

424 << "ERROR: failed to delinearize reference\n");

425 Subscripts.clear();

426 Sizes.clear();

427 return false;

428 }

429

430

431

432

433

434

435 const SCEVAddRecExpr *AccessFnAR = dyn_cast(AccessFn);

437

445 Sizes.push_back(ElemSize);

446 }

447

448 return all_of(Subscripts, [&](const SCEV *Subscript) {

449 return isSimpleAddRecurrence(*Subscript, *L);

450 });

451 }

452

453 return false;

454}

455

456bool IndexedReference::isLoopInvariant(const Loop &L) const {

458 assert(Addr != nullptr && "Expecting either a load or a store instruction");

460

462 return true;

463

464

465

466 bool allCoeffForLoopAreZero = all_of(Subscripts, [&](const SCEV *Subscript) {

467 return isCoeffForLoopZeroOrInvariant(*Subscript, L);

468 });

469

470 return allCoeffForLoopAreZero;

471}

472

473bool IndexedReference::isConsecutive(const Loop &L, const SCEV *&Stride,

474 unsigned CLS) const {

475

476

477 const SCEV *LastSubscript = Subscripts.back();

478 for (const SCEV *Subscript : Subscripts) {

479 if (Subscript == LastSubscript)

480 continue;

481 if (!isCoeffForLoopZeroOrInvariant(*Subscript, L))

482 return false;

483 }

484

485

486 const SCEV *Coeff = getLastCoefficient();

487 const SCEV *ElemSize = Sizes.back();

489

490

491

492

493

494

495

496

497

498

502

505}

506

507int IndexedReference::getSubscriptIndex(const Loop &L) const {

510 if (AR && AR->getLoop() == &L) {

511 return Idx;

512 }

513 }

514 return -1;

515}

516

517const SCEV *IndexedReference::getLastCoefficient() const {

519 auto *AR = cast(LastSubscript);

521}

522

523bool IndexedReference::isCoeffForLoopZeroOrInvariant(const SCEV &Subscript,

524 const Loop &L) const {

525 const SCEVAddRecExpr *AR = dyn_cast(&Subscript);

526 return (AR != nullptr) ? AR->getLoop() != &L

528}

529

530bool IndexedReference::isSimpleAddRecurrence(const SCEV &Subscript,

531 const Loop &L) const {

532 if (!isa(Subscript))

533 return false;

534

535 const SCEVAddRecExpr *AR = cast(&Subscript);

536 assert(AR->getLoop() && "AR should have a loop");

537

539 return false;

540

543

545 return false;

546

547 return true;

548}

549

555}

556

557

558

559

561 for (const auto &LC : CC.LoopCosts) {

562 const Loop *L = LC.first;

563 OS << "Loop '" << L->getName() << "' has cost = " << LC.second << "\n";

564 }

565 return OS;

566}

567

571 std::optional TRT)

573 TTI(TTI), AA(AA), DI(DI) {

574 assert(Loops.empty() && "Expecting a non-empty loop vector.");

575

579 TripCounts.push_back({L, TripCount});

580 }

581

582 calculateCacheFootprint();

583}

584

585std::unique_ptr

589 LLVM_DEBUG(dbgs() << "Expecting the outermost loop in a loop nest\n");

590 return nullptr;

591 }

592

595

597 LLVM_DEBUG(dbgs() << "Cannot compute cache cost of loop nest with more "

598 "than one innermost loop\n");

599 return nullptr;

600 }

601

602 return std::make_unique(Loops, AR.LI, AR.SE, AR.TTI, AR.AA, DI, TRT);

603}

604

605void CacheCost::calculateCacheFootprint() {

606 LLVM_DEBUG(dbgs() << "POPULATING REFERENCE GROUPS\n");

608 if (!populateReferenceGroups(RefGroups))

609 return;

610

611 LLVM_DEBUG(dbgs() << "COMPUTING LOOP CACHE COSTS\n");

612 for (const Loop *L : Loops) {

614 LoopCosts,

615 [L](const LoopCacheCostTy &LCC) { return LCC.first == L; }) &&

616 "Should not add duplicate element");

617 CacheCostTy LoopCost = computeLoopCacheCost(*L, RefGroups);

618 LoopCosts.push_back(std::make_pair(L, LoopCost));

619 }

620

621 sortLoopCosts();

622 RefGroups.clear();

623}

624

625bool CacheCost::populateReferenceGroups(ReferenceGroupsTy &RefGroups) const {

626 assert(RefGroups.empty() && "Reference groups should be empty");

627

630 assert(InnerMostLoop != nullptr && "Expecting a valid innermost loop");

631

634 if (!isa(I) && !isa(I))

635 continue;

636

637 std::unique_ptr R(new IndexedReference(I, LI, SE));

638 if (R->isValid())

639 continue;

640

641 bool Added = false;

645 dbgs() << "References:\n";

647 dbgs().indent(2) << Representative << "\n";

648 });

649

650

651

652

653

654

655

656

657

658

659

660

661

662 std::optional HasTemporalReuse =

663 R->hasTemporalReuse(Representative, *TRT, *InnerMostLoop, DI, AA);

664 std::optional HasSpacialReuse =

665 R->hasSpacialReuse(Representative, CLS, AA);

666

667 if ((HasTemporalReuse && *HasTemporalReuse) ||

668 (HasSpacialReuse && *HasSpacialReuse)) {

669 RefGroup.push_back(std::move(R));

671 break;

672 }

673 }

674

675 if (!Added) {

678 RefGroups.push_back(std::move(RG));

679 }

680 }

681 }

682

683 if (RefGroups.empty())

684 return false;

685

687 dbgs() << "\nIDENTIFIED REFERENCE GROUPS:\n";

688 int n = 1;

690 dbgs().indent(2) << "RefGroup " << n << ":\n";

691 for (const auto &IR : RG)

693 n++;

694 }

695 dbgs() << "\n";

696 });

697

698 return true;

699}

700

702CacheCost::computeLoopCacheCost(const Loop &L,

704 if (L.isLoopSimplifyForm())

706

708 << "' as innermost loop.\n");

709

710

712 for (const auto &TC : TripCounts) {

713 if (TC.first == &L)

714 continue;

715 TripCountsProduct *= TC.second;

716 }

717

720 CacheCostTy RefGroupCost = computeRefGroupCacheCost(RG, L);

721 LoopCost += RefGroupCost * TripCountsProduct;

722 }

723

725 << "' has cost=" << LoopCost << "\n");

726

727 return LoopCost;

728}

729

731 const Loop &L) const {

732 assert(!RG.empty() && "Reference group should have at least one member.");

733

736}

737

738

739

740

744 Function *F = L.getHeader()->getParent();

746

748 OS << *CC;

749

751}

This file builds on the ADT/GraphTraits.h file to build a generic breadth first graph iterator.

static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")

Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx

Legalize the Machine IR a function s Machine IR

static bool isOneDimensionalArray(const SCEV &AccessFn, const SCEV &ElemSize, const Loop &L, ScalarEvolution &SE)

static cl::opt< unsigned > TemporalReuseThreshold("temporal-reuse-threshold", cl::init(2), cl::Hidden, cl::desc("Use this to specify the max. distance between array elements " "accessed in a loop so that the elements are classified to have " "temporal reuse"))

static const SCEV * computeTripCount(const Loop &L, const SCEV &ElemSize, ScalarEvolution &SE)

Compute the trip count for the given loop L or assume a default value if it is not a compile time con...

static Loop * getInnerMostLoop(const LoopVectorTy &Loops)

Retrieve the innermost loop in the given loop nest Loops.

static cl::opt< unsigned > DefaultTripCount("default-trip-count", cl::init(100), cl::Hidden, cl::desc("Use this to specify the default trip count of a loop"))

This file defines the interface for the loop cache analysis.

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

Provides some synthesis utilities to produce sequences of values.

This file defines the SmallVector class.

static cl::opt< unsigned > CacheLineSize("cache-line-size", cl::init(0), cl::Hidden, cl::desc("Use this to override the target cache line size when " "specified by the user."))

This pass exposes codegen information to IR-level passes.

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

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

A container for analyses that lazily runs them and caches their results.

LLVM Basic Block Representation.

CacheCost represents the estimated cost of a inner loop as the number of cache lines used by the memo...

CacheCost(const LoopVectorTy &Loops, const LoopInfo &LI, ScalarEvolution &SE, TargetTransformInfo &TTI, AAResults &AA, DependenceInfo &DI, std::optional< unsigned > TRT=std::nullopt)

Construct a CacheCost object for the loop nest described by Loops.

static std::unique_ptr< CacheCost > getCacheCost(Loop &Root, LoopStandardAnalysisResults &AR, DependenceInfo &DI, std::optional< unsigned > TRT=std::nullopt)

Create a CacheCost for the loop nest rooted by Root.

@ ICMP_ULT

unsigned less than

This is the shared class of boolean and integer constants.

bool isZero() const

This is just a convenience method to make client code smaller for a common code.

int64_t getSExtValue() const

Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...

DependenceInfo - This class is the main dependence-analysis driver.

std::unique_ptr< Dependence > depends(Instruction *Src, Instruction *Dst, bool PossiblyLoopIndependent)

depends - Tests for a dependence between the Src and Dst instructions.

Represents a memory reference as a base pointer and a set of indexing operations.

CacheCostTy computeRefCost(const Loop &L, unsigned CLS) const

Compute the cost of the reference w.r.t.

const SCEV * getSubscript(unsigned SubNum) const

std::optional< bool > hasSpacialReuse(const IndexedReference &Other, unsigned CLS, AAResults &AA) const

Return true/false if the current object and the indexed reference Other are/aren't in the same cache ...

std::optional< bool > hasTemporalReuse(const IndexedReference &Other, unsigned MaxDistance, const Loop &L, DependenceInfo &DI, AAResults &AA) const

Return true if the current object and the indexed reference Other have distance smaller than MaxDista...

IndexedReference(Instruction &StoreOrLoadInst, const LoopInfo &LI, ScalarEvolution &SE)

Construct an indexed reference given a StoreOrLoadInst instruction.

const SCEV * getLastSubscript() const

size_t getNumSubscripts() const

static InstructionCost getInvalid(CostType Val=0)

This class provides an interface for updating the loop pass manager based on mutations to the loop ne...

bool isOutermost() const

Return true if the loop does not have a parent (natural) loop.

unsigned getLoopDepth() const

Return the nesting level of this loop.

ArrayRef< BlockT * > getBlocks() const

Get a list of the basic blocks which make up this loop.

LoopT * getParentLoop() const

Return the parent loop if it exists or nullptr for top level loops.

PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U)

LoopT * getLoopFor(const BlockT *BB) const

Return the inner most loop that BB lives in.

Represents a single loop in the control flow graph.

static MemoryLocation get(const LoadInst *LI)

Return a location with information about the memory reference by the given instruction.

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.

This node represents a polynomial recurrence on the trip count of the specified loop.

const SCEV * getStart() const

const SCEV * getStepRecurrence(ScalarEvolution &SE) const

Constructs and returns the recurrence indicating how much this expression steps by.

bool isAffine() const

Return true if this represents an expression A + B*x where A and B are loop invariant values.

const Loop * getLoop() const

This class represents a constant integer value.

ConstantInt * getValue() const

NoWrapFlags getNoWrapFlags(NoWrapFlags Mask=NoWrapMask) const

This class represents an analyzed expression in the program.

Type * getType() const

Return the LLVM type of this SCEV expression.

The main scalar evolution driver.

const SCEV * getNegativeSCEV(const SCEV *V, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)

Return the SCEV object corresponding to -V.

const SCEV * getUDivCeilSCEV(const SCEV *N, const SCEV *D)

Compute ceil(N / D).

Type * getWiderType(Type *Ty1, Type *Ty2) const

bool isKnownNegative(const SCEV *S)

Test if the given expression is known to be negative.

const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)

Return a SCEV expression for the specified value at the specified scope in the program.

const SCEV * getBackedgeTakenCount(const Loop *L, ExitCountKind Kind=Exact)

If the specified loop has a predictable backedge-taken count, return it, otherwise return a SCEVCould...

const SCEV * getConstant(ConstantInt *V)

const SCEV * getSCEV(Value *V)

Return a SCEV expression for the full generality of the specified expression.

const SCEV * getNoopOrSignExtend(const SCEV *V, Type *Ty)

Return a SCEV corresponding to a conversion of the input value to the specified type.

const SCEV * getTripCountFromExitCount(const SCEV *ExitCount)

A version of getTripCountFromExitCount below which always picks an evaluation type which can not resu...

bool isLoopInvariant(const SCEV *S, const Loop *L)

Return true if the value of the given SCEV is unchanging in the specified loop.

const SCEV * getAddRecExpr(const SCEV *Start, const SCEV *Step, const Loop *L, SCEV::NoWrapFlags Flags)

Get an add recurrence expression for the specified loop.

bool isSCEVable(Type *Ty) const

Test if values of the given type are analyzable within the SCEV framework.

const SCEV * getNoopOrAnyExtend(const SCEV *V, Type *Ty)

Return a SCEV corresponding to a conversion of the input value to the specified type.

const SCEV * getMinusSCEV(const SCEV *LHS, const SCEV *RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)

Return LHS-RHS.

const SCEV * getNoopOrZeroExtend(const SCEV *V, Type *Ty)

Return a SCEV corresponding to a conversion of the input value to the specified type.

unsigned getSmallConstantTripCount(const Loop *L)

Returns the exact trip count of the loop if we can compute it, and the result is a small constant.

const SCEV * getPointerBase(const SCEV *V)

Transitively follow the chain of pointer-type operands until reaching a SCEV that does not have a sin...

const SCEV * getMulExpr(SmallVectorImpl< const SCEV * > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)

Get a canonical multiply expression, or something simpler if possible.

const SCEV * getElementSize(Instruction *Inst)

Return the size of an element read or written by Inst.

const SCEV * getUDivExactExpr(const SCEV *LHS, const SCEV *RHS)

Get a canonical unsigned division expression, or something simpler if possible.

bool isKnownPredicate(CmpPredicate Pred, const SCEV *LHS, const SCEV *RHS)

Test if the given expression is known to satisfy the condition described by Pred, LHS,...

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

This pass provides access to the codegen interfaces that are needed for IR-level transformations.

unsigned getCacheLineSize() const

The instances of the Type class are immutable: once they are created, they are never changed.

Type * getExtendedType() const

Given scalar/vector integer type, returns a type with elements twice as wide as in the original type.

LLVM Value Representation.

const ParentTy * getParent() const

This class implements an extremely fast bulk output stream that can only output to a stream.

raw_ostream & indent(unsigned NumSpaces)

indent - Insert 'NumSpaces' spaces.

initializer< Ty > init(const Ty &Val)

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.

const Value * getLoadStorePointerOperand(const Value *V)

A helper function that returns the pointer operand of a load or store instruction.

void append_range(Container &C, Range &&R)

Wrapper function to append range R to container C.

const Value * getPointerOperand(const Value *V)

A helper function that returns the pointer operand of a load, store or GEP instruction.

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

bool none_of(R &&Range, UnaryPredicate P)

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

bool is_sorted(R &&Range, Compare C)

Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...

iterator_range< bf_iterator< T > > breadth_first(const T &G)

bool tryDelinearizeFixedSizeImpl(ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< int > &Sizes)

Implementation of fixed size array delinearization.

raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)

void delinearize(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< const SCEV * > &Sizes, const SCEV *ElementSize)

Split this SCEVAddRecExpr into two vectors of SCEVs representing the subscripts and sizes of an array...

The adaptor from a function pass to a loop pass computes these analyses and makes them available to t...

TargetTransformInfo & TTI