Skip to content

Commit 3dbba8e

Browse files
committed
record runtime predicates on each Dependence relation
1 parent bf9fcfd commit 3dbba8e

File tree

4 files changed

+78
-24
lines changed

4 files changed

+78
-24
lines changed

llvm/include/llvm/Analysis/DependenceAnalysis.h

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define LLVM_ANALYSIS_DEPENDENCEANALYSIS_H
4141

4242
#include "llvm/ADT/SmallBitVector.h"
43+
#include "llvm/Analysis/ScalarEvolution.h"
4344
#include "llvm/IR/Instructions.h"
4445
#include "llvm/IR/PassManager.h"
4546
#include "llvm/Pass.h"
@@ -49,11 +50,7 @@ namespace llvm {
4950
template <typename T> class ArrayRef;
5051
class Loop;
5152
class LoopInfo;
52-
class ScalarEvolution;
53-
class SCEV;
5453
class SCEVConstant;
55-
class SCEVPredicate;
56-
class SCEVUnionPredicate;
5754
class raw_ostream;
5855

5956
/// Dependence - This class represents a dependence between two memory
@@ -76,8 +73,9 @@ namespace llvm {
7673
Dependence &operator=(Dependence &&) = default;
7774

7875
public:
79-
Dependence(Instruction *Source, Instruction *Destination)
80-
: Src(Source), Dst(Destination) {}
76+
Dependence(Instruction *Source, Instruction *Destination,
77+
const SCEVUnionPredicate &A)
78+
: Src(Source), Dst(Destination), Assumptions(A) {}
8179
virtual ~Dependence() = default;
8280

8381
/// Dependence::DVEntry - Each level in the distance/direction vector
@@ -205,6 +203,10 @@ namespace llvm {
205203
/// field.
206204
void setNextSuccessor(const Dependence *succ) { NextSuccessor = succ; }
207205

206+
/// getRuntimeAssumptions - Returns the runtime assumptions under which this
207+
/// Dependence relation is valid.
208+
SCEVUnionPredicate getRuntimeAssumptions() const { return Assumptions; }
209+
208210
/// dump - For debugging purposes, dumps a dependence to OS.
209211
///
210212
void dump(raw_ostream &OS) const;
@@ -213,6 +215,7 @@ namespace llvm {
213215
Instruction *Src, *Dst;
214216

215217
private:
218+
SCEVUnionPredicate Assumptions;
216219
const Dependence *NextPredecessor = nullptr, *NextSuccessor = nullptr;
217220
friend class DependenceInfo;
218221
};
@@ -227,8 +230,9 @@ namespace llvm {
227230
/// input dependences are unordered.
228231
class FullDependence final : public Dependence {
229232
public:
230-
FullDependence(Instruction *Src, Instruction *Dst, bool LoopIndependent,
231-
unsigned Levels);
233+
FullDependence(Instruction *Source, Instruction *Destination,
234+
const SCEVUnionPredicate &Assumes,
235+
bool PossiblyLoopIndependent, unsigned Levels);
232236

233237
/// isLoopIndependent - Returns true if this is a loop-independent
234238
/// dependence.
@@ -304,9 +308,13 @@ namespace llvm {
304308

305309
/// depends - Tests for a dependence between the Src and Dst instructions.
306310
/// Returns NULL if no dependence; otherwise, returns a Dependence (or a
307-
/// FullDependence) with as much information as can be gleaned.
308-
std::unique_ptr<Dependence> depends(Instruction *Src,
309-
Instruction *Dst);
311+
/// FullDependence) with as much information as can be gleaned. By default,
312+
/// the dependence test collects a set of runtime assumptions that cannot be
313+
/// solved at compilation time. Set UnderRuntimeAssumptions to false for a
314+
/// safe approximation of the dependence relation that does not require
315+
/// runtime checks.
316+
std::unique_ptr<Dependence> depends(Instruction *Src, Instruction *Dst,
317+
bool UnderRuntimeAssumptions = true);
310318

311319
/// getSplitIteration - Give a dependence that's splittable at some
312320
/// particular level, return the iteration that should be used to split
@@ -351,7 +359,10 @@ namespace llvm {
351359
const SCEV *getSplitIteration(const Dependence &Dep, unsigned Level);
352360

353361
Function *getFunction() const { return F; }
354-
SCEVUnionPredicate getRuntimeAssumptions();
362+
363+
/// getRuntimeAssumptions - Returns all the runtime assumptions under which
364+
/// the dependence test is valid.
365+
SCEVUnionPredicate getRuntimeAssumptions() const;
355366

356367
private:
357368
AAResults *AA;

llvm/lib/Analysis/DependenceAnalysis.cpp

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,10 @@ bool Dependence::isScalar(unsigned level) const {
269269
// FullDependence methods
270270

271271
FullDependence::FullDependence(Instruction *Source, Instruction *Destination,
272+
const SCEVUnionPredicate &Assumes,
272273
bool PossiblyLoopIndependent,
273274
unsigned CommonLevels)
274-
: Dependence(Source, Destination), Levels(CommonLevels),
275+
: Dependence(Source, Destination, Assumes), Levels(CommonLevels),
275276
LoopIndependent(PossiblyLoopIndependent) {
276277
Consistent = true;
277278
if (CommonLevels)
@@ -711,6 +712,12 @@ void Dependence::dump(raw_ostream &OS) const {
711712
OS << " splitable";
712713
}
713714
OS << "!\n";
715+
716+
SCEVUnionPredicate Assumptions = getRuntimeAssumptions();
717+
if (!Assumptions.isAlwaysTrue()) {
718+
OS << " Runtime Assumptions:\n";
719+
Assumptions.print(OS, 2);
720+
}
714721
}
715722

716723
// Returns NoAlias/MayAliass/MustAlias for two memory locations based upon their
@@ -3574,7 +3581,7 @@ bool DependenceInfo::invalidate(Function &F, const PreservedAnalyses &PA,
35743581
Inv.invalidate<LoopAnalysis>(F, PA);
35753582
}
35763583

3577-
SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() {
3584+
SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() const {
35783585
return SCEVUnionPredicate(Assumptions, *SE);
35793586
}
35803587

@@ -3590,7 +3597,9 @@ SCEVUnionPredicate DependenceInfo::getRuntimeAssumptions() {
35903597
// Care is required to keep the routine below, getSplitIteration(),
35913598
// up to date with respect to this routine.
35923599
std::unique_ptr<Dependence>
3593-
DependenceInfo::depends(Instruction *Src, Instruction *Dst) {
3600+
DependenceInfo::depends(Instruction *Src, Instruction *Dst,
3601+
bool UnderRuntimeAssumptions) {
3602+
SmallVector<const SCEVPredicate *, 4> Assume;
35943603
bool PossiblyLoopIndependent = true;
35953604
if (Src == Dst)
35963605
PossiblyLoopIndependent = false;
@@ -3602,7 +3611,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst) {
36023611
if (!isLoadOrStore(Src) || !isLoadOrStore(Dst)) {
36033612
// can only analyze simple loads and stores, i.e., no calls, invokes, etc.
36043613
LLVM_DEBUG(dbgs() << "can only handle simple loads and stores\n");
3605-
return std::make_unique<Dependence>(Src, Dst);
3614+
return std::make_unique<Dependence>(Src, Dst,
3615+
SCEVUnionPredicate(Assume, *SE));
36063616
}
36073617

36083618
const MemoryLocation &DstLoc = MemoryLocation::get(Dst);
@@ -3613,7 +3623,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst) {
36133623
case AliasResult::PartialAlias:
36143624
// cannot analyse objects if we don't understand their aliasing.
36153625
LLVM_DEBUG(dbgs() << "can't analyze may or partial alias\n");
3616-
return std::make_unique<Dependence>(Src, Dst);
3626+
return std::make_unique<Dependence>(Src, Dst,
3627+
SCEVUnionPredicate(Assume, *SE));
36173628
case AliasResult::NoAlias:
36183629
// If the objects noalias, they are distinct, accesses are independent.
36193630
LLVM_DEBUG(dbgs() << "no alias\n");
@@ -3626,7 +3637,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst) {
36263637
// The dependence test gets confused if the size of the memory accesses
36273638
// differ.
36283639
LLVM_DEBUG(dbgs() << "can't analyze must alias with different sizes\n");
3629-
return std::make_unique<Dependence>(Src, Dst);
3640+
return std::make_unique<Dependence>(Src, Dst,
3641+
SCEVUnionPredicate(Assume, *SE));
36303642
}
36313643

36323644
Value *SrcPtr = getLoadStorePointerOperand(Src);
@@ -3645,7 +3657,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst) {
36453657
// We check this upfront so we don't crash in cases where getMinusSCEV()
36463658
// returns a SCEVCouldNotCompute.
36473659
LLVM_DEBUG(dbgs() << "can't analyze SCEV with different pointer base\n");
3648-
return std::make_unique<Dependence>(Src, Dst);
3660+
return std::make_unique<Dependence>(Src, Dst,
3661+
SCEVUnionPredicate(Assume, *SE));
36493662
}
36503663

36513664
uint64_t EltSize = SrcLoc.Size.toRaw();
@@ -3656,18 +3669,40 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst) {
36563669

36573670
if (Src != Dst) {
36583671
// Check that memory access offsets are multiples of element sizes.
3659-
if (!SE->isKnownMultipleOf(SrcEv, EltSize, Assumptions) ||
3660-
!SE->isKnownMultipleOf(DstEv, EltSize, Assumptions)) {
3672+
if (!SE->isKnownMultipleOf(SrcEv, EltSize, Assume) ||
3673+
!SE->isKnownMultipleOf(DstEv, EltSize, Assume)) {
36613674
LLVM_DEBUG(dbgs() << "can't analyze SCEV with different offsets\n");
3662-
return std::make_unique<Dependence>(Src, Dst);
3675+
return std::make_unique<Dependence>(Src, Dst,
3676+
SCEVUnionPredicate(Assume, *SE));
3677+
}
3678+
}
3679+
3680+
if (!Assume.empty()) {
3681+
if (!UnderRuntimeAssumptions)
3682+
return std::make_unique<Dependence>(Src, Dst,
3683+
SCEVUnionPredicate(Assume, *SE));
3684+
if (Assumptions.empty()) {
3685+
Assumptions.append(Assume.begin(), Assume.end());
3686+
} else {
3687+
// Add non-redundant assumptions.
3688+
unsigned N = Assumptions.size();
3689+
for (const SCEVPredicate *P : Assume) {
3690+
bool Implied = false;
3691+
for (unsigned I = 0; I != N && !Implied; I++)
3692+
if (Assumptions[I]->implies(P, *SE))
3693+
Implied = true;
3694+
if (!Implied)
3695+
Assumptions.push_back(P);
3696+
}
36633697
}
36643698
}
36653699

36663700
establishNestingLevels(Src, Dst);
36673701
LLVM_DEBUG(dbgs() << " common nesting levels = " << CommonLevels << "\n");
36683702
LLVM_DEBUG(dbgs() << " maximum nesting levels = " << MaxLevels << "\n");
36693703

3670-
FullDependence Result(Src, Dst, PossiblyLoopIndependent, CommonLevels);
3704+
FullDependence Result(Src, Dst, SCEVUnionPredicate(Assume, *SE),
3705+
PossiblyLoopIndependent, CommonLevels);
36713706
++TotalArrayPairs;
36723707

36733708
unsigned Pairs = 1;
@@ -4065,7 +4100,7 @@ const SCEV *DependenceInfo::getSplitIteration(const Dependence &Dep,
40654100
// establish loop nesting levels
40664101
establishNestingLevels(Src, Dst);
40674102

4068-
FullDependence Result(Src, Dst, false, CommonLevels);
4103+
FullDependence Result(Src, Dst, Dep.Assumptions, false, CommonLevels);
40694104

40704105
unsigned Pairs = 1;
40714106
SmallVector<Subscript, 2> Pair(Pairs);

llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ define i32 @alias_with_parametric_offset(ptr nocapture %A, i64 %n) {
3030
; CHECK-NEXT: da analyze - none!
3131
; CHECK-NEXT: Src: store i32 2, ptr %arrayidx, align 1 --> Dst: %0 = load i32, ptr %A, align 1
3232
; CHECK-NEXT: da analyze - flow [|<]!
33+
; CHECK-NEXT: Runtime Assumptions:
34+
; CHECK-NEXT: Equal predicate: (zext i2 (trunc i64 %n to i2) to i64) == 0
3335
; CHECK-NEXT: Src: %0 = load i32, ptr %A, align 1 --> Dst: %0 = load i32, ptr %A, align 1
3436
; CHECK-NEXT: da analyze - none!
3537
; CHECK-NEXT: Runtime Assumptions:
@@ -48,6 +50,9 @@ define i32 @alias_with_parametric_expr(ptr nocapture %A, i64 %n, i64 %m) {
4850
; CHECK-NEXT: da analyze - none!
4951
; CHECK-NEXT: Src: store i32 2, ptr %arrayidx, align 1 --> Dst: %0 = load i32, ptr %arrayidx1, align 1
5052
; CHECK-NEXT: da analyze - flow [|<]!
53+
; CHECK-NEXT: Runtime Assumptions:
54+
; CHECK-NEXT: Equal predicate: (zext i2 ((trunc i64 %m to i2) + (-2 * (trunc i64 %n to i2))) to i64) == 0
55+
; CHECK-NEXT: Equal predicate: (zext i2 (-2 + (trunc i64 %m to i2)) to i64) == 0
5156
; CHECK-NEXT: Src: %0 = load i32, ptr %arrayidx1, align 1 --> Dst: %0 = load i32, ptr %arrayidx1, align 1
5257
; CHECK-NEXT: da analyze - none!
5358
; CHECK-NEXT: Runtime Assumptions:

llvm/test/Analysis/DependenceAnalysis/MIVCheckConst.ll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ define void @test(ptr %A, ptr %B, i1 %arg, i32 %n, i32 %m) #0 align 2 {
4242
; CHECK-NEXT: da analyze - consistent input [0 S S]!
4343
; CHECK-NEXT: Src: %v27 = load <32 x i32>, ptr %v25, align 256 --> Dst: %v32 = load <32 x i32>, ptr %v30, align 128
4444
; CHECK-NEXT: da analyze - input [* S S|<]!
45+
; CHECK-NEXT: Runtime Assumptions:
46+
; CHECK-NEXT: Equal predicate: (zext i7 (4 * (trunc i32 %v1 to i7) * (1 + (trunc i32 %n to i7))) to i32) == 0
47+
; CHECK-NEXT: Equal predicate: (8 * (zext i4 (trunc i32 %v1 to i4) to i32))<nuw><nsw> == 0
4548
; CHECK-NEXT: Src: %v32 = load <32 x i32>, ptr %v30, align 128 --> Dst: %v32 = load <32 x i32>, ptr %v30, align 128
4649
; CHECK-NEXT: da analyze - consistent input [0 S S]!
4750
; CHECK-NEXT: Runtime Assumptions:

0 commit comments

Comments
 (0)