@@ -128,6 +128,18 @@ static cl::opt<bool> RunSIVRoutinesOnly(
128128 " The purpose is mainly to exclude the influence of those routines "
129129 " in regression tests for SIV routines." ));
130130
131+ // TODO: This flag is disabled by default because it is still under development.
132+ // Enable it or delete this flag when the feature is ready.
133+ static cl::opt<bool > EnableMonotonicityCheck (
134+ " da-enable-monotonicity-check" , cl::init(false ), cl::Hidden,
135+ cl::desc(" Check if the subscripts are monotonic. If it's not, dependence "
136+ " is reported as unknown." ));
137+
138+ static cl::opt<bool > DumpMonotonicityReport (
139+ " da-dump-monotonicity-report" , cl::init(false ), cl::Hidden,
140+ cl::desc(
141+ " When printing analysis, dump the results of monotonicity checks." ));
142+
131143// ===----------------------------------------------------------------------===//
132144// basics
133145
@@ -177,13 +189,196 @@ void DependenceAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
177189 AU.addRequiredTransitive <LoopInfoWrapperPass>();
178190}
179191
192+ namespace {
193+
194+ // / The property of monotonicity of a SCEV. To define the monotonicity, assume
195+ // / a SCEV defined within N-nested loops. Let i_k denote the iteration number
196+ // / of the k-th loop. Then we can regard the SCEV as an N-ary function:
197+ // /
198+ // / F(i_1, i_2, ..., i_N)
199+ // /
200+ // / The domain of i_k is the closed range [0, BTC_k], where BTC_k is the
201+ // / backedge-taken count of the k-th loop.
202+ // /
203+ // / A function F is said to be "monotonically increasing with respect to the
204+ // / k-th loop" if x <= y implies the following condition:
205+ // /
206+ // / F(i_1, ..., i_{k-1}, x, i_{k+1}, ..., i_N) <=
207+ // / F(i_1, ..., i_{k-1}, y, i_{k+1}, ..., i_N)
208+ // /
209+ // / where i_1, ..., i_{k-1}, i_{k+1}, ..., i_N, x, and y are elements of their
210+ // / respective domains.
211+ // /
212+ // / Likewise F is "monotonically decreasing with respect to the k-th loop"
213+ // / if x <= y implies
214+ // /
215+ // / F(i_1, ..., i_{k-1}, x, i_{k+1}, ..., i_N) >=
216+ // / F(i_1, ..., i_{k-1}, y, i_{k+1}, ..., i_N)
217+ // /
218+ // / A function F that is monotonically increasing or decreasing with respect to
219+ // / the k-th loop is simply called "monotonic with respect to k-th loop".
220+ // /
221+ // / A function F is said to be "multivariate monotonic" when it is monotonic
222+ // / with respect to all of the N loops.
223+ // /
224+ // / Since integer comparison can be either signed or unsigned, we need to
225+ // / distinguish monotonicity in the signed sense from that in the unsigned
226+ // / sense. Note that the inequality "x <= y" merely indicates loop progression
227+ // / and is not affected by the difference between signed and unsigned order.
228+ // /
229+ // / Currently we only consider monotonicity in a signed sense.
230+ enum class SCEVMonotonicityType {
231+ // / We don't know anything about the monotonicity of the SCEV.
232+ Unknown,
233+
234+ // / The SCEV is loop-invariant with respect to the outermost loop. In other
235+ // / words, the function F corresponding to the SCEV is a constant function.
236+ Invariant,
237+
238+ // / The function F corresponding to the SCEV is multivariate monotonic in a
239+ // / signed sense. Note that the multivariate monotonic function may also be a
240+ // / constant function. The order employed in the definition of monotonicity
241+ // / is not strict order.
242+ MultivariateSignedMonotonic,
243+ };
244+
245+ struct SCEVMonotonicity {
246+ SCEVMonotonicity (SCEVMonotonicityType Type,
247+ const SCEV *FailurePoint = nullptr );
248+
249+ SCEVMonotonicityType getType () const { return Type; }
250+
251+ const SCEV *getFailurePoint () const { return FailurePoint; }
252+
253+ bool isUnknown () const { return Type == SCEVMonotonicityType::Unknown; }
254+
255+ void print (raw_ostream &OS, unsigned Depth) const ;
256+
257+ private:
258+ SCEVMonotonicityType Type;
259+
260+ // / The subexpression that caused Unknown. Mainly for debugging purpose.
261+ const SCEV *FailurePoint;
262+ };
263+
264+ // / Check the monotonicity of a SCEV. Since dependence tests (SIV, MIV, etc.)
265+ // / assume that subscript expressions are (multivariate) monotonic, we need to
266+ // / verify this property before applying those tests. Violating this assumption
267+ // / may cause them to produce incorrect results.
268+ struct SCEVMonotonicityChecker
269+ : public SCEVVisitor<SCEVMonotonicityChecker, SCEVMonotonicity> {
270+
271+ SCEVMonotonicityChecker (ScalarEvolution *SE) : SE(SE) {}
272+
273+ // / Check the monotonicity of \p Expr. \p Expr must be integer type. If \p
274+ // / OutermostLoop is not null, \p Expr must be defined in \p OutermostLoop or
275+ // / one of its nested loops.
276+ SCEVMonotonicity checkMonotonicity (const SCEV *Expr,
277+ const Loop *OutermostLoop);
278+
279+ private:
280+ ScalarEvolution *SE;
281+
282+ // / The outermost loop that DA is analyzing.
283+ const Loop *OutermostLoop;
284+
285+ // / A helper to classify \p Expr as either Invariant or Unknown.
286+ SCEVMonotonicity invariantOrUnknown (const SCEV *Expr);
287+
288+ // / Return true if \p Expr is loop-invariant with respect to the outermost
289+ // / loop.
290+ bool isLoopInvariant (const SCEV *Expr) const ;
291+
292+ // / A helper to create an Unknown SCEVMonotonicity.
293+ SCEVMonotonicity createUnknown (const SCEV *FailurePoint) {
294+ return SCEVMonotonicity (SCEVMonotonicityType::Unknown, FailurePoint);
295+ }
296+
297+ SCEVMonotonicity visitAddRecExpr (const SCEVAddRecExpr *Expr);
298+
299+ SCEVMonotonicity visitConstant (const SCEVConstant *) {
300+ return SCEVMonotonicity (SCEVMonotonicityType::Invariant);
301+ }
302+ SCEVMonotonicity visitVScale (const SCEVVScale *) {
303+ return SCEVMonotonicity (SCEVMonotonicityType::Invariant);
304+ }
305+
306+ // TODO: Handle more cases.
307+ SCEVMonotonicity visitZeroExtendExpr (const SCEVZeroExtendExpr *Expr) {
308+ return invariantOrUnknown (Expr);
309+ }
310+ SCEVMonotonicity visitSignExtendExpr (const SCEVSignExtendExpr *Expr) {
311+ return invariantOrUnknown (Expr);
312+ }
313+ SCEVMonotonicity visitAddExpr (const SCEVAddExpr *Expr) {
314+ return invariantOrUnknown (Expr);
315+ }
316+ SCEVMonotonicity visitMulExpr (const SCEVMulExpr *Expr) {
317+ return invariantOrUnknown (Expr);
318+ }
319+ SCEVMonotonicity visitPtrToIntExpr (const SCEVPtrToIntExpr *Expr) {
320+ return invariantOrUnknown (Expr);
321+ }
322+ SCEVMonotonicity visitTruncateExpr (const SCEVTruncateExpr *Expr) {
323+ return invariantOrUnknown (Expr);
324+ }
325+ SCEVMonotonicity visitUDivExpr (const SCEVUDivExpr *Expr) {
326+ return invariantOrUnknown (Expr);
327+ }
328+ SCEVMonotonicity visitSMaxExpr (const SCEVSMaxExpr *Expr) {
329+ return invariantOrUnknown (Expr);
330+ }
331+ SCEVMonotonicity visitUMaxExpr (const SCEVUMaxExpr *Expr) {
332+ return invariantOrUnknown (Expr);
333+ }
334+ SCEVMonotonicity visitSMinExpr (const SCEVSMinExpr *Expr) {
335+ return invariantOrUnknown (Expr);
336+ }
337+ SCEVMonotonicity visitUMinExpr (const SCEVUMinExpr *Expr) {
338+ return invariantOrUnknown (Expr);
339+ }
340+ SCEVMonotonicity visitSequentialUMinExpr (const SCEVSequentialUMinExpr *Expr) {
341+ return invariantOrUnknown (Expr);
342+ }
343+ SCEVMonotonicity visitUnknown (const SCEVUnknown *Expr) {
344+ return invariantOrUnknown (Expr);
345+ }
346+ SCEVMonotonicity visitCouldNotCompute (const SCEVCouldNotCompute *Expr) {
347+ return invariantOrUnknown (Expr);
348+ }
349+
350+ friend struct SCEVVisitor <SCEVMonotonicityChecker, SCEVMonotonicity>;
351+ };
352+
353+ } // anonymous namespace
354+
180355// Used to test the dependence analyzer.
181356// Looks through the function, noting instructions that may access memory.
182357// Calls depends() on every possible pair and prints out the result.
183358// Ignores all other instructions.
184359static void dumpExampleDependence (raw_ostream &OS, DependenceInfo *DA,
185- ScalarEvolution &SE, bool NormalizeResults) {
360+ ScalarEvolution &SE, LoopInfo &LI,
361+ bool NormalizeResults) {
186362 auto *F = DA->getFunction ();
363+
364+ if (DumpMonotonicityReport) {
365+ SCEVMonotonicityChecker Checker (&SE);
366+ OS << " Monotonicity check:\n " ;
367+ for (Instruction &Inst : instructions (F)) {
368+ if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
369+ continue ;
370+ Value *Ptr = getLoadStorePointerOperand (&Inst);
371+ const Loop *L = LI.getLoopFor (Inst.getParent ());
372+ const SCEV *PtrSCEV = SE.getSCEVAtScope (Ptr, L);
373+ const SCEV *AccessFn = SE.removePointerBase (PtrSCEV);
374+ SCEVMonotonicity Mon = Checker.checkMonotonicity (AccessFn, L);
375+ OS.indent (2 ) << " Inst: " << Inst << " \n " ;
376+ OS.indent (4 ) << " Expr: " << *AccessFn << " \n " ;
377+ Mon.print (OS, 4 );
378+ }
379+ OS << " \n " ;
380+ }
381+
187382 for (inst_iterator SrcI = inst_begin (F), SrcE = inst_end (F); SrcI != SrcE;
188383 ++SrcI) {
189384 if (SrcI->mayReadOrWriteMemory ()) {
@@ -235,7 +430,8 @@ static void dumpExampleDependence(raw_ostream &OS, DependenceInfo *DA,
235430void DependenceAnalysisWrapperPass::print (raw_ostream &OS,
236431 const Module *) const {
237432 dumpExampleDependence (
238- OS, info.get (), getAnalysis<ScalarEvolutionWrapperPass>().getSE (), false );
433+ OS, info.get (), getAnalysis<ScalarEvolutionWrapperPass>().getSE (),
434+ getAnalysis<LoopInfoWrapperPass>().getLoopInfo (), false );
239435}
240436
241437PreservedAnalyses
@@ -244,7 +440,7 @@ DependenceAnalysisPrinterPass::run(Function &F, FunctionAnalysisManager &FAM) {
244440 << " ':\n " ;
245441 dumpExampleDependence (OS, &FAM.getResult <DependenceAnalysis>(F),
246442 FAM.getResult <ScalarEvolutionAnalysis>(F),
247- NormalizeResults);
443+ FAM. getResult <LoopAnalysis>(F), NormalizeResults);
248444 return PreservedAnalyses::all ();
249445}
250446
@@ -670,6 +866,81 @@ bool DependenceInfo::intersectConstraints(Constraint *X, const Constraint *Y) {
670866 return false ;
671867}
672868
869+ // ===----------------------------------------------------------------------===//
870+ // SCEVMonotonicity
871+
872+ SCEVMonotonicity::SCEVMonotonicity (SCEVMonotonicityType Type,
873+ const SCEV *FailurePoint)
874+ : Type(Type), FailurePoint(FailurePoint) {
875+ assert (
876+ ((Type == SCEVMonotonicityType::Unknown) == (FailurePoint != nullptr )) &&
877+ " FailurePoint must be provided iff Type is Unknown" );
878+ }
879+
880+ void SCEVMonotonicity::print (raw_ostream &OS, unsigned Depth) const {
881+ OS.indent (Depth) << " Monotonicity: " ;
882+ switch (Type) {
883+ case SCEVMonotonicityType::Unknown:
884+ assert (FailurePoint && " FailurePoint must be provided for Unknown" );
885+ OS << " Unknown\n " ;
886+ OS.indent (Depth) << " Reason: " << *FailurePoint << " \n " ;
887+ break ;
888+ case SCEVMonotonicityType::Invariant:
889+ OS << " Invariant\n " ;
890+ break ;
891+ case SCEVMonotonicityType::MultivariateSignedMonotonic:
892+ OS << " MultivariateSignedMonotonic\n " ;
893+ break ;
894+ }
895+ }
896+
897+ bool SCEVMonotonicityChecker::isLoopInvariant (const SCEV *Expr) const {
898+ return !OutermostLoop || SE->isLoopInvariant (Expr, OutermostLoop);
899+ }
900+
901+ SCEVMonotonicity SCEVMonotonicityChecker::invariantOrUnknown (const SCEV *Expr) {
902+ if (isLoopInvariant (Expr))
903+ return SCEVMonotonicity (SCEVMonotonicityType::Invariant);
904+ return createUnknown (Expr);
905+ }
906+
907+ SCEVMonotonicity
908+ SCEVMonotonicityChecker::checkMonotonicity (const SCEV *Expr,
909+ const Loop *OutermostLoop) {
910+ assert (Expr->getType ()->isIntegerTy () && " Expr must be integer type" );
911+ this ->OutermostLoop = OutermostLoop;
912+ return visit (Expr);
913+ }
914+
915+ // / We only care about an affine AddRec at the moment. For an affine AddRec,
916+ // / the monotonicity can be inferred from its nowrap property. For example, let
917+ // / X and Y be loop-invariant, and assume Y is non-negative. An AddRec
918+ // / {X,+.Y}<nsw> implies:
919+ // /
920+ // / X <=s (X + Y) <=s ((X + Y) + Y) <=s ...
921+ // /
922+ // / Thus, we can conclude that the AddRec is monotonically increasing with
923+ // / respect to the associated loop in a signed sense. The similar reasoning
924+ // / applies when Y is non-positive, leading to a monotonically decreasing
925+ // / AddRec.
926+ SCEVMonotonicity
927+ SCEVMonotonicityChecker::visitAddRecExpr (const SCEVAddRecExpr *Expr) {
928+ if (!Expr->isAffine () || !Expr->hasNoSignedWrap ())
929+ return createUnknown (Expr);
930+
931+ const SCEV *Start = Expr->getStart ();
932+ const SCEV *Step = Expr->getStepRecurrence (*SE);
933+
934+ SCEVMonotonicity StartMon = visit (Start);
935+ if (StartMon.isUnknown ())
936+ return StartMon;
937+
938+ if (!isLoopInvariant (Step))
939+ return createUnknown (Expr);
940+
941+ return SCEVMonotonicity (SCEVMonotonicityType::MultivariateSignedMonotonic);
942+ }
943+
673944// ===----------------------------------------------------------------------===//
674945// DependenceInfo methods
675946
@@ -3488,10 +3759,19 @@ bool DependenceInfo::tryDelinearize(Instruction *Src, Instruction *Dst,
34883759 // resize Pair to contain as many pairs of subscripts as the delinearization
34893760 // has found, and then initialize the pairs following the delinearization.
34903761 Pair.resize (Size);
3762+ SCEVMonotonicityChecker MonChecker (SE);
3763+ const Loop *OutermostLoop = SrcLoop ? SrcLoop->getOutermostLoop () : nullptr ;
34913764 for (int I = 0 ; I < Size; ++I) {
34923765 Pair[I].Src = SrcSubscripts[I];
34933766 Pair[I].Dst = DstSubscripts[I];
34943767 unifySubscriptType (&Pair[I]);
3768+
3769+ if (EnableMonotonicityCheck) {
3770+ if (MonChecker.checkMonotonicity (Pair[I].Src , OutermostLoop).isUnknown ())
3771+ return false ;
3772+ if (MonChecker.checkMonotonicity (Pair[I].Dst , OutermostLoop).isUnknown ())
3773+ return false ;
3774+ }
34953775 }
34963776
34973777 return true ;
@@ -3824,6 +4104,14 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
38244104 Pair[0 ].Src = SrcEv;
38254105 Pair[0 ].Dst = DstEv;
38264106
4107+ SCEVMonotonicityChecker MonChecker (SE);
4108+ const Loop *OutermostLoop = SrcLoop ? SrcLoop->getOutermostLoop () : nullptr ;
4109+ if (EnableMonotonicityCheck)
4110+ if (MonChecker.checkMonotonicity (Pair[0 ].Src , OutermostLoop).isUnknown () ||
4111+ MonChecker.checkMonotonicity (Pair[0 ].Dst , OutermostLoop).isUnknown ())
4112+ return std::make_unique<Dependence>(Src, Dst,
4113+ SCEVUnionPredicate (Assume, *SE));
4114+
38274115 if (Delinearize) {
38284116 if (tryDelinearize (Src, Dst, Pair)) {
38294117 LLVM_DEBUG (dbgs () << " delinearized\n " );
0 commit comments