Skip to content

Commit 564ddfb

Browse files
committed
[TSAR, Memory] Extend private array analysis with non-constant loop bounds.
1 parent 6f012f9 commit 564ddfb

File tree

5 files changed

+505
-126
lines changed

5 files changed

+505
-126
lines changed

include/tsar/Analysis/Memory/MemoryLocationRange.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <llvm/ADT/BitmaskEnum.h>
3030
#include <llvm/Analysis/MemoryLocation.h>
3131
#include <llvm/Analysis/ScalarEvolution.h>
32+
#include <llvm/Analysis/ScalarEvolutionExpressions.h>
3233

3334
namespace tsar {
3435

@@ -61,6 +62,32 @@ struct MemoryLocationRange {
6162
return Start == Other.Start && End == Other.End && Step == Other.Step &&
6263
DimSize == Other.DimSize;
6364
}
65+
inline void print(llvm::raw_ostream &OS, bool IsDebug = false) const {
66+
auto PrintSCEV = [](const llvm::SCEV *Expr, llvm::raw_ostream &OS) {
67+
if (!Expr)
68+
OS << "(nullptr)";
69+
else
70+
Expr->print(OS);
71+
};
72+
if (IsDebug) {
73+
OS << "{Start: ";
74+
PrintSCEV(Start, OS);
75+
OS << ", End: ";
76+
PrintSCEV(End, OS);
77+
OS << ", Step: ";
78+
PrintSCEV(Step, OS);
79+
OS << ", DimSize: " << DimSize << "}";
80+
} else {
81+
OS << "[";
82+
PrintSCEV(Start, OS);
83+
OS << ":";
84+
PrintSCEV(End, OS);
85+
OS << ":";
86+
PrintSCEV(Step, OS);
87+
OS << "," << DimSize;
88+
OS << "]";
89+
}
90+
}
6491
};
6592

6693
const llvm::Value * Ptr;
@@ -227,6 +254,18 @@ llvm::Optional<MemoryLocationRange> intersect(
227254
llvm::SmallVectorImpl<MemoryLocationRange> *LC = nullptr,
228255
llvm::SmallVectorImpl<MemoryLocationRange> *RC = nullptr,
229256
unsigned Threshold = 10);
257+
258+
/// TODO: description.
259+
/// Returns distance between LHS and RHS.
260+
inline llvm::Optional<int64_t> compareSCEVs(const llvm::SCEV *LHS,
261+
const llvm::SCEV *RHS,
262+
llvm::ScalarEvolution *SE) {
263+
assert(SE && "ScalarEvolution must be specified!");
264+
assert(LHS && RHS && "SCEV must be specified!");
265+
if (auto Const = llvm::dyn_cast<llvm::SCEVConstant>(SE->getMinusSCEV(LHS, RHS)))
266+
return Const->getAPInt().getSExtValue();
267+
return llvm::None;
268+
}
230269
}
231270

232271
namespace llvm {

include/tsar/Analysis/Memory/MemorySetInfo.h

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#include "tsar/Analysis/Memory/MemoryLocationRange.h"
2929
#include <llvm/Analysis/ScalarEvolutionExpressions.h>
3030

31+
using llvm::cast;
32+
using llvm::dyn_cast;
33+
using llvm::isa;
34+
using llvm::SCEVConstant;
35+
3136
namespace tsar {
3237
/// Provide traits for objects stored in a MemorySet.
3338
///
@@ -238,22 +243,30 @@ template<> struct MemorySetInfo<MemoryLocationRange> {
238243
auto &Right = RHS.DimList[I];
239244
if (Left == Right)
240245
continue;
241-
auto LeftStartConst = llvm::dyn_cast<llvm::SCEVConstant>(Left.Start);
242-
auto LeftEndConst = llvm::dyn_cast<llvm::SCEVConstant>(Left.End);
243-
auto LeftStepConst = llvm::dyn_cast<llvm::SCEVConstant>(Left.Step);
244-
auto RightStartConst = llvm::dyn_cast<llvm::SCEVConstant>(Right.Start);
245-
auto RightEndConst = llvm::dyn_cast<llvm::SCEVConstant>(Right.End);
246-
auto RightStepConst = llvm::dyn_cast<llvm::SCEVConstant>(Right.Step);
247-
assert(LeftStepConst && RightStepConst &&
246+
assert(isa<SCEVConstant>(Left.Step) && isa<SCEVConstant>(Right.Step) &&
248247
"Dimension step must be constant!");
249-
assert(LeftStartConst && LeftEndConst && RightStartConst &&
250-
RightEndConst && "Dimension bounds must be constant!");
251-
auto LeftStart = LeftStartConst->getValue()->getZExtValue();
252-
auto LeftEnd = LeftEndConst->getValue()->getZExtValue();
253-
auto LeftStep = LeftStepConst->getValue()->getZExtValue();
254-
auto RightStart = RightStartConst->getValue()->getZExtValue();
255-
auto RightEnd = RightEndConst->getValue()->getZExtValue();
256-
auto RightStep = RightStepConst->getValue()->getZExtValue();
248+
if (!isa<SCEVConstant>(Left.Start) || !isa<SCEVConstant>(Left.End) ||
249+
!isa<SCEVConstant>(Right.Start) || !isa<SCEVConstant>(Right.End)) {
250+
auto CmpLeftStartRightEnd = compareSCEVs(Left.Start, Right.End, SE);
251+
auto CmpRightStartLeftEnd = compareSCEVs(Right.Start, Left.End, SE);
252+
if (CmpLeftStartRightEnd && (*CmpLeftStartRightEnd == 0 || *CmpLeftStartRightEnd == 1) ||
253+
CmpRightStartLeftEnd && (*CmpRightStartLeftEnd == 0 || *CmpRightStartLeftEnd == 1))
254+
++JoinableDimCount;
255+
else
256+
return false;
257+
}
258+
auto LeftStart = cast<SCEVConstant>(Left.Start)->
259+
getValue()->getZExtValue();
260+
auto LeftEnd = cast<SCEVConstant>(Left.End)->
261+
getValue()->getZExtValue();
262+
auto LeftStep = cast<SCEVConstant>(Left.Step)->
263+
getValue()->getZExtValue();
264+
auto RightStart = cast<SCEVConstant>(Right.Start)->
265+
getValue()->getZExtValue();
266+
auto RightEnd = cast<SCEVConstant>(Right.End)->
267+
getValue()->getZExtValue();
268+
auto RightStep = cast<SCEVConstant>(Right.Step)->
269+
getValue()->getZExtValue();
257270
assert(LeftStart <= LeftEnd && RightStart <= RightEnd &&
258271
"Start of dimension must be less or equal than End.");
259272
if (LeftStep != RightStep ||
@@ -285,20 +298,34 @@ template<> struct MemorySetInfo<MemoryLocationRange> {
285298
IsChanged = true;
286299
}
287300
} else {
301+
auto SE = What.SE;
302+
assert(SE && "ScalarEvolution must be specified!");
288303
for (size_t I = 0; I < To.DimList.size(); I++) {
289304
auto &DimTo = To.DimList[I];
290305
auto &DimFrom = What.DimList[I];
291-
auto Diff = llvm::dyn_cast<llvm::SCEVConstant>(
292-
What.SE->getMinusSCEV(DimTo.Start, DimFrom.Start));
293-
assert(Diff && "Difference must be constant!");
294-
if (Diff->getValue()->getSExtValue() > 0) {
306+
if (!isa<SCEVConstant>(DimTo.Start) || !isa<SCEVConstant>(DimTo.End) ||
307+
!isa<SCEVConstant>(DimFrom.Start) || !isa<SCEVConstant>(DimFrom.End)) {
308+
auto CmpFromEndToStart = compareSCEVs(DimTo.Start, DimFrom.End, SE);
309+
auto CmpToEndFromStart = compareSCEVs(DimFrom.Start, DimTo.End, SE);
310+
if (CmpFromEndToStart && (*CmpFromEndToStart == 0 || *CmpFromEndToStart == 1)) {
311+
DimTo.Start = DimFrom.Start;
312+
IsChanged = true;
313+
}
314+
if (CmpToEndFromStart && (*CmpToEndFromStart == 0 || *CmpToEndFromStart == 1)) {
315+
DimTo.End = DimFrom.End;
316+
IsChanged = true;
317+
}
318+
continue;
319+
}
320+
auto DiffStart = compareSCEVs(DimTo.Start, DimFrom.Start, SE);
321+
assert(DiffStart && "Difference must be constant!");
322+
if (*DiffStart > 0) {
295323
DimTo.Start = DimFrom.Start;
296324
IsChanged = true;
297325
}
298-
Diff = llvm::dyn_cast<llvm::SCEVConstant>(
299-
What.SE->getMinusSCEV(DimFrom.End, DimTo.End));
300-
assert(Diff && "Difference must be constant!");
301-
if (Diff->getValue()->getSExtValue() > 0) {
326+
auto DiffEnd = compareSCEVs(DimFrom.End, DimTo.End, SE);
327+
assert(DiffEnd && "Difference must be constant!");
328+
if (*DiffEnd > 0) {
302329
DimTo.End = DimFrom.End;
303330
IsChanged = true;
304331
}

lib/Analysis/Memory/DefinedMemory.cpp

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ std::pair<MemoryLocationRange, bool> aggregate(
250250
DFRegion *R, const MemoryLocationRange &Loc, const ReachDFFwk *Fwk) {
251251
typedef MemoryLocationRange::Dimension Dimension;
252252
typedef MemoryLocationRange::LocKind LocKind;
253+
typedef ICmpInst::Predicate Predicate;
253254
assert(Fwk && "Data-flow framework must not be null");
254255
assert(!(Loc.Kind & LocKind::Collapsed) || Loc.DimList.size() > 0 &&
255256
"Collapsed array location must not be empty!");
@@ -351,28 +352,113 @@ std::pair<MemoryLocationRange, bool> aggregate(
351352
LLVM_DEBUG(dbgs() << "[AGGREGATE] Non-constant step.\n");
352353
break;
353354
}
355+
auto AddRecStep = cast<SCEVConstant>(StepSCEV)->getAPInt().getSExtValue();
354356
auto TripCount = SE->getSmallConstantTripCount(C->getLoop());
355-
if (TripCount <= 1) {
356-
LLVM_DEBUG(dbgs() << "[AGGREGATE] Unknown or non-constant "
357-
"trip count.\n");
358-
break;
359-
}
360-
auto StartValue = SE->getSignedRangeMin(SCEV).getSExtValue();
361-
if (StartValue < 0) {
362-
LLVM_DEBUG(dbgs() << "[AGGREGATE] Range bounds must be "
363-
"non-negative.\n");
357+
if (TripCount > 1) {
358+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Aggregate constant range.\n");
359+
int64_t SignedRangeMin = SE->getSignedRangeMin(SCEV).getSExtValue();
360+
if (SignedRangeMin < 0) {
361+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Range bounds must be "
362+
"non-negative.\n");
363+
break;
364+
}
365+
DimInfo.Start = SE->getConstant(Int64Ty, SignedRangeMin);
366+
DimInfo.End = SE->getConstant(Int64Ty,
367+
SignedRangeMin + std::abs(AddRecStep) * (TripCount - 2));
368+
} else if (TripCount == 0) {
369+
if (std::abs(AddRecStep) != 1)
370+
break;
371+
auto Bounds = C->getLoop()->getBounds(*SE);
372+
if (!Bounds) {
373+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Failed to get loop bounds.\n");
374+
break;
375+
}
376+
auto *InitValue = &Bounds->getInitialIVValue();
377+
auto *FinalValue = &Bounds->getFinalIVValue();
378+
if (!SE->isSCEVable(InitValue->getType()) ||
379+
!SE->isSCEVable(FinalValue->getType())) {
380+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Loop bound is not SCEVable.\n");
381+
break;
382+
}
383+
if (!InitValue->getType()->isIntegerTy() ||
384+
!FinalValue->getType()->isIntegerTy()) {
385+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Non-integer loop bound.\n");
386+
break;
387+
}
388+
auto Predicate = Bounds->getCanonicalPredicate();
389+
if (!ICmpInst::isRelational(Predicate)) {
390+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Bad predicate.\n");
391+
break;
392+
}
393+
if (Bounds->getDirection() == Loop::LoopBounds::Direction::Unknown) {
394+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Unknown direction.\n");
395+
break;
396+
}
397+
auto LoopStep = cast<SCEVConstant>(
398+
SE->getSCEV(Bounds->getStepValue()))->getAPInt().getSExtValue();
399+
auto InitSCEV = SE->getSCEV(InitValue);
400+
auto FinalSCEV = SE->getSCEV(FinalValue);
401+
if (Bounds->getDirection() == Loop::LoopBounds::Direction::Increasing &&
402+
(Predicate == Predicate::ICMP_SGT ||
403+
Predicate == Predicate::ICMP_SGE ||
404+
Predicate == Predicate::ICMP_UGT ||
405+
Predicate == Predicate::ICMP_UGE) ||
406+
(Bounds->getDirection() == Loop::LoopBounds::Direction::Decreasing &&
407+
(Predicate == Predicate::ICMP_SLT ||
408+
Predicate == Predicate::ICMP_SLE ||
409+
Predicate == Predicate::ICMP_ULT ||
410+
Predicate == Predicate::ICMP_ULE))) {
411+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Unpredictable predicate.\n");
412+
break;
413+
}
414+
if (Bounds->getDirection() == Loop::LoopBounds::Direction::Increasing) {
415+
if (Predicate == Predicate::ICMP_SLT ||
416+
Predicate == Predicate::ICMP_ULT) {
417+
FinalSCEV = SE->getMinusSCEV(FinalSCEV, SE->getOne(Int64Ty));
418+
}
419+
} else {
420+
//std::swap(InitSCEV, FinalSCEV);
421+
if (Predicate == Predicate::ICMP_SGT ||
422+
Predicate == Predicate::ICMP_UGT) {
423+
FinalSCEV = SE->getAddExpr(SE->getOne(Int64Ty), FinalSCEV);
424+
}
425+
}
426+
auto ZeroItr = C->evaluateAtIteration(SE->getZero(Int64Ty), *SE);
427+
auto IdxExprStep = AddRecStep / LoopStep;
428+
LLVM_DEBUG(dbgs() << "[AGGREGATE] LoopStep: " << LoopStep <<
429+
", IdxExprStep: " << IdxExprStep << "\n");
430+
if (LoopStep > 0 && IdxExprStep > 0) {
431+
DimInfo.Start = ZeroItr;
432+
DimInfo.End = C->evaluateAtIteration(
433+
SE->getMinusSCEV(FinalSCEV, InitSCEV), *SE);
434+
} else if (LoopStep > 0 && IdxExprStep < 0) {
435+
DimInfo.Start = C->evaluateAtIteration(
436+
SE->getMinusSCEV(FinalSCEV, InitSCEV), *SE);
437+
DimInfo.End = ZeroItr;
438+
} else if (LoopStep < 0 && IdxExprStep > 0) {
439+
DimInfo.Start = C->evaluateAtIteration(
440+
SE->getMinusSCEV(InitSCEV, FinalSCEV), *SE);
441+
DimInfo.End = ZeroItr;
442+
} else {
443+
DimInfo.Start = ZeroItr;
444+
DimInfo.End = C->evaluateAtIteration(
445+
SE->getMinusSCEV(InitSCEV, FinalSCEV), *SE);
446+
}
447+
auto CmpStartEnd = compareSCEVs(DimInfo.Start, DimInfo.End, SE);
448+
if (CmpStartEnd && *CmpStartEnd > 0) {
449+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Incorrect bounds.\n");
450+
break;
451+
}
452+
} else {
453+
LLVM_DEBUG(dbgs() << "[AGGREGATE] Invalid trip count.\n");
364454
break;
365455
}
366-
DimInfo.Start = SE->getConstant(Int64Ty, StartValue);
367-
auto StepValue = std::abs(cast<SCEVConstant>(StepSCEV)->getAPInt().
368-
getSExtValue());
369-
DimInfo.Step = SE->getConstant(Int64Ty, StepValue);
370-
DimInfo.End = SE->getConstant(Int64Ty,
371-
StartValue + (TripCount - 2) * StepValue);
456+
DimInfo.Step = SE->getConstant(Int64Ty, std::abs(AddRecStep));
372457
assert(DimInfo.Start && DimInfo.End && DimInfo.Step &&
373458
"Dimension bounds and step must be specified!");
374-
if (StartValue + StepValue * (TripCount - 2) >= DimInfo.DimSize &&
375-
DimensionN != 0) {
459+
if (isa<SCEVConstant>(DimInfo.End) &&
460+
cast<SCEVConstant>(DimInfo.End)->getAPInt().
461+
getSExtValue() >= DimInfo.DimSize && DimensionN != 0) {
376462
LLVM_DEBUG(dbgs() << "[AGGREGATE] Array index out of bounds.");
377463
break;
378464
}

0 commit comments

Comments
 (0)