1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -loop-vectorize -mtriple=x86_64-apple-darwin %s | FileCheck %s --check-prefixes=CHECK,SSE 3; RUN: opt -S -loop-vectorize -mtriple=x86_64-apple-darwin -mattr=+avx %s | FileCheck %s --check-prefixes=CHECK,AVX 4 5; Two mostly identical functions. The only difference is the presence of 6; fast-math flags on the second. The loop is a pretty simple reduction: 7 8; for (int i = 0; i < 32; ++i) 9; if (arr[i] != 42) 10; tot += arr[i]; 11 12define double @sumIfScalar(double* nocapture readonly %arr) { 13; CHECK-LABEL: @sumIfScalar( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: br label [[LOOP:%.*]] 16; CHECK: loop: 17; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[NEXT_ITER:%.*]] ] 18; CHECK-NEXT: [[TOT:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[TOT_NEXT:%.*]], [[NEXT_ITER]] ] 19; CHECK-NEXT: [[ADDR:%.*]] = getelementptr double, double* [[ARR:%.*]], i32 [[I]] 20; CHECK-NEXT: [[NEXTVAL:%.*]] = load double, double* [[ADDR]] 21; CHECK-NEXT: [[TST:%.*]] = fcmp une double [[NEXTVAL]], 4.200000e+01 22; CHECK-NEXT: br i1 [[TST]], label [[DO_ADD:%.*]], label [[NO_ADD:%.*]] 23; CHECK: do.add: 24; CHECK-NEXT: [[TOT_NEW:%.*]] = fadd double [[TOT]], [[NEXTVAL]] 25; CHECK-NEXT: br label [[NEXT_ITER]] 26; CHECK: no.add: 27; CHECK-NEXT: br label [[NEXT_ITER]] 28; CHECK: next.iter: 29; CHECK-NEXT: [[TOT_NEXT]] = phi double [ [[TOT]], [[NO_ADD]] ], [ [[TOT_NEW]], [[DO_ADD]] ] 30; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 31; CHECK-NEXT: [[AGAIN:%.*]] = icmp ult i32 [[I_NEXT]], 32 32; CHECK-NEXT: br i1 [[AGAIN]], label [[LOOP]], label [[DONE:%.*]] 33; CHECK: done: 34; CHECK-NEXT: [[TOT_NEXT_LCSSA:%.*]] = phi double [ [[TOT_NEXT]], [[NEXT_ITER]] ] 35; CHECK-NEXT: ret double [[TOT_NEXT_LCSSA]] 36; 37entry: 38 br label %loop 39 40loop: 41 %i = phi i32 [0, %entry], [%i.next, %next.iter] 42 %tot = phi double [0.0, %entry], [%tot.next, %next.iter] 43 44 %addr = getelementptr double, double* %arr, i32 %i 45 %nextval = load double, double* %addr 46 47 %tst = fcmp une double %nextval, 42.0 48 br i1 %tst, label %do.add, label %no.add 49 50do.add: 51 %tot.new = fadd double %tot, %nextval 52 br label %next.iter 53 54no.add: 55 br label %next.iter 56 57next.iter: 58 %tot.next = phi double [%tot, %no.add], [%tot.new, %do.add] 59 %i.next = add i32 %i, 1 60 %again = icmp ult i32 %i.next, 32 61 br i1 %again, label %loop, label %done 62 63done: 64 ret double %tot.next 65} 66 67define double @sumIfVector(double* nocapture readonly %arr) { 68; SSE-LABEL: @sumIfVector( 69; SSE-NEXT: entry: 70; SSE-NEXT: br label [[LOOP:%.*]] 71; SSE: loop: 72; SSE-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[NEXT_ITER:%.*]] ] 73; SSE-NEXT: [[TOT:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[TOT_NEXT:%.*]], [[NEXT_ITER]] ] 74; SSE-NEXT: [[ADDR:%.*]] = getelementptr double, double* [[ARR:%.*]], i32 [[I]] 75; SSE-NEXT: [[NEXTVAL:%.*]] = load double, double* [[ADDR]] 76; SSE-NEXT: [[TST:%.*]] = fcmp fast une double [[NEXTVAL]], 4.200000e+01 77; SSE-NEXT: br i1 [[TST]], label [[DO_ADD:%.*]], label [[NO_ADD:%.*]] 78; SSE: do.add: 79; SSE-NEXT: [[TOT_NEW:%.*]] = fadd fast double [[TOT]], [[NEXTVAL]] 80; SSE-NEXT: br label [[NEXT_ITER]] 81; SSE: no.add: 82; SSE-NEXT: br label [[NEXT_ITER]] 83; SSE: next.iter: 84; SSE-NEXT: [[TOT_NEXT]] = phi double [ [[TOT]], [[NO_ADD]] ], [ [[TOT_NEW]], [[DO_ADD]] ] 85; SSE-NEXT: [[I_NEXT]] = add i32 [[I]], 1 86; SSE-NEXT: [[AGAIN:%.*]] = icmp ult i32 [[I_NEXT]], 32 87; SSE-NEXT: br i1 [[AGAIN]], label [[LOOP]], label [[DONE:%.*]] 88; SSE: done: 89; SSE-NEXT: [[TOT_NEXT_LCSSA:%.*]] = phi double [ [[TOT_NEXT]], [[NEXT_ITER]] ] 90; SSE-NEXT: ret double [[TOT_NEXT_LCSSA]] 91; 92; AVX-LABEL: @sumIfVector( 93; AVX-NEXT: entry: 94; AVX-NEXT: br i1 false, label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]] 95; AVX: vector.ph: 96; AVX-NEXT: br label [[VECTOR_BODY:%.*]] 97; AVX: vector.body: 98; AVX-NEXT: [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ] 99; AVX-NEXT: [[VEC_PHI:%.*]] = phi <4 x double> [ zeroinitializer, [[VECTOR_PH]] ], [ [[PREDPHI:%.*]], [[VECTOR_BODY]] ] 100; AVX-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i32> undef, i32 [[INDEX]], i32 0 101; AVX-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i32> [[BROADCAST_SPLATINSERT]], <4 x i32> undef, <4 x i32> zeroinitializer 102; AVX-NEXT: [[INDUCTION:%.*]] = add <4 x i32> [[BROADCAST_SPLAT]], <i32 0, i32 1, i32 2, i32 3> 103; AVX-NEXT: [[TMP0:%.*]] = add i32 [[INDEX]], 0 104; AVX-NEXT: [[TMP1:%.*]] = getelementptr double, double* [[ARR:%.*]], i32 [[TMP0]] 105; AVX-NEXT: [[TMP2:%.*]] = getelementptr double, double* [[TMP1]], i32 0 106; AVX-NEXT: [[TMP3:%.*]] = bitcast double* [[TMP2]] to <4 x double>* 107; AVX-NEXT: [[WIDE_LOAD:%.*]] = load <4 x double>, <4 x double>* [[TMP3]], align 8 108; AVX-NEXT: [[TMP4:%.*]] = fcmp fast une <4 x double> [[WIDE_LOAD]], <double 4.200000e+01, double 4.200000e+01, double 4.200000e+01, double 4.200000e+01> 109; AVX-NEXT: [[TMP5:%.*]] = fadd fast <4 x double> [[VEC_PHI]], [[WIDE_LOAD]] 110; AVX-NEXT: [[TMP6:%.*]] = xor <4 x i1> [[TMP4]], <i1 true, i1 true, i1 true, i1 true> 111; AVX-NEXT: [[PREDPHI]] = select <4 x i1> [[TMP4]], <4 x double> [[TMP5]], <4 x double> [[VEC_PHI]] 112; AVX-NEXT: [[INDEX_NEXT]] = add i32 [[INDEX]], 4 113; AVX-NEXT: [[TMP7:%.*]] = icmp eq i32 [[INDEX_NEXT]], 32 114; AVX-NEXT: br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop !0 115; AVX: middle.block: 116; AVX-NEXT: [[RDX_SHUF:%.*]] = shufflevector <4 x double> [[PREDPHI]], <4 x double> undef, <4 x i32> <i32 2, i32 3, i32 undef, i32 undef> 117; AVX-NEXT: [[BIN_RDX:%.*]] = fadd fast <4 x double> [[PREDPHI]], [[RDX_SHUF]] 118; AVX-NEXT: [[RDX_SHUF1:%.*]] = shufflevector <4 x double> [[BIN_RDX]], <4 x double> undef, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef> 119; AVX-NEXT: [[BIN_RDX2:%.*]] = fadd fast <4 x double> [[BIN_RDX]], [[RDX_SHUF1]] 120; AVX-NEXT: [[TMP8:%.*]] = extractelement <4 x double> [[BIN_RDX2]], i32 0 121; AVX-NEXT: [[CMP_N:%.*]] = icmp eq i32 32, 32 122; AVX-NEXT: br i1 [[CMP_N]], label [[DONE:%.*]], label [[SCALAR_PH]] 123; AVX: scalar.ph: 124; AVX-NEXT: [[BC_RESUME_VAL:%.*]] = phi i32 [ 32, [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ] 125; AVX-NEXT: [[BC_MERGE_RDX:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[TMP8]], [[MIDDLE_BLOCK]] ] 126; AVX-NEXT: br label [[LOOP:%.*]] 127; AVX: loop: 128; AVX-NEXT: [[I:%.*]] = phi i32 [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ], [ [[I_NEXT:%.*]], [[NEXT_ITER:%.*]] ] 129; AVX-NEXT: [[TOT:%.*]] = phi double [ [[BC_MERGE_RDX]], [[SCALAR_PH]] ], [ [[TOT_NEXT:%.*]], [[NEXT_ITER]] ] 130; AVX-NEXT: [[ADDR:%.*]] = getelementptr double, double* [[ARR]], i32 [[I]] 131; AVX-NEXT: [[NEXTVAL:%.*]] = load double, double* [[ADDR]] 132; AVX-NEXT: [[TST:%.*]] = fcmp fast une double [[NEXTVAL]], 4.200000e+01 133; AVX-NEXT: br i1 [[TST]], label [[DO_ADD:%.*]], label [[NO_ADD:%.*]] 134; AVX: do.add: 135; AVX-NEXT: [[TOT_NEW:%.*]] = fadd fast double [[TOT]], [[NEXTVAL]] 136; AVX-NEXT: br label [[NEXT_ITER]] 137; AVX: no.add: 138; AVX-NEXT: br label [[NEXT_ITER]] 139; AVX: next.iter: 140; AVX-NEXT: [[TOT_NEXT]] = phi double [ [[TOT]], [[NO_ADD]] ], [ [[TOT_NEW]], [[DO_ADD]] ] 141; AVX-NEXT: [[I_NEXT]] = add i32 [[I]], 1 142; AVX-NEXT: [[AGAIN:%.*]] = icmp ult i32 [[I_NEXT]], 32 143; AVX-NEXT: br i1 [[AGAIN]], label [[LOOP]], label [[DONE]], !llvm.loop !2 144; AVX: done: 145; AVX-NEXT: [[TOT_NEXT_LCSSA:%.*]] = phi double [ [[TOT_NEXT]], [[NEXT_ITER]] ], [ [[TMP8]], [[MIDDLE_BLOCK]] ] 146; AVX-NEXT: ret double [[TOT_NEXT_LCSSA]] 147; 148entry: 149 br label %loop 150 151loop: 152 %i = phi i32 [0, %entry], [%i.next, %next.iter] 153 %tot = phi double [0.0, %entry], [%tot.next, %next.iter] 154 155 %addr = getelementptr double, double* %arr, i32 %i 156 %nextval = load double, double* %addr 157 158 %tst = fcmp fast une double %nextval, 42.0 159 br i1 %tst, label %do.add, label %no.add 160 161do.add: 162 %tot.new = fadd fast double %tot, %nextval 163 br label %next.iter 164 165no.add: 166 br label %next.iter 167 168next.iter: 169 %tot.next = phi double [%tot, %no.add], [%tot.new, %do.add] 170 %i.next = add i32 %i, 1 171 %again = icmp ult i32 %i.next, 32 172 br i1 %again, label %loop, label %done 173 174done: 175 ret double %tot.next 176} 177 178