Skip to content

Commit 6646b65

Browse files
authored
[LAA] Rework and rename stripGetElementPtr (#125315)
The stripGetElementPtr function is mysteriously named, and calls into another mysterious getGEPInductionOperand which does something complicated with GEP indices. The real purpose of the badly-named stripGetElementPtr function is to get a loop-variant GEP index, if there is one. The getGEPInductionOperand is totally redundant, as stripping off zeros from the end of GEP indices has no effect on computing the loop-variant GEP index, as constant zeros are always loop-invariant. Moreover, the GEP induction operand is simply the first non-zero index from the end, which stripGetElementPtr returns when it finds that any of the GEP indices are loop-variant: this is a completely unrelated value to the GEP index that is loop-variant. The implicit assumption here is that there is only ever one loop-variant index, and it is the first non-zero one from the end. The logic is unnecessarily complicated for what stripGetElementPtr wants to achieve, and the header comments are confusing as well. Strip getGEPInductionOperand, rework and rename stripGetElementPtr.
1 parent ef21831 commit 6646b65

File tree

2 files changed

+64
-44
lines changed

2 files changed

+64
-44
lines changed

llvm/lib/Analysis/LoopAccessAnalysis.cpp

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,12 @@
4242
#include "llvm/IR/DiagnosticInfo.h"
4343
#include "llvm/IR/Dominators.h"
4444
#include "llvm/IR/Function.h"
45-
#include "llvm/IR/GetElementPtrTypeIterator.h"
4645
#include "llvm/IR/InstrTypes.h"
4746
#include "llvm/IR/Instruction.h"
4847
#include "llvm/IR/Instructions.h"
48+
#include "llvm/IR/IntrinsicInst.h"
4949
#include "llvm/IR/Operator.h"
5050
#include "llvm/IR/PassManager.h"
51-
#include "llvm/IR/PatternMatch.h"
5251
#include "llvm/IR/Type.h"
5352
#include "llvm/IR/Value.h"
5453
#include "llvm/IR/ValueHandle.h"
@@ -66,7 +65,6 @@
6665
#include <vector>
6766

6867
using namespace llvm;
69-
using namespace llvm::PatternMatch;
7068

7169
#define DEBUG_TYPE "loop-accesses"
7270

@@ -2815,50 +2813,25 @@ bool LoopAccessInfo::isInvariant(Value *V) const {
28152813
return SE->isLoopInvariant(S, TheLoop);
28162814
}
28172815

2818-
/// Find the operand of the GEP that should be checked for consecutive
2819-
/// stores. This ignores trailing indices that have no effect on the final
2820-
/// pointer.
2821-
static unsigned getGEPInductionOperand(const GetElementPtrInst *Gep) {
2822-
const DataLayout &DL = Gep->getDataLayout();
2823-
unsigned LastOperand = Gep->getNumOperands() - 1;
2824-
TypeSize GEPAllocSize = DL.getTypeAllocSize(Gep->getResultElementType());
2825-
2826-
// Walk backwards and try to peel off zeros.
2827-
while (LastOperand > 1 && match(Gep->getOperand(LastOperand), m_Zero())) {
2828-
// Find the type we're currently indexing into.
2829-
gep_type_iterator GEPTI = gep_type_begin(Gep);
2830-
std::advance(GEPTI, LastOperand - 2);
2831-
2832-
// If it's a type with the same allocation size as the result of the GEP we
2833-
// can peel off the zero index.
2834-
TypeSize ElemSize = GEPTI.isStruct()
2835-
? DL.getTypeAllocSize(GEPTI.getIndexedType())
2836-
: GEPTI.getSequentialElementStride(DL);
2837-
if (ElemSize != GEPAllocSize)
2838-
break;
2839-
--LastOperand;
2840-
}
2841-
2842-
return LastOperand;
2843-
}
2844-
2845-
/// If the argument is a GEP, then returns the operand identified by
2846-
/// getGEPInductionOperand. However, if there is some other non-loop-invariant
2847-
/// operand, it returns that instead.
2848-
static Value *stripGetElementPtr(Value *Ptr, ScalarEvolution *SE, Loop *Lp) {
2816+
/// If \p Ptr is a GEP, which has a loop-variant operand, return that operand.
2817+
/// Otherwise, return \p Ptr.
2818+
static Value *getLoopVariantGEPOperand(Value *Ptr, ScalarEvolution *SE,
2819+
Loop *Lp) {
28492820
auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
28502821
if (!GEP)
28512822
return Ptr;
28522823

2853-
unsigned InductionOperand = getGEPInductionOperand(GEP);
2854-
2855-
// Check that all of the gep indices are uniform except for our induction
2856-
// operand.
2857-
for (unsigned I = 0, E = GEP->getNumOperands(); I != E; ++I)
2858-
if (I != InductionOperand &&
2859-
!SE->isLoopInvariant(SE->getSCEV(GEP->getOperand(I)), Lp))
2860-
return Ptr;
2861-
return GEP->getOperand(InductionOperand);
2824+
Value *V = Ptr;
2825+
for (const Use &U : GEP->operands()) {
2826+
if (!SE->isLoopInvariant(SE->getSCEV(U), Lp)) {
2827+
if (V == Ptr)
2828+
V = U;
2829+
else
2830+
// There must be exactly one loop-variant operand.
2831+
return Ptr;
2832+
}
2833+
}
2834+
return V;
28622835
}
28632836

28642837
/// Get the stride of a pointer access in a loop. Looks for symbolic
@@ -2873,7 +2846,7 @@ static const SCEV *getStrideFromPointer(Value *Ptr, ScalarEvolution *SE, Loop *L
28732846
// pointer, otherwise, we are analyzing the index.
28742847
Value *OrigPtr = Ptr;
28752848

2876-
Ptr = stripGetElementPtr(Ptr, SE, Lp);
2849+
Ptr = getLoopVariantGEPOperand(Ptr, SE, Lp);
28772850
const SCEV *V = SE->getSCEV(Ptr);
28782851

28792852
if (Ptr != OrigPtr)

llvm/test/Analysis/LoopAccessAnalysis/symbolic-stride.ll

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,53 @@ exit:
140140
ret void
141141
}
142142

143+
; Test with multiple GEP indices
144+
define void @single_stride_array(ptr noalias %A, ptr noalias %B, i64 %N, i64 %stride) {
145+
; CHECK-LABEL: 'single_stride_array'
146+
; CHECK-NEXT: loop:
147+
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
148+
; CHECK-NEXT: Backward loop carried data dependence.
149+
; CHECK-NEXT: Dependences:
150+
; CHECK-NEXT: Backward:
151+
; CHECK-NEXT: %load = load [2 x i32], ptr %gep.A, align 4 ->
152+
; CHECK-NEXT: store [2 x i32] %ins, ptr %gep.A.next, align 4
153+
; CHECK-EMPTY:
154+
; CHECK-NEXT: Run-time memory checks:
155+
; CHECK-NEXT: Grouped accesses:
156+
; CHECK-EMPTY:
157+
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
158+
; CHECK-NEXT: SCEV assumptions:
159+
; CHECK-NEXT: Equal predicate: %stride == 1
160+
; CHECK-EMPTY:
161+
; CHECK-NEXT: Expressions re-written:
162+
; CHECK-NEXT: [PSE] %gep.A = getelementptr inbounds [2 x i32], ptr %A, i64 %mul, i64 1:
163+
; CHECK-NEXT: {(4 + %A),+,(8 * %stride)}<%loop>
164+
; CHECK-NEXT: --> {(4 + %A),+,8}<%loop>
165+
;
166+
entry:
167+
br label %loop
168+
169+
loop:
170+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
171+
%mul = mul i64 %iv, %stride
172+
%gep.A = getelementptr inbounds [2 x i32], ptr %A, i64 %mul, i64 1
173+
%load = load [2 x i32], ptr %gep.A, align 4
174+
%gep.B = getelementptr inbounds [2 x i32], ptr %B, i64 %iv
175+
%load_1 = load [2 x i32], ptr %gep.B, align 4
176+
%v1 = extractvalue [2 x i32] %load, 0
177+
%v2 = extractvalue [2 x i32] %load_1, 0
178+
%add = add i32 %v1, %v2
179+
%ins = insertvalue [2 x i32] poison, i32 %add, 0
180+
%iv.next = add nuw nsw i64 %iv, 1
181+
%gep.A.next = getelementptr inbounds [2 x i32], ptr %A, i64 %iv.next
182+
store [2 x i32] %ins, ptr %gep.A.next, align 4
183+
%exitcond = icmp eq i64 %iv.next, %N
184+
br i1 %exitcond, label %exit, label %loop
185+
186+
exit:
187+
ret void
188+
}
189+
143190
define void @single_stride_castexpr(i32 %offset, ptr %src, ptr %dst, i1 %cond) {
144191
; CHECK-LABEL: 'single_stride_castexpr'
145192
; CHECK-NEXT: inner.loop:

0 commit comments

Comments
 (0)