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