1; RUN: opt < %s -basicaa -slp-vectorizer -slp-threshold=-999 -dce -S -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx | FileCheck %s 2 3target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" 4target triple = "x86_64-apple-macosx10.8.0" 5 6declare double @sin(double) 7declare double @cos(double) 8declare double @pow(double, double) 9declare double @exp2(double) 10declare double @sqrt(double) 11declare i64 @round(i64) 12 13 14define void @sin_libm(double* %a, double* %b) { 15; CHECK-LABEL: @sin_libm( 16; CHECK-NEXT: [[TMP1:%.*]] = bitcast double* %a to <2 x double>* 17; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, <2 x double>* [[TMP1]], align 8 18; CHECK-NEXT: [[TMP3:%.*]] = call <2 x double> @llvm.sin.v2f64(<2 x double> [[TMP2]]) 19; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* %b to <2 x double>* 20; CHECK-NEXT: store <2 x double> [[TMP3]], <2 x double>* [[TMP4]], align 8 21; CHECK-NEXT: ret void 22; 23 %a0 = load double, double* %a, align 8 24 %idx1 = getelementptr inbounds double, double* %a, i64 1 25 %a1 = load double, double* %idx1, align 8 26 %sin1 = tail call double @sin(double %a0) nounwind readnone 27 %sin2 = tail call double @sin(double %a1) nounwind readnone 28 store double %sin1, double* %b, align 8 29 %idx2 = getelementptr inbounds double, double* %b, i64 1 30 store double %sin2, double* %idx2, align 8 31 ret void 32} 33 34define void @cos_libm(double* %a, double* %b) { 35; CHECK-LABEL: @cos_libm( 36; CHECK-NEXT: [[TMP1:%.*]] = bitcast double* %a to <2 x double>* 37; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, <2 x double>* [[TMP1]], align 8 38; CHECK-NEXT: [[TMP3:%.*]] = call <2 x double> @llvm.cos.v2f64(<2 x double> [[TMP2]]) 39; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* %b to <2 x double>* 40; CHECK-NEXT: store <2 x double> [[TMP3]], <2 x double>* [[TMP4]], align 8 41; CHECK-NEXT: ret void 42; 43 %a0 = load double, double* %a, align 8 44 %idx1 = getelementptr inbounds double, double* %a, i64 1 45 %a1 = load double, double* %idx1, align 8 46 %cos1 = tail call double @cos(double %a0) nounwind readnone 47 %cos2 = tail call double @cos(double %a1) nounwind readnone 48 store double %cos1, double* %b, align 8 49 %idx2 = getelementptr inbounds double, double* %b, i64 1 50 store double %cos2, double* %idx2, align 8 51 ret void 52} 53 54define void @pow_libm(double* %a, double* %b) { 55; CHECK-LABEL: @pow_libm( 56; CHECK-NEXT: [[TMP1:%.*]] = bitcast double* %a to <2 x double>* 57; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, <2 x double>* [[TMP1]], align 8 58; CHECK-NEXT: [[TMP3:%.*]] = call <2 x double> @llvm.pow.v2f64(<2 x double> [[TMP2]], <2 x double> [[TMP2]]) 59; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* %b to <2 x double>* 60; CHECK-NEXT: store <2 x double> [[TMP3]], <2 x double>* [[TMP4]], align 8 61; CHECK-NEXT: ret void 62; 63 %a0 = load double, double* %a, align 8 64 %idx1 = getelementptr inbounds double, double* %a, i64 1 65 %a1 = load double, double* %idx1, align 8 66 %pow1 = tail call double @pow(double %a0, double %a0) nounwind readnone 67 %pow2 = tail call double @pow(double %a1, double %a1) nounwind readnone 68 store double %pow1, double* %b, align 8 69 %idx2 = getelementptr inbounds double, double* %b, i64 1 70 store double %pow2, double* %idx2, align 8 71 ret void 72} 73 74define void @exp_libm(double* %a, double* %b) { 75; CHECK-LABEL: @exp_libm( 76; CHECK-NEXT: [[TMP1:%.*]] = bitcast double* %a to <2 x double>* 77; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, <2 x double>* [[TMP1]], align 8 78; CHECK-NEXT: [[TMP3:%.*]] = call <2 x double> @llvm.exp2.v2f64(<2 x double> [[TMP2]]) 79; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* %b to <2 x double>* 80; CHECK-NEXT: store <2 x double> [[TMP3]], <2 x double>* [[TMP4]], align 8 81; CHECK-NEXT: ret void 82; 83 %a0 = load double, double* %a, align 8 84 %idx1 = getelementptr inbounds double, double* %a, i64 1 85 %a1 = load double, double* %idx1, align 8 86 %exp1 = tail call double @exp2(double %a0) nounwind readnone 87 %exp2 = tail call double @exp2(double %a1) nounwind readnone 88 store double %exp1, double* %b, align 8 89 %idx2 = getelementptr inbounds double, double* %b, i64 1 90 store double %exp2, double* %idx2, align 8 91 ret void 92} 93 94; No fast-math-flags are required to convert sqrt library calls to an intrinsic. 95; We just need to know that errno is not set (readnone). 96 97define void @sqrt_libm_no_errno(double* %a, double* %b) { 98; CHECK-LABEL: @sqrt_libm_no_errno( 99; CHECK-NEXT: [[TMP1:%.*]] = bitcast double* %a to <2 x double>* 100; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, <2 x double>* [[TMP1]], align 8 101; CHECK-NEXT: [[TMP3:%.*]] = call <2 x double> @llvm.sqrt.v2f64(<2 x double> [[TMP2]]) 102; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* %b to <2 x double>* 103; CHECK-NEXT: store <2 x double> [[TMP3]], <2 x double>* [[TMP4]], align 8 104; CHECK-NEXT: ret void 105; 106 %a0 = load double, double* %a, align 8 107 %idx1 = getelementptr inbounds double, double* %a, i64 1 108 %a1 = load double, double* %idx1, align 8 109 %sqrt1 = tail call double @sqrt(double %a0) nounwind readnone 110 %sqrt2 = tail call double @sqrt(double %a1) nounwind readnone 111 store double %sqrt1, double* %b, align 8 112 %idx2 = getelementptr inbounds double, double* %b, i64 1 113 store double %sqrt2, double* %idx2, align 8 114 ret void 115} 116 117; The sqrt intrinsic does not set errno, but a non-constant sqrt call might, so this can't vectorize. 118; The nnan on the call does not matter because there's no guarantee in the C standard that a negative 119; input would result in a nan output ("On a domain error, the function returns an 120; implementation-defined value.") 121 122define void @sqrt_libm_errno(double* %a, double* %b) { 123; CHECK-LABEL: @sqrt_libm_errno( 124; CHECK-NEXT: [[A0:%.*]] = load double, double* %a, align 8 125; CHECK-NEXT: [[IDX1:%.*]] = getelementptr inbounds double, double* %a, i64 1 126; CHECK-NEXT: [[A1:%.*]] = load double, double* [[IDX1]], align 8 127; CHECK-NEXT: [[SQRT1:%.*]] = tail call nnan double @sqrt(double [[A0]]) #2 128; CHECK-NEXT: [[SQRT2:%.*]] = tail call nnan double @sqrt(double [[A1]]) #2 129; CHECK-NEXT: store double [[SQRT1]], double* %b, align 8 130; CHECK-NEXT: [[IDX2:%.*]] = getelementptr inbounds double, double* %b, i64 1 131; CHECK-NEXT: store double [[SQRT2]], double* [[IDX2]], align 8 132; CHECK-NEXT: ret void 133; 134 %a0 = load double, double* %a, align 8 135 %idx1 = getelementptr inbounds double, double* %a, i64 1 136 %a1 = load double, double* %idx1, align 8 137 %sqrt1 = tail call nnan double @sqrt(double %a0) nounwind 138 %sqrt2 = tail call nnan double @sqrt(double %a1) nounwind 139 store double %sqrt1, double* %b, align 8 140 %idx2 = getelementptr inbounds double, double* %b, i64 1 141 store double %sqrt2, double* %idx2, align 8 142 ret void 143} 144 145; Negative test case 146define void @round_custom(i64* %a, i64* %b) { 147; CHECK-LABEL: @round_custom( 148; CHECK-NEXT: [[A0:%.*]] = load i64, i64* %a, align 8 149; CHECK-NEXT: [[IDX1:%.*]] = getelementptr inbounds i64, i64* %a, i64 1 150; CHECK-NEXT: [[A1:%.*]] = load i64, i64* [[IDX1]], align 8 151; CHECK-NEXT: [[ROUND1:%.*]] = tail call i64 @round(i64 [[A0]]) #3 152; CHECK-NEXT: [[ROUND2:%.*]] = tail call i64 @round(i64 [[A1]]) #3 153; CHECK-NEXT: store i64 [[ROUND1]], i64* %b, align 8 154; CHECK-NEXT: [[IDX2:%.*]] = getelementptr inbounds i64, i64* %b, i64 1 155; CHECK-NEXT: store i64 [[ROUND2]], i64* [[IDX2]], align 8 156; CHECK-NEXT: ret void 157; 158 %a0 = load i64, i64* %a, align 8 159 %idx1 = getelementptr inbounds i64, i64* %a, i64 1 160 %a1 = load i64, i64* %idx1, align 8 161 %round1 = tail call i64 @round(i64 %a0) nounwind readnone 162 %round2 = tail call i64 @round(i64 %a1) nounwind readnone 163 store i64 %round1, i64* %b, align 8 164 %idx2 = getelementptr inbounds i64, i64* %b, i64 1 165 store i64 %round2, i64* %idx2, align 8 166 ret void 167} 168 169 170; CHECK: declare <2 x double> @llvm.sin.v2f64(<2 x double>) [[ATTR0:#[0-9]+]] 171; CHECK: declare <2 x double> @llvm.cos.v2f64(<2 x double>) [[ATTR0]] 172; CHECK: declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) [[ATTR0]] 173; CHECK: declare <2 x double> @llvm.exp2.v2f64(<2 x double>) [[ATTR0]] 174 175; CHECK: attributes [[ATTR0]] = { nounwind readnone speculatable } 176 177