xref: /llvm-project/clang/test/CodeGen/fp-floatcontrol-pragma.cpp (revision 1592d88aa7bc13c9f53cf09d25b98e7318a57bfb)
1 // RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 \
2 // RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \
3 // RUN: | FileCheck -check-prefix=CHECK-NS %s
4 
5 // RUN: %clang_cc1 -fexperimental-strict-floating-point \
6 // RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s \
7 // RUN: -check-prefixes=CHECK-DEFAULT,CHECK-CONST-ARGS
8 
9 // RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 \
10 // RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \
11 // RUN: | FileCheck -check-prefix=CHECK-FENV %s
12 
13 // RUN: %clang_cc1 -fexperimental-strict-floating-point -DNF128 \
14 // RUN: -triple %itanium_abi_triple -O3 -emit-llvm -o - %s \
15 // RUN: | FileCheck -check-prefix=CHECK-O3 %s
16 
17 // RUN: %clang_cc1 -fexperimental-strict-floating-point \
18 // RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
19 // RUN: | FileCheck %s -check-prefixes=CHECK-SOURCE,CHECK-CONST-ARGS
20 
21 // RUN: %clang_cc1 -fexperimental-strict-floating-point \
22 // RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \
23 // RUN: | FileCheck %s -check-prefixes=CHECK-DOUBLE,CHECK-CONST-ARGS
24 
25 // RUN: %clang_cc1 -fexperimental-strict-floating-point \
26 // RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \
27 // RUN: -mlong-double-80 | FileCheck %s \
28 // RUN: -check-prefixes=CHECK-EXTENDED,CHECK-CONST-ARGS
29 
30 // RUN: %clang_cc1 -fexperimental-strict-floating-point \
31 // RUN: -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
32 // RUN: | FileCheck %s -check-prefix=CHECK-SOURCE
33 
34 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
35 // RUN: -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s \
36 // RUN: -check-prefix=CHECK-DOUBLE
37 
38 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
39 // RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \
40 // RUN: | FileCheck %s -check-prefix=CHECK-EXTENDED
41 
42 // RUN: %clang_cc1 -triple powerpc-unknown-aix -DNF128 -emit-llvm -o - %s \
43 // RUN: | FileCheck %s -check-prefix=CHECK-AIX
44 
f()45 bool f() {
46   // CHECK: define {{.*}}f{{.*}}
47   return __FLT_EVAL_METHOD__ < 0 &&
48          __FLT_EVAL_METHOD__ == -1;
49   // CHECK: ret {{.*}} true
50 }
51 
52 // Verify float_control(precise, off) enables fast math flags on fp operations.
fp_precise_1(float a,float b,float c)53 float fp_precise_1(float a, float b, float c) {
54 // CHECK-O3: _Z12fp_precise_1fff
55 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
56 // CHECK-O3: fadd fast float %[[M]], %c
57 #pragma float_control(precise, off)
58   return a * b + c;
59 }
60 
61 // Is float_control state cleared on exiting compound statements?
fp_precise_2(float a,float b,float c)62 float fp_precise_2(float a, float b, float c) {
63   // CHECK-O3: _Z12fp_precise_2fff
64   // CHECK-O3: %[[M:.+]] = fmul float{{.*}}
65   // CHECK-O3: fadd float %[[M]], %c
66   {
67 #pragma float_control(precise, off)
68   }
69   return a * b + c;
70 }
71 
72 // Does float_control survive template instantiation?
73 class Foo {};
74 Foo operator+(Foo, Foo);
75 
76 template <typename T>
template_muladd(T a,T b,T c)77 T template_muladd(T a, T b, T c) {
78 #pragma float_control(precise, off)
79   return a * b + c;
80 }
81 
fp_precise_3(float a,float b,float c)82 float fp_precise_3(float a, float b, float c) {
83   // CHECK-O3: _Z12fp_precise_3fff
84   // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
85   // CHECK-O3: fadd fast float %[[M]], %c
86   return template_muladd<float>(a, b, c);
87 }
88 
89 template <typename T>
90 class fp_precise_4 {
method(float a,float b,float c)91   float method(float a, float b, float c) {
92 #pragma float_control(precise, off)
93     return a * b + c;
94   }
95 };
96 
97 template class fp_precise_4<int>;
98 // CHECK-O3: _ZN12fp_precise_4IiE6methodEfff
99 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
100 // CHECK-O3: fadd fast float %[[M]], %c
101 
102 // Check file-scoped float_control
103 #pragma float_control(push)
104 #pragma float_control(precise, off)
fp_precise_5(float a,float b,float c)105 float fp_precise_5(float a, float b, float c) {
106   // CHECK-O3: _Z12fp_precise_5fff
107   // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
108   // CHECK-O3: fadd fast float %[[M]], %c
109   return a * b + c;
110 }
111 #pragma float_control(pop)
112 
fff(float x,float y)113 float fff(float x, float y) {
114 // CHECK-LABEL: define{{.*}} float @_Z3fffff{{.*}}
115 // CHECK: entry
116 #pragma float_control(except, on)
117   float z;
118   z = z * z;
119   //CHECK: llvm.experimental.constrained.fmul{{.*}}
120   {
121     z = x * y;
122     //CHECK: llvm.experimental.constrained.fmul{{.*}}
123   }
124   {
125 // This pragma has no effect since if there are any fp intrin in the
126 // function then all the operations need to be fp intrin
127 #pragma float_control(except, off)
128     z = z + x * y;
129     //CHECK: llvm.experimental.constrained.fmul{{.*}}
130   }
131   z = z * z;
132   //CHECK: llvm.experimental.constrained.fmul{{.*}}
133   return z;
134 }
check_precise(float x,float y)135 float check_precise(float x, float y) {
136   // CHECK-LABEL: define{{.*}} float @_Z13check_preciseff{{.*}}
137   float z;
138   {
139 #pragma float_control(precise, on)
140     z = x * y + z;
141     //CHECK: llvm.fmuladd{{.*}}
142   }
143   {
144 #pragma float_control(precise, off)
145     z = x * y + z;
146     //CHECK: fmul fast float
147     //CHECK: fadd fast float
148   }
149   return z;
150 }
151 
fma_test2(float a,float b,float c)152 float fma_test2(float a, float b, float c) {
153 // CHECK-LABEL define{{.*}} float @_Z9fma_test2fff{{.*}}
154 #pragma float_control(precise, off)
155   float x = a * b + c;
156   //CHECK: fmuladd
157   return x;
158 }
159 
fma_test1(float a,float b,float c)160 float fma_test1(float a, float b, float c) {
161 // CHECK-LABEL define{{.*}} float @_Z9fma_test1fff{{.*}}
162 #pragma float_control(precise, on)
163   float x = a * b + c;
164   //CHECK: fmuladd
165   return x;
166 }
167 
168 #pragma float_control(push)
169 #pragma float_control(precise, on)
170 struct Distance {};
171 Distance operator+(Distance, Distance);
172 
173 template <class T>
add(T lhs,T rhs)174 T add(T lhs, T rhs) {
175 #pragma float_control(except, on)
176   return lhs + rhs;
177 }
178 #pragma float_control(pop)
179 
test_OperatorCall()180 float test_OperatorCall() {
181   return add(1.0f, 2.0f);
182   //CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict
183 }
184 // CHECK-LABEL define{{.*}} float  {{.*}}test_OperatorCall{{.*}}
185 
186 #if FENV_ON
187 #pragma STDC FENV_ACCESS ON
188 #endif
189 // CHECK-LABEL: define {{.*}}callt{{.*}}
190 
callt()191 void callt() {
192   volatile float z;
193   z = z * z;
194   //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}
195 }
196 
197 // CHECK-LABEL: define {{.*}}myAdd{{.*}}
myAdd(int i,float f)198 float myAdd(int i, float f) {
199   if (i<0)
200   return 1.0 + 2.0;
201   // Check that floating point constant folding doesn't occur if
202   // #pragma STC FENV_ACCESS is enabled.
203   //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}
204   //CHECK: store float 3.0{{.*}}retval{{.*}}
205   static double v = 1.0 / 3.0;
206   //CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}
207   //CHECK-NOT: fdiv
208   return v;
209 }
210 
211 #if EXCEPT
212 namespace ns {
213 // Check that pragma float_control can appear in namespace.
214 #pragma float_control(except, on, push)
exc_on(double x,float zero)215 float exc_on(double x, float zero) {
216 // CHECK-NS: define {{.*}}exc_on{{.*}}
217   {} try {
218     x = 1.0 / zero; /* division by zero, the result unused */
219 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
220   } catch (...) {}
221   return zero;
222 }
223 }
224 
225 // Check pragma is still effective after namespace closes
exc_still_on(double x,float zero)226 float exc_still_on(double x, float zero) {
227 // CHECK-NS: define {{.*}}exc_still_on{{.*}}
228   {} try {
229     x = 1.0 / zero; /* division by zero, the result unused */
230 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
231   } catch (...) {}
232   return zero;
233 }
234 
235 #pragma float_control(pop)
exc_off(double x,float zero)236 float exc_off(double x, float zero) {
237 // CHECK-NS: define {{.*}}exc_off{{.*}}
238   {} try {
239     x = 1.0 / zero; /* division by zero, the result unused */
240 //CHECK-NS: fdiv double
241   } catch (...) {}
242   return zero;
243 }
244 
245 namespace fc_template_namespace {
246 #pragma float_control(except, on, push)
247 template <class T>
exc_on(double x,T zero)248 T exc_on(double x, T zero) {
249 // CHECK-NS: define {{.*}}fc_template_namespace{{.*}}
250   {} try {
251     x = 1.0 / zero; /* division by zero, the result unused */
252 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
253   } catch (...) {}
254   return zero;
255 }
256 }
257 
258 #pragma float_control(pop)
xx(double x,float z)259 float xx(double x, float z) {
260   return fc_template_namespace::exc_on<float>(x, z);
261 }
262 #endif // EXCEPT
263 
try_lam(float x,unsigned n)264 float try_lam(float x, unsigned n) {
265 // CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}
266   float result;
267   auto t =
268         // Lambda expression begins
269         [](float a, float b) {
270 #pragma float_control( except, on)
271             return a * b;
272 //CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict
273         } // end of lambda expression
274   (1.0f,2.0f);
275   result = x + t;
276   return result;
277 }
278 
mySub(float x,float y)279 float mySub(float x, float y) {
280   // CHECK: define {{.*}}float {{.*}}mySub{{.*}}
281   // CHECK-NS: fsub float
282   // CHECK-SOURCE: fsub float
283   // CHECK-DOUBLE: fpext float
284   // CHECK-DOUBLE: fpext float
285   // CHECK-DOUBLE: fsub double
286   // CHECK-DOUBLE: fptrunc double {{.*}} to float
287   // CHECK-EXTENDED: fpext float
288   // CHECK-EXTENDED: fpext float
289   // CHECK-EXTENDED: fsub double
290   // CHECK-EXTENDED: fptrunc double {{.*}} to float
291   return x - y;
292 }
293 
mySubSource(float x,float y)294 float mySubSource(float x, float y) {
295 // CHECK: define {{.*}}float {{.*}}mySubSource{{.*}}
296 #pragma clang fp eval_method(source)
297   return x - y;
298   // CHECK: fsub float
299 }
300 
mySubExtended(float x,float y)301 float mySubExtended(float x, float y) {
302 // CHECK: define {{.*}}float {{.*}}mySubExtended{{.*}}
303 #pragma clang fp eval_method(extended)
304   return x - y;
305   // CHECK: fpext float
306   // CHECK: fpext float
307   // CHECK: fsub x86_fp80
308   // CHECK: fptrunc x86_fp80 {{.*}} to float
309   // CHECK-AIX: fsub double
310   // CHECK-AIX: fptrunc double
311 }
312 
mySubDouble(float x,float y)313 float mySubDouble(float x, float y) {
314 // CHECK: define {{.*}}float {{.*}}mySubDouble{{.*}}
315 #pragma clang fp eval_method(double)
316   return x - y;
317   // CHECK: fpext float
318   // CHECK: fpext float
319   // CHECK: fsub double
320   // CHECK: fptrunc double {{.*}} to float
321 }
322 
323 #ifndef NF128
mySub128(__float128 x,__float128 y)324 __float128 mySub128(__float128 x, __float128 y) {
325   // CHECK: define {{.*}}mySub128{{.*}}
326   // Expect no fpext since fp128 is already widest
327   // CHECK: load fp128
328   // CHECK-NEXT: load fp128
329   // CHECK-NEXT: fsub fp128
330   // CHECK-NEXT: ret fp128
331   return x - y;
332 }
333 #endif
334 
mySubfp16(__fp16 * res,__fp16 * x,__fp16 * y)335 void mySubfp16(__fp16 *res, __fp16 *x, __fp16 *y) {
336   // CHECK: define {{.*}}mySubfp16{{.*}}
337   *res = *x - *y;
338   // CHECK: load half
339   // CHECK-NEXT: load half
340   // CHECK-NEXT: fpext half{{.*}}
341   // CHECK-NEXT: load half
342   // CHECK-NEXT: load half
343   // CHECK-NS: fpext half{{.*}} to float
344   // CHECK-DEFAULT: fpext half{{.*}} to float
345   // CHECK-DOUBLE: fpext half{{.*}} to float
346   // CHECK-EXTENDED: fpext half{{.*}} to float
347   // CHECK-NEXT: fsub
348   // CHECK-NEXT: fptrunc {{.*}}to half
349   // CHECK-NS: fptrunc float {{.*}} to half
350   // CHECK-DOUBLE: fptrunc float {{.*}} to half
351   // CHECK-EXTENDED: fptrunc float {{.*}} to half
352 }
353 
Div(float x,float y,float z)354 float Div(float x, float y, float z) {
355   // CHECK: define{{.*}}float {{.*}}Div{{.*}}
356   // CHECK-CONST-ARGS: fdiv float
357   return x / (y / z);
358 }
359 
DivExtended(float x,float y,float z)360 float DivExtended(float x, float y, float z) {
361 // CHECK: define{{.*}}float {{.*}}DivExtended{{.*}}
362 #pragma clang fp eval_method(extended)
363   // CHECK-CONST-ARGS: fdiv x86_fp80
364   // CHECK-CONST-ARGS: fptrunc x86_fp80
365   return x / (y / z);
366 }
367 
DivDouble(float x,float y,float z)368 float DivDouble(float x, float y, float z) {
369 // CHECK: define{{.*}}float {{.*}}DivDouble{{.*}}
370 #pragma clang fp eval_method(double)
371   // CHECK-CONST-ARGS: fdiv double
372   // CHECK-CONST-ARGS: fptrunc double
373   return x / (y / z);
374 }
375 
DivSource(float x,float y,float z)376 float DivSource(float x, float y, float z) {
377 // CHECK: define{{.*}}float {{.*}}DivSource{{.*}}
378 #pragma clang fp eval_method(source)
379   // CHECK-CONST-ARGS: fdiv float
380   return x / (y / z);
381 }
382 
main()383 int main() {
384   float f = Div(4.2f, 1.0f, 3.0f);
385   float fextended = DivExtended(4.2f, 1.0f, 3.0f);
386   float fdouble = DivDouble(4.2f, 1.0f, 3.0f);
387   float fsource = DivSource(4.2f, 1.0f, 3.0f);
388   // CHECK: store float
389 }
390