aboutsummaryrefslogtreecommitdiff
path: root/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
blob: 966eaf6053970ad1a2a25737e2e6d9ddf26bbc6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 \
// RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \
// RUN: | FileCheck -check-prefix=CHECK-NS %s

// RUN: %clang_cc1 -fexperimental-strict-floating-point \
// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s \
// RUN: -check-prefixes=CHECK-DEFAULT,CHECK-CONST-ARGS

// RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 \
// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \
// RUN: | FileCheck -check-prefix=CHECK-FENV %s

// RUN: %clang_cc1 -fexperimental-strict-floating-point -DNF128 \
// RUN: -triple %itanium_abi_triple -O3 -emit-llvm -o - %s \
// RUN: | FileCheck -check-prefix=CHECK-O3 %s

// RUN: %clang_cc1 -fexperimental-strict-floating-point \
// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
// RUN: | FileCheck %s -check-prefixes=CHECK-SOURCE,CHECK-CONST-ARGS

// RUN: %clang_cc1 -fexperimental-strict-floating-point \
// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \
// RUN: | FileCheck %s -check-prefixes=CHECK-DOUBLE,CHECK-CONST-ARGS

// RUN: %clang_cc1 -fexperimental-strict-floating-point \
// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \
// RUN: -mlong-double-80 | FileCheck %s \
// RUN: -check-prefixes=CHECK-EXTENDED,CHECK-CONST-ARGS

// RUN: %clang_cc1 -fexperimental-strict-floating-point \
// RUN: -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
// RUN: | FileCheck %s -check-prefix=CHECK-SOURCE

// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
// RUN: -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s \
// RUN: -check-prefix=CHECK-DOUBLE

// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
// RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \
// RUN: | FileCheck %s -check-prefix=CHECK-EXTENDED

// RUN: %clang_cc1 -triple powerpc-unknown-aix -DNF128 -emit-llvm -o - %s \
// RUN: | FileCheck %s -check-prefix=CHECK-AIX

bool f() {
  // CHECK: define {{.*}}f{{.*}}
  return __FLT_EVAL_METHOD__ < 0 &&
         __FLT_EVAL_METHOD__ == -1;
  // CHECK: ret {{.*}} true
}

// Verify float_control(precise, off) enables fast math flags on fp operations.
float fp_precise_1(float a, float b, float c) {
// CHECK-O3: _Z12fp_precise_1fff
// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
// CHECK-O3: fadd fast float %[[M]], %c
#pragma float_control(precise, off)
  return a * b + c;
}

// Is float_control state cleared on exiting compound statements?
float fp_precise_2(float a, float b, float c) {
  // CHECK-O3: _Z12fp_precise_2fff
  // CHECK-O3: %[[M:.+]] = fmul float{{.*}}
  // CHECK-O3: fadd float %[[M]], %c
  {
#pragma float_control(precise, off)
  }
  return a * b + c;
}

// Does float_control survive template instantiation?
class Foo {};
Foo operator+(Foo, Foo);

template <typename T>
T template_muladd(T a, T b, T c) {
#pragma float_control(precise, off)
  return a * b + c;
}

float fp_precise_3(float a, float b, float c) {
  // CHECK-O3: _Z12fp_precise_3fff
  // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
  // CHECK-O3: fadd fast float %[[M]], %c
  return template_muladd<float>(a, b, c);
}

template <typename T>
class fp_precise_4 {
  float method(float a, float b, float c) {
#pragma float_control(precise, off)
    return a * b + c;
  }
};

template class fp_precise_4<int>;
// CHECK-O3: _ZN12fp_precise_4IiE6methodEfff
// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
// CHECK-O3: fadd fast float %[[M]], %c

// Check file-scoped float_control
#pragma float_control(push)
#pragma float_control(precise, off)
float fp_precise_5(float a, float b, float c) {
  // CHECK-O3: _Z12fp_precise_5fff
  // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
  // CHECK-O3: fadd fast float %[[M]], %c
  return a * b + c;
}
#pragma float_control(pop)

float fff(float x, float y) {
// CHECK-LABEL: define{{.*}} float @_Z3fffff{{.*}}
// CHECK: entry
#pragma float_control(except, on)
  float z;
  z = z * z;
  //CHECK: llvm.experimental.constrained.fmul{{.*}}
  {
    z = x * y;
    //CHECK: llvm.experimental.constrained.fmul{{.*}}
  }
  {
// This pragma has no effect since if there are any fp intrin in the
// function then all the operations need to be fp intrin
#pragma float_control(except, off)
    z = z + x * y;
    //CHECK: llvm.experimental.constrained.fmul{{.*}}
  }
  z = z * z;
  //CHECK: llvm.experimental.constrained.fmul{{.*}}
  return z;
}
float check_precise(float x, float y) {
  // CHECK-LABEL: define{{.*}} float @_Z13check_preciseff{{.*}}
  float z;
  {
#pragma float_control(precise, on)
    z = x * y + z;
    //CHECK: llvm.fmuladd{{.*}}
  }
  {
#pragma float_control(precise, off)
    z = x * y + z;
    //CHECK: fmul fast float
    //CHECK: fadd fast float
  }
  return z;
}

float fma_test2(float a, float b, float c) {
// CHECK-LABEL define{{.*}} float @_Z9fma_test2fff{{.*}}
#pragma float_control(precise, off)
  float x = a * b + c;
  //CHECK: fmuladd
  return x;
}

float fma_test1(float a, float b, float c) {
// CHECK-LABEL define{{.*}} float @_Z9fma_test1fff{{.*}}
#pragma float_control(precise, on)
  float x = a * b + c;
  //CHECK: fmuladd
  return x;
}

#pragma float_control(push)
#pragma float_control(precise, on)
struct Distance {};
Distance operator+(Distance, Distance);

template <class T>
T add(T lhs, T rhs) {
#pragma float_control(except, on)
  return lhs + rhs;
}
#pragma float_control(pop)

float test_OperatorCall() {
  return add(1.0f, 2.0f);
  //CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict
}
// CHECK-LABEL define{{.*}} float  {{.*}}test_OperatorCall{{.*}}

#if FENV_ON
#pragma STDC FENV_ACCESS ON
#endif
// CHECK-LABEL: define {{.*}}callt{{.*}}

void callt() {
  volatile float z;
  z = z * z;
  //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}
}

// CHECK-LABEL: define {{.*}}myAdd{{.*}}
float myAdd(int i, float f) {
  if (i<0)
  return 1.0 + 2.0;
  // Check that floating point constant folding doesn't occur if
  // #pragma STC FENV_ACCESS is enabled.
  //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}
  //CHECK: store float 3.0{{.*}}retval{{.*}}
  static double v = 1.0 / 3.0;
  //CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}
  //CHECK-NOT: fdiv
  return v;
}

#if EXCEPT
namespace ns {
// Check that pragma float_control can appear in namespace.
#pragma float_control(except, on, push)
float exc_on(double x, float zero) {
// CHECK-NS: define {{.*}}exc_on{{.*}}
  {} try {
    x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
  } catch (...) {}
  return zero;
}
}

// Check pragma is still effective after namespace closes
float exc_still_on(double x, float zero) {
// CHECK-NS: define {{.*}}exc_still_on{{.*}}
  {} try {
    x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
  } catch (...) {}
  return zero;
}

#pragma float_control(pop)
float exc_off(double x, float zero) {
// CHECK-NS: define {{.*}}exc_off{{.*}}
  {} try {
    x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: fdiv double
  } catch (...) {}
  return zero;
}

namespace fc_template_namespace {
#pragma float_control(except, on, push)
template <class T>
T exc_on(double x, T zero) {
// CHECK-NS: define {{.*}}fc_template_namespace{{.*}}
  {} try {
    x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
  } catch (...) {}
  return zero;
}
}

#pragma float_control(pop)
float xx(double x, float z) {
  return fc_template_namespace::exc_on<float>(x, z);
}
#endif // EXCEPT

float try_lam(float x, unsigned n) {
// CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}
  float result;
  auto t =
        // Lambda expression begins
        [](float a, float b) {
#pragma float_control( except, on)
            return a * b;
//CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict
        } // end of lambda expression
  (1.0f,2.0f);
  result = x + t;
  return result;
}

float mySub(float x, float y) {
  // CHECK: define {{.*}}float {{.*}}mySub{{.*}}
  // CHECK-NS: fsub float
  // CHECK-SOURCE: fsub float
  // CHECK-DOUBLE: fpext float
  // CHECK-DOUBLE: fpext float
  // CHECK-DOUBLE: fsub double
  // CHECK-DOUBLE: fptrunc double {{.*}} to float
  // CHECK-EXTENDED: fpext float
  // CHECK-EXTENDED: fpext float
  // CHECK-EXTENDED: fsub double
  // CHECK-EXTENDED: fptrunc double {{.*}} to float
  return x - y;
}

float mySubSource(float x, float y) {
// CHECK: define {{.*}}float {{.*}}mySubSource{{.*}}
#pragma clang fp eval_method(source)
  return x - y;
  // CHECK: fsub float
}

float mySubExtended(float x, float y) {
// CHECK: define {{.*}}float {{.*}}mySubExtended{{.*}}
#pragma clang fp eval_method(extended)
  return x - y;
  // CHECK: fpext float
  // CHECK: fpext float
  // CHECK: fsub x86_fp80
  // CHECK: fptrunc x86_fp80 {{.*}} to float
  // CHECK-AIX: fsub double
  // CHECK-AIX: fptrunc double
}

float mySubDouble(float x, float y) {
// CHECK: define {{.*}}float {{.*}}mySubDouble{{.*}}
#pragma clang fp eval_method(double)
  return x - y;
  // CHECK: fpext float
  // CHECK: fpext float
  // CHECK: fsub double
  // CHECK: fptrunc double {{.*}} to float
}

#ifndef NF128
__float128 mySub128(__float128 x, __float128 y) {
  // CHECK: define {{.*}}mySub128{{.*}}
  // Expect no fpext since fp128 is already widest
  // CHECK: load fp128
  // CHECK-NEXT: load fp128
  // CHECK-NEXT: fsub fp128
  // CHECK-NEXT: ret fp128
  return x - y;
}
#endif

void mySubfp16(__fp16 *res, __fp16 *x, __fp16 *y) {
  // CHECK: define {{.*}}mySubfp16{{.*}}
  *res = *x - *y;
  // CHECK: load half
  // CHECK-NEXT: load half
  // CHECK-NEXT: fpext half{{.*}}
  // CHECK-NEXT: load half
  // CHECK-NEXT: load half
  // CHECK-NS: fpext half{{.*}} to float
  // CHECK-DEFAULT: fpext half{{.*}} to float
  // CHECK-DOUBLE: fpext half{{.*}} to float
  // CHECK-EXTENDED: fpext half{{.*}} to float
  // CHECK-NEXT: fsub
  // CHECK-NEXT: fptrunc {{.*}}to half
  // CHECK-NS: fptrunc float {{.*}} to half
  // CHECK-DOUBLE: fptrunc float {{.*}} to half
  // CHECK-EXTENDED: fptrunc float {{.*}} to half
}

float Div(float x, float y, float z) {
  // CHECK: define{{.*}}float {{.*}}Div{{.*}}
  // CHECK-CONST-ARGS: fdiv float
  return x / (y / z);
}

float DivExtended(float x, float y, float z) {
// CHECK: define{{.*}}float {{.*}}DivExtended{{.*}}
#pragma clang fp eval_method(extended)
  // CHECK-CONST-ARGS: fdiv x86_fp80
  // CHECK-CONST-ARGS: fptrunc x86_fp80
  return x / (y / z);
}

float DivDouble(float x, float y, float z) {
// CHECK: define{{.*}}float {{.*}}DivDouble{{.*}}
#pragma clang fp eval_method(double)
  // CHECK-CONST-ARGS: fdiv double
  // CHECK-CONST-ARGS: fptrunc double
  return x / (y / z);
}

float DivSource(float x, float y, float z) {
// CHECK: define{{.*}}float {{.*}}DivSource{{.*}}
#pragma clang fp eval_method(source)
  // CHECK-CONST-ARGS: fdiv float
  return x / (y / z);
}

int main() {
  float f = Div(4.2f, 1.0f, 3.0f);
  float fextended = DivExtended(4.2f, 1.0f, 3.0f);
  float fdouble = DivDouble(4.2f, 1.0f, 3.0f);
  float fsource = DivSource(4.2f, 1.0f, 3.0f);
  // CHECK: store float
}