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