Index: lib/Analysis/DependenceAnalysis.cpp =================================================================== --- lib/Analysis/DependenceAnalysis.cpp +++ lib/Analysis/DependenceAnalysis.cpp @@ -3241,6 +3241,28 @@ llvm_unreachable("constraint has unexpected kind"); } +/// Check that all recurrences in an expression are affine. +static bool allAddRecsAffine(const SCEVAddRecExpr *S) { + + // Local struct for the SCEVTraversal. Traverse the expression until a + // SCEVAddRecExpr is found that is not affine. + struct AllAddRecsAffine { + bool IsAffine; + AllAddRecsAffine() : IsAffine(true) {} + bool follow(const SCEV *S) { + if (auto *AddRec = dyn_cast(S)) + IsAffine = AddRec->isAffine(); + return true; + } + bool isDone() { return !IsAffine; } + }; + + AllAddRecsAffine Check; + SCEVTraversal ST(Check); + ST.visitAll(S); + return Check.IsAffine; +} + /// Check if we can delinearize the subscripts. If the SCEVs representing the /// source and destination array references are recurrences on a nested loop, /// this function flattens the nested recurrences into separate recurrences @@ -3278,7 +3300,7 @@ const SCEVAddRecExpr *SrcAR = dyn_cast(SrcSCEV); const SCEVAddRecExpr *DstAR = dyn_cast(DstSCEV); - if (!SrcAR || !DstAR || !SrcAR->isAffine() || !DstAR->isAffine()) + if (!SrcAR || !DstAR || !allAddRecsAffine(SrcAR) || !allAddRecsAffine(DstAR)) return false; // First step: collect parametric terms in both array references. Index: test/Analysis/DependenceAnalysis/AffineSCEVAddRecExpr.ll =================================================================== --- /dev/null +++ test/Analysis/DependenceAnalysis/AffineSCEVAddRecExpr.ll @@ -0,0 +1,36 @@ +; REQUIRES: asserts +; RUN: opt < %s -analyze -basicaa -da-delinearize -da +; +; This is a reduced test case from a benchmark in spec2006. We check that this +; code does not abort. +; +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64" +target triple = "thumbv7--linux-gnueabi" + +define void @f(i32** %a, i32 %n) align 2 { +for.preheader: + %t.0 = ashr exact i32 %n, 3 + br label %for.body.1 + +for.body.1: + %i.1 = phi i32 [ %t.5, %for.inc ], [ 0, %for.preheader ] + %i.2 = phi i32 [ %i.5, %for.inc ], [ %t.0, %for.preheader ] + br i1 undef, label %for.inc, label %for.body.2 + +for.body.2: + %i.3 = phi i32 [ %t.1, %for.body.2 ], [ %i.1, %for.body.1 ] + %t.1 = add i32 %i.3, 1 + %t.2 = load i32*, i32** %a, align 4 + %t.3 = getelementptr inbounds i32, i32* %t.2, i32 %i.3 + %t.4 = load i32, i32* %t.3, align 4 + br i1 undef, label %for.inc, label %for.body.2 + +for.inc: + %i.4 = phi i32 [ %i.2, %for.body.1 ], [ %i.2, %for.body.2 ] + %t.5 = add i32 %i.1, %i.4 + %i.5 = add i32 %i.2, -1 + br i1 undef, label %for.exit, label %for.body.1 + +for.exit: + ret void +}