Skip to content

Commit bff0b1b

Browse files
committed
[DA] do not handle array accesses of different offsets
The patch adds a testcase that is not supposed to be disambiguated by the DA. Most of the code of the filter is disabled under FIXME comments. There is not much DA can do to prove properties on symbolic expressions. Polly collects all assumptions under which data dependences and code-gen are valid. DA needs a similar mechanism. Without collecting assumptions, half the testsuite fails.
1 parent ee9862d commit bff0b1b

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

llvm/lib/Analysis/DependenceAnalysis.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3632,7 +3632,9 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
36323632
const SCEV *DstSCEV = SE->getSCEV(DstPtr);
36333633
LLVM_DEBUG(dbgs() << " SrcSCEV = " << *SrcSCEV << "\n");
36343634
LLVM_DEBUG(dbgs() << " DstSCEV = " << *DstSCEV << "\n");
3635-
if (SE->getPointerBase(SrcSCEV) != SE->getPointerBase(DstSCEV)) {
3635+
const SCEV *SrcBase = SE->getPointerBase(SrcSCEV);
3636+
const SCEV *DstBase = SE->getPointerBase(DstSCEV);
3637+
if (SrcBase != DstBase) {
36363638
// If two pointers have different bases, trying to analyze indexes won't
36373639
// work; we can't compare them to each other. This can happen, for example,
36383640
// if one is produced by an LCSSA PHI node.
@@ -3643,6 +3645,57 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
36433645
return std::make_unique<Dependence>(Src, Dst);
36443646
}
36453647

3648+
std::function<bool(ScalarEvolution *, const SCEV *, uint64_t)>
3649+
checkOffsetsAndStrides =
3650+
[&](ScalarEvolution *SE, const SCEV *V, uint64_t Size) -> bool {
3651+
if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(V)) {
3652+
if (!checkOffsetsAndStrides(SE, AddRec->getStart(), Size))
3653+
return false;
3654+
return checkOffsetsAndStrides(SE, AddRec->getStepRecurrence(*SE), Size);
3655+
}
3656+
if (auto *Cst = dyn_cast<SCEVConstant>(V)) {
3657+
APInt C = Cst->getAPInt();
3658+
return C.srem(Size) == 0;
3659+
}
3660+
if (auto *Add = dyn_cast<SCEVAddExpr>(V)) {
3661+
// FIXME: DA cannot reason about expressions containing SSA names.
3662+
return true;
3663+
// If the expression contains variable names, i.e., "n + 1", then we
3664+
// cannot reason about the coefficients of V being multiples of Size.
3665+
if (SCEVExprContains(V, [](const SCEV *S) { return isa<SCEVUnknown>(S); }))
3666+
return false;
3667+
for (const SCEV *AddOp : Add->operands()) {
3668+
if (!checkOffsetsAndStrides(SE, AddOp, Size))
3669+
return false;
3670+
}
3671+
return true;
3672+
}
3673+
if (auto *Mul = dyn_cast<SCEVMulExpr>(V)) {
3674+
// FIXME: DA cannot reason about expressions containing SSA names.
3675+
return true;
3676+
// If the expression contains variable names, i.e., "n * 3", then we
3677+
// cannot reason about the coefficients of V being multiples of Size.
3678+
if (SCEVExprContains(V, [](const SCEV *S) { return isa<SCEVUnknown>(S); }))
3679+
return false;
3680+
for (const SCEV *MulOp : Mul->operands()) {
3681+
if (!checkOffsetsAndStrides(SE, MulOp, Size))
3682+
return false;
3683+
}
3684+
return true;
3685+
}
3686+
// SCEV node not handled yet.
3687+
return false;
3688+
};
3689+
3690+
// Check that memory access offsets are multiples of element sizes.
3691+
const SCEV *SrcEv = SE->getMinusSCEV(SrcSCEV, SrcBase);
3692+
const SCEV *DstEv = SE->getMinusSCEV(DstSCEV, DstBase);
3693+
if (!checkOffsetsAndStrides(SE, SrcEv, SrcLoc.Size.toRaw()) ||
3694+
!checkOffsetsAndStrides(SE, DstEv, DstLoc.Size.toRaw())) {
3695+
LLVM_DEBUG(dbgs() << "can't analyze SCEV with different offsets\n");
3696+
return std::make_unique<Dependence>(Src, Dst);
3697+
}
3698+
36463699
// establish loop nesting levels
36473700
establishNestingLevels(Src, Dst);
36483701
LLVM_DEBUG(dbgs() << " common nesting levels = " << CommonLevels << "\n");
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -disable-output "-passes=print<da>" -aa-pipeline=basic-aa 2>&1 \
3+
; RUN: | FileCheck %s
4+
5+
; The dependence test does not handle array accesses with difference between array accesses
6+
; is not a multiple of the array element size.
7+
8+
; In this test, the element size is i32 = 4 bytes and the difference between the
9+
; load and the store is 2 bytes.
10+
11+
define i32 @alias_with_different_offsets(ptr nocapture %A) {
12+
; CHECK-LABEL: 'alias_with_different_offsets'
13+
; CHECK-NEXT: Src: store i32 2, ptr %arrayidx, align 1 --> Dst: store i32 2, ptr %arrayidx, align 1
14+
; CHECK-NEXT: da analyze - confused!
15+
; CHECK-NEXT: Src: store i32 2, ptr %arrayidx, align 1 --> Dst: %0 = load i32, ptr %A, align 1
16+
; CHECK-NEXT: da analyze - confused!
17+
; CHECK-NEXT: Src: %0 = load i32, ptr %A, align 1 --> Dst: %0 = load i32, ptr %A, align 1
18+
; CHECK-NEXT: da analyze - none!
19+
;
20+
entry:
21+
%arrayidx = getelementptr inbounds i8, ptr %A, i64 2
22+
store i32 2, ptr %arrayidx, align 1
23+
%0 = load i32, ptr %A, align 1
24+
ret i32 %0
25+
}

0 commit comments

Comments
 (0)