1 // RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s
2 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
3 // RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s
4 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
5
6 // Verify float_control(precise, off) enables fast math flags on fp operations.
fp_precise_1(float a,float b,float c)7 float fp_precise_1(float a, float b, float c) {
8 // CHECK-O3: _Z12fp_precise_1fff
9 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
10 // CHECK-O3: fadd fast float %[[M]], %c
11 #pragma float_control(precise, off)
12 return a * b + c;
13 }
14
15 // Is float_control state cleared on exiting compound statements?
fp_precise_2(float a,float b,float c)16 float fp_precise_2(float a, float b, float c) {
17 // CHECK-O3: _Z12fp_precise_2fff
18 // CHECK-O3: %[[M:.+]] = fmul float{{.*}}
19 // CHECK-O3: fadd float %[[M]], %c
20 {
21 #pragma float_control(precise, off)
22 }
23 return a * b + c;
24 }
25
26 // Does float_control survive template instantiation?
27 class Foo {};
28 Foo operator+(Foo, Foo);
29
30 template <typename T>
template_muladd(T a,T b,T c)31 T template_muladd(T a, T b, T c) {
32 #pragma float_control(precise, off)
33 return a * b + c;
34 }
35
fp_precise_3(float a,float b,float c)36 float fp_precise_3(float a, float b, float c) {
37 // CHECK-O3: _Z12fp_precise_3fff
38 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
39 // CHECK-O3: fadd fast float %[[M]], %c
40 return template_muladd<float>(a, b, c);
41 }
42
43 template <typename T>
44 class fp_precise_4 {
method(float a,float b,float c)45 float method(float a, float b, float c) {
46 #pragma float_control(precise, off)
47 return a * b + c;
48 }
49 };
50
51 template class fp_precise_4<int>;
52 // CHECK-O3: _ZN12fp_precise_4IiE6methodEfff
53 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
54 // CHECK-O3: fadd fast float %[[M]], %c
55
56 // Check file-scoped float_control
57 #pragma float_control(push)
58 #pragma float_control(precise, off)
fp_precise_5(float a,float b,float c)59 float fp_precise_5(float a, float b, float c) {
60 // CHECK-O3: _Z12fp_precise_5fff
61 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
62 // CHECK-O3: fadd fast float %[[M]], %c
63 return a * b + c;
64 }
65 #pragma float_control(pop)
66
fff(float x,float y)67 float fff(float x, float y) {
68 // CHECK-LABEL: define float @_Z3fffff{{.*}}
69 // CHECK: entry
70 #pragma float_control(except, on)
71 float z;
72 z = z * z;
73 //CHECK: llvm.experimental.constrained.fmul{{.*}}
74 {
75 z = x * y;
76 //CHECK: llvm.experimental.constrained.fmul{{.*}}
77 }
78 {
79 // This pragma has no effect since if there are any fp intrin in the
80 // function then all the operations need to be fp intrin
81 #pragma float_control(except, off)
82 z = z + x * y;
83 //CHECK: llvm.experimental.constrained.fmul{{.*}}
84 }
85 z = z * z;
86 //CHECK: llvm.experimental.constrained.fmul{{.*}}
87 return z;
88 }
check_precise(float x,float y)89 float check_precise(float x, float y) {
90 // CHECK-LABEL: define float @_Z13check_preciseff{{.*}}
91 float z;
92 {
93 #pragma float_control(precise, on)
94 z = x * y + z;
95 //CHECK: llvm.fmuladd{{.*}}
96 }
97 {
98 #pragma float_control(precise, off)
99 z = x * y + z;
100 //CHECK: fmul fast float
101 //CHECK: fadd fast float
102 }
103 return z;
104 }
105
fma_test2(float a,float b,float c)106 float fma_test2(float a, float b, float c) {
107 // CHECK-LABEL define float @_Z9fma_test2fff{{.*}}
108 #pragma float_control(precise, off)
109 float x = a * b + c;
110 //CHECK: fmuladd
111 return x;
112 }
113
fma_test1(float a,float b,float c)114 float fma_test1(float a, float b, float c) {
115 // CHECK-LABEL define float @_Z9fma_test1fff{{.*}}
116 #pragma float_control(precise, on)
117 float x = a * b + c;
118 //CHECK: fmuladd
119 return x;
120 }
121
122 #pragma float_control(push)
123 #pragma float_control(precise, on)
124 struct Distance {};
125 Distance operator+(Distance, Distance);
126
127 template <class T>
add(T lhs,T rhs)128 T add(T lhs, T rhs) {
129 #pragma float_control(except, on)
130 return lhs + rhs;
131 }
132 #pragma float_control(pop)
133
test_OperatorCall()134 float test_OperatorCall() {
135 return add(1.0f, 2.0f);
136 //CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict
137 }
138 // CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}}
139
140 #if FENV_ON
141 #pragma STDC FENV_ACCESS ON
142 #endif
143 // CHECK-LABEL: define {{.*}}callt{{.*}}
144
callt()145 void callt() {
146 volatile float z;
147 z = z * z;
148 //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}
149 }
150
151 // CHECK-LABEL: define {{.*}}myAdd{{.*}}
myAdd(int i,float f)152 float myAdd(int i, float f) {
153 if (i<0)
154 return 1.0 + 2.0;
155 // Check that floating point constant folding doesn't occur if
156 // #pragma STC FENV_ACCESS is enabled.
157 //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}
158 //CHECK: store float 3.0{{.*}}retval{{.*}}
159 static double v = 1.0 / 3.0;
160 //CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}
161 //CHECK-NOT: fdiv
162 return v;
163 }
164
165 #if EXCEPT
166 namespace ns {
167 // Check that pragma float_control can appear in namespace.
168 #pragma float_control(except, on, push)
exc_on(double x,float zero)169 float exc_on(double x, float zero) {
170 // CHECK-NS: define {{.*}}exc_on{{.*}}
171 {} try {
172 x = 1.0 / zero; /* division by zero, the result unused */
173 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
174 } catch (...) {}
175 return zero;
176 }
177 }
178
179 // Check pragma is still effective after namespace closes
exc_still_on(double x,float zero)180 float exc_still_on(double x, float zero) {
181 // CHECK-NS: define {{.*}}exc_still_on{{.*}}
182 {} try {
183 x = 1.0 / zero; /* division by zero, the result unused */
184 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
185 } catch (...) {}
186 return zero;
187 }
188
189 #pragma float_control(pop)
exc_off(double x,float zero)190 float exc_off(double x, float zero) {
191 // CHECK-NS: define {{.*}}exc_off{{.*}}
192 {} try {
193 x = 1.0 / zero; /* division by zero, the result unused */
194 //CHECK-NS: fdiv double
195 } catch (...) {}
196 return zero;
197 }
198
199 namespace fc_template_namespace {
200 #pragma float_control(except, on, push)
201 template <class T>
exc_on(double x,T zero)202 T exc_on(double x, T zero) {
203 // CHECK-NS: define {{.*}}fc_template_namespace{{.*}}
204 {} try {
205 x = 1.0 / zero; /* division by zero, the result unused */
206 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
207 } catch (...) {}
208 return zero;
209 }
210 }
211
212 #pragma float_control(pop)
xx(double x,float z)213 float xx(double x, float z) {
214 return fc_template_namespace::exc_on<float>(x, z);
215 }
216 #endif // EXCEPT
217
try_lam(float x,unsigned n)218 float try_lam(float x, unsigned n) {
219 // CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}
220 float result;
221 auto t =
222 // Lambda expression begins
223 [](float a, float b) {
224 #pragma float_control( except, on)
225 return a * b;
226 //CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict
227 } // end of lambda expression
228 (1.0f,2.0f);
229 result = x + t;
230 return result;
231 }
232