Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion llvm/include/llvm/Analysis/LoopCacheAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class IndexedReference {

/// Attempt to delinearize \p AccessFn for fixed-size arrays.
bool tryDelinearizeFixedSize(const SCEV *AccessFn,
SmallVectorImpl<const SCEV *> &Subscripts);
SmallVectorImpl<const SCEV *> &Subscripts,
const SCEV *ElementSize);

/// Return true if the index reference is invariant with respect to loop \p L.
bool isLoopInvariant(const Loop &L) const;
Expand Down
26 changes: 11 additions & 15 deletions llvm/lib/Analysis/LoopCacheAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,22 +355,18 @@ CacheCostTy IndexedReference::computeRefCost(const Loop &L,
}

bool IndexedReference::tryDelinearizeFixedSize(
const SCEV *AccessFn, SmallVectorImpl<const SCEV *> &Subscripts) {
SmallVector<int, 4> ArraySizes;
if (!tryDelinearizeFixedSizeImpl(&SE, &StoreOrLoadInst, AccessFn, Subscripts,
ArraySizes))
const SCEV *AccessFn, SmallVectorImpl<const SCEV *> &Subscripts,
const SCEV *ElementSize) {
const SCEV *Offset = SE.removePointerBase(AccessFn);
if (!delinearizeFixedSizeArray(SE, Offset, Subscripts, Sizes, ElementSize)) {
Sizes.clear();
return false;
}

// Populate Sizes with scev expressions to be used in calculations later.
for (auto Idx : seq<unsigned>(1, Subscripts.size()))
Sizes.push_back(
SE.getConstant(Subscripts[Idx]->getType(), ArraySizes[Idx - 1]));

LLVM_DEBUG({
dbgs() << "Delinearized subscripts of fixed-size array\n"
<< "GEP:" << *getLoadStorePointerOperand(&StoreOrLoadInst)
<< "\n";
});
// Drop the last element of Sizes which is the same as ElementSize.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think this is self-evident from the assert and line 369, but maybe the more interesting question is why we drop that element, so maybe you can leave a little comment about that.

assert(!Sizes.empty() && Sizes.back() == ElementSize &&
"Expecting the last one to be the element size");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going leave a nit if we can make the message a little bit more descriptive, but now looking at this, my first question is why we need to pass ElementSize if it is last element in the Sizes list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have the following LLVM,

...
%gep = getelementptr i8, ptr %p, i64 %offset
store i32 0, %gep

to delinearize %gep as an i32 array, %offset must be a multiple of 4. We need to tell this information to delinearization function, and it's now passed as ElementSize. For historical reasons, delinearizer appends it to the end of Sizes.

Sizes.pop_back();
return true;
}

Expand All @@ -397,7 +393,7 @@ bool IndexedReference::delinearize(const LoopInfo &LI) {

bool IsFixedSize = false;
// Try to delinearize fixed-size arrays.
if (tryDelinearizeFixedSize(AccessFn, Subscripts)) {
if (tryDelinearizeFixedSize(AccessFn, Subscripts, ElemSize)) {
IsFixedSize = true;
// The last element of Sizes is the element size.
Sizes.push_back(ElemSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,45 @@
; For a loop with a very large iteration count, make sure the cost
; calculation does not overflow:
;
; void a(int b) {
; for (int c;; c += b)
; void a() {
; for (int c;; c += 2)
; for (long d = 0; d < -3ULL; d += 2ULL)
; A[c][d][d] = 0;
; for (long e = 0; e < -3ULL; e += 2ULL)
; A[c][d][e] = 0;
; }

; CHECK: Loop 'outer.loop' has cost = 9223372036854775807
; CHECK: Loop 'middle.loop' has cost = 9223372036854775807
; CHECK: Loop 'inner.loop' has cost = 9223372036854775807

@A = local_unnamed_addr global [11 x [11 x [11 x i32]]] zeroinitializer, align 16

define void @foo(i32 noundef %b) {
define void @foo() {
entry:
%0 = sext i32 %b to i64
br label %outer.loop

outer.loop:
%indvars.iv = phi i64 [ %indvars.iv.next, %outer.loop.cleanup ], [ 0, %entry ]
br label %inner.loop
br label %middle.loop

outer.loop.cleanup:
%indvars.iv.next = add nsw i64 %indvars.iv, %0
%indvars.iv.next = add i64 %indvars.iv, 2
br label %outer.loop

middle.loop:
%middle.iv = phi i64 [ %middle.iv.next, %middle.loop.cleanup ], [ 0, %outer.loop ]
br label %inner.loop

middle.loop.cleanup:
%middle.iv.next = add nuw i64 %middle.iv, 2
%ec.middle = icmp ult i64 %middle.iv, -5
br i1 %ec.middle, label %middle.loop, label %outer.loop.cleanup

inner.loop:
%inner.iv = phi i64 [ 0, %outer.loop ], [ %add, %inner.loop ]
%arrayidx3 = getelementptr inbounds [11 x [11 x [11 x i32]]], ptr @A, i64 0, i64 %indvars.iv, i64 %inner.iv, i64 %inner.iv
%inner.iv = phi i64 [ 0, %middle.loop ], [ %add, %inner.loop ]
%arrayidx3 = getelementptr inbounds [11 x [11 x [11 x i32]]], ptr @A, i64 0, i64 %indvars.iv, i64 %middle.iv, i64 %inner.iv
store i32 0, ptr %arrayidx3, align 4
%add = add nuw i64 %inner.iv, 2
%cmp = icmp ult i64 %inner.iv, -5
br i1 %cmp, label %inner.loop, label %outer.loop.cleanup
br i1 %cmp, label %inner.loop, label %middle.loop.cleanup
}
Loading