1; RUN: opt %loadPolly -polly-stmt-granularity=bb -polly-optree -polly-codegen -analyze < %s | FileCheck %s -match-full-lines 2; 3; %val1 is used three times: Twice by its own operand tree of %val2 and once 4; more by the store in %bodyB. 5; Verify that we can handle multiple uses by the same instruction and uses 6; in multiple statements as well. 7; The result processing may depend on the order in which the values are used, 8; hence we check both orderings. 9; 10; for (int j = 0; j < n; j += 1) { 11; bodyA: 12; double val1 = A[j]; 13; double val2 = val1 + val1; 14; 15; bodyB: 16; B[j] = val1; 17; C[j] = val2; 18; } 19; 20define void @func1(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B, double* noalias nonnull %C) { 21entry: 22 br label %for 23 24for: 25 %j = phi i32 [0, %entry], [%j.inc, %inc] 26 %j.cmp = icmp slt i32 %j, %n 27 br i1 %j.cmp, label %bodyA, label %exit 28 29 bodyA: 30 %A_idx = getelementptr inbounds double, double* %A, i32 %j 31 %val1 = load double, double* %A_idx 32 %val2 = fadd double %val1, %val1 33 br label %bodyB 34 35 bodyB: 36 %B_idx = getelementptr inbounds double, double* %B, i32 %j 37 store double %val1, double* %B_idx 38 %C_idx = getelementptr inbounds double, double* %C, i32 %j 39 store double %val2, double* %C_idx 40 br label %inc 41 42inc: 43 %j.inc = add nuw nsw i32 %j, 1 44 br label %for 45 46exit: 47 br label %return 48 49return: 50 ret void 51} 52 53 54; CHECK: Statistics { 55; CHECK: Instructions copied: 1 56; CHECK: Known loads forwarded: 2 57; CHECK: Operand trees forwarded: 2 58; CHECK: Statements with forwarded operand trees: 1 59; CHECK: } 60 61; CHECK: After statements { 62; CHECK-NEXT: Stmt_bodyA 63; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] 64; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] }; 65; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] 66; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_val1[] }; 67; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] 68; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_val2[] }; 69; CHECK-NEXT: Instructions { 70; CHECK-NEXT: %val1 = load double, double* %A_idx, align 8 71; CHECK-NEXT: %val2 = fadd double %val1, %val1 72; CHECK-NEXT: } 73; CHECK-NEXT: Stmt_bodyB 74; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] 75; CHECK-NEXT: ; 76; CHECK-NEXT: new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] }; 77; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] 78; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }; 79; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] 80; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_C[i0] }; 81; CHECK-NEXT: Instructions { 82; CHECK-NEXT: %val1 = load double, double* %A_idx, align 8 83; CHECK-NEXT: %val2 = fadd double %val1, %val1 84; CHECK-NEXT: %val1 = load double, double* %A_idx, align 8 85; CHECK-NEXT: store double %val1, double* %B_idx, align 8 86; CHECK-NEXT: store double %val2, double* %C_idx, align 8 87; CHECK-NEXT: } 88; CHECK-NEXT: } 89 90 91define void @func2(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B, double* noalias nonnull %C) { 92entry: 93 br label %for 94 95for: 96 %j = phi i32 [0, %entry], [%j.inc, %inc] 97 %j.cmp = icmp slt i32 %j, %n 98 br i1 %j.cmp, label %bodyA, label %exit 99 100 bodyA: 101 %A_idx = getelementptr inbounds double, double* %A, i32 %j 102 %val1 = load double, double* %A_idx 103 %val2 = fadd double %val1, %val1 104 br label %bodyB 105 106 bodyB: 107 %B_idx = getelementptr inbounds double, double* %B, i32 %j 108 store double %val2, double* %B_idx 109 %C_idx = getelementptr inbounds double, double* %C, i32 %j 110 store double %val1, double* %C_idx 111 br label %inc 112 113inc: 114 %j.inc = add nuw nsw i32 %j, 1 115 br label %for 116 117exit: 118 br label %return 119 120return: 121 ret void 122} 123 124 125; CHECK: Statistics { 126; CHECK: Instructions copied: 1 127; CHECK: Known loads forwarded: 2 128; CHECK: Operand trees forwarded: 2 129; CHECK: Statements with forwarded operand trees: 1 130; CHECK: } 131 132; CHECK: After statements { 133; CHECK-NEXT: Stmt_bodyA 134; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] 135; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] }; 136; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] 137; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_val2[] }; 138; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] 139; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_val1[] }; 140; CHECK-NEXT: Instructions { 141; CHECK-NEXT: %val1 = load double, double* %A_idx, align 8 142; CHECK-NEXT: %val2 = fadd double %val1, %val1 143; CHECK-NEXT: } 144; CHECK-NEXT: Stmt_bodyB 145; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] 146; CHECK-NEXT: ; 147; CHECK-NEXT: new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] }; 148; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] 149; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }; 150; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] 151; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_C[i0] }; 152; CHECK-NEXT: Instructions { 153; CHECK-NEXT: %val1 = load double, double* %A_idx, align 8 154; CHECK-NEXT: %val1 = load double, double* %A_idx, align 8 155; CHECK-NEXT: %val2 = fadd double %val1, %val1 156; CHECK-NEXT: store double %val2, double* %B_idx, align 8 157; CHECK-NEXT: store double %val1, double* %C_idx, align 8 158; CHECK-NEXT: } 159; CHECK-NEXT: } 160