1; RUN: opt -basicaa -loop-accesses -analyze < %s | FileCheck %s 2; RUN: opt -passes='require<scalar-evolution>,require<aa>,loop(print-access-info)' -disable-output < %s 2>&1 | FileCheck %s 3 4; This loop: 5; 6; int **A; 7; for (i) 8; for (j) { 9; A[i][j] = A[i-1][j] * B[j] 10; B[j+1] = 2 // backward dep between this and the previous 11; } 12; 13; is transformed by Load-PRE to stash away A[i] for the next iteration of the 14; outer loop: 15; 16; Curr = A[0]; // Prev_0 17; for (i: 1..N) { 18; Prev = Curr; // Prev = PHI (Prev_0, Curr) 19; Curr = A[i]; 20; for (j: 0..N) { 21; Curr[j] = Prev[j] * B[j] 22; B[j+1] = 2 // backward dep between this and the previous 23; } 24; } 25; 26; Since A[i] and A[i-1] are likely to be independent, getUnderlyingObjects 27; should not assume that Curr and Prev share the same underlying object. 28; 29; If it did we would try to dependence-analyze Curr and Prev and the analysis 30; would fail with non-constant distance. 31; 32; To illustrate one of the negative consequences of this, if the loop has a 33; backward dependence we won't detect this but instead fully fall back on 34; memchecks (that is what LAA does after encountering a case of non-constant 35; distance). 36 37target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" 38target triple = "x86_64-apple-macosx10.10.0" 39 40; CHECK: for_j.body: 41; CHECK-NEXT: Report: unsafe dependent memory operations in loop 42; CHECK-NEXT: Dependences: 43; CHECK-NEXT: Backward: 44; CHECK-NEXT: %loadB = load i8, i8* %gepB, align 1 -> 45; CHECK-NEXT: store i8 2, i8* %gepB_plus_one, align 1 46 47define void @f(i8** noalias %A, i8* noalias %B, i64 %N) { 48for_i.preheader: 49 %prev_0 = load i8*, i8** %A, align 8 50 br label %for_i.body 51 52for_i.body: 53 %i = phi i64 [1, %for_i.preheader], [%i.1, %for_j.end] 54 %prev = phi i8* [%prev_0, %for_i.preheader], [%curr, %for_j.end] 55 %gep = getelementptr inbounds i8*, i8** %A, i64 %i 56 %curr = load i8*, i8** %gep, align 8 57 br label %for_j.preheader 58 59for_j.preheader: 60 br label %for_j.body 61 62for_j.body: 63 %j = phi i64 [0, %for_j.preheader], [%j.1, %for_j.body] 64 65 %gepPrev = getelementptr inbounds i8, i8* %prev, i64 %j 66 %gepCurr = getelementptr inbounds i8, i8* %curr, i64 %j 67 %gepB = getelementptr inbounds i8, i8* %B, i64 %j 68 69 %loadPrev = load i8, i8* %gepPrev, align 1 70 %loadB = load i8, i8* %gepB, align 1 71 72 %mul = mul i8 %loadPrev, %loadB 73 74 store i8 %mul, i8* %gepCurr, align 1 75 76 %gepB_plus_one = getelementptr inbounds i8, i8* %gepB, i64 1 77 store i8 2, i8* %gepB_plus_one, align 1 78 79 %j.1 = add nuw i64 %j, 1 80 %exitcondj = icmp eq i64 %j.1, %N 81 br i1 %exitcondj, label %for_j.end, label %for_j.body 82 83for_j.end: 84 85 %i.1 = add nuw i64 %i, 1 86 %exitcond = icmp eq i64 %i.1, %N 87 br i1 %exitcond, label %for_i.end, label %for_i.body 88 89for_i.end: 90 ret void 91} 92