xref: /llvm-project/clang/test/CodeGen/fp16-ops.c (revision af7c58b7ea853ef34462ce97739203e2da3c5894)
1 // REQUIRES: arm-registered-target
2 // RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s --check-prefix=NOTNATIVE --check-prefix=CHECK
3 // RUN: %clang_cc1 -emit-llvm -o - -triple aarch64 %s | FileCheck %s --check-prefix=NOTNATIVE --check-prefix=CHECK
4 // RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-linux-gnu %s | FileCheck %s --check-prefix=NOTNATIVE --check-prefix=CHECK
5 // RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi -fnative-half-type %s \
6 // RUN:   | FileCheck %s --check-prefix=NATIVE-HALF
7 // RUN: %clang_cc1 -emit-llvm -o - -triple aarch64 -fnative-half-type %s \
8 // RUN:   | FileCheck %s --check-prefix=NATIVE-HALF
9 typedef unsigned cond_t;
10 typedef __fp16 float16_t;
11 
12 volatile cond_t test;
13 volatile int i0;
14 volatile __fp16 h0 = 0.0, h1 = 1.0, h2;
15 volatile float f0, f1, f2;
16 volatile double d0;
17 short s0;
18 
19 void foo(void) {
20   // CHECK-LABEL: define{{.*}} void @foo()
21 
22   // Check unary ops
23 
24   // NOTNATIVE: [[F16TOF32:fpext half]]
25   // CHECK: fptoui float
26   // NATIVE-HALF: fptoui half
27   test = (h0);
28   // CHECK: uitofp i32
29   // NOTNATIVE: [[F32TOF16:fptrunc float]]
30   // NATIVE-HALF: uitofp i32 {{.*}} to half
31   h0 = (test);
32   // CHECK: [[F16TOF32]]
33   // CHECK: fcmp une float
34   // NATIVE-HALF: fcmp une half
35   test = (!h1);
36   // CHECK: [[F16TOF32]]
37   // CHECK: fneg float
38   // NOTNATIVE: [[F32TOF16]]
39   // NATIVE-HALF: fneg half
40   h1 = -h1;
41   // CHECK: [[F16TOF32]]
42   // CHECK: [[F32TOF16]]
43   // NATIVE-HALF: load volatile half
44   // NATIVE-HALF-NEXT: store volatile half
45   h1 = +h1;
46   // CHECK: [[F16TOF32]]
47   // CHECK: fadd float
48   // CHECK: [[F32TOF16]]
49   // NATIVE-HALF: fadd half
50   h1++;
51   // CHECK: [[F16TOF32]]
52   // CHECK: fadd float
53   // CHECK: [[F32TOF16]]
54   // NATIVE-HALF: fadd half
55   ++h1;
56   // CHECK: [[F16TOF32]]
57   // CHECK: fadd float
58   // CHECK: [[F32TOF16]]
59   // NATIVE-HALF: fadd half
60   --h1;
61   // CHECK: [[F16TOF32]]
62   // CHECK: fadd float
63   // CHECK: [[F32TOF16]]
64   // NATIVE-HALF: fadd half
65   h1--;
66 
67   // Check binary ops with various operands
68   // CHECK: [[F16TOF32]]
69   // CHECK: [[F16TOF32]]
70   // CHECK: fmul float
71   // CHECK: [[F32TOF16]]
72   // NATIVE-HALF: fmul half
73   h1 = h0 * h2;
74   // CHECK: [[F16TOF32]]
75   // CHECK: fmul float
76   // CHECK: [[F32TOF16]]
77   // NATIVE-HALF: fmul half
78   h1 = h0 * (__fp16) -2.0f;
79   // CHECK: [[F16TOF32]]
80   // CHECK: fmul float
81   // CHECK: [[F32TOF16]]
82   // NATIVE-HALF: fpext half
83   // NATIVE-HALF: fmul float
84   h1 = h0 * f2;
85   // CHECK: [[F16TOF32]]
86   // CHECK: fmul float
87   // CHECK: [[F32TOF16]]
88   // NATIVE-HALF: fpext half
89   // NATIVE-HALF: fmul float
90   h1 = f0 * h2;
91   // CHECK: [[F16TOF32]]
92   // CHECK: fmul float
93   // CHECK: [[F32TOF16]]
94   // NATIVE-HALF: fmul half
95   h1 = h0 * i0;
96 
97   // CHECK: [[F16TOF32]]
98   // CHECK: [[F16TOF32]]
99   // CHECK: fdiv float
100   // CHECK: [[F32TOF16]]
101   // NATIVE-HALF: fdiv half
102   h1 = (h0 / h2);
103   // CHECK: [[F16TOF32]]
104   // CHECK: fdiv float
105   // CHECK: [[F32TOF16]]
106   // NATIVE-HALF: fdiv half
107   h1 = (h0 / (__fp16) -2.0f);
108   // CHECK: [[F16TOF32]]
109   // CHECK: fdiv float
110   // CHECK: [[F32TOF16]]
111   // NATIVE-HALF: fpext half
112   // NATIVE-HALF: fdiv float
113   h1 = (h0 / f2);
114   // CHECK: [[F16TOF32]]
115   // CHECK: fdiv float
116   // CHECK: [[F32TOF16]]
117   // NATIVE-HALF: fpext half
118   // NATIVE-HALF: fdiv float
119   h1 = (f0 / h2);
120   // CHECK: [[F16TOF32]]
121   // CHECK: fdiv float
122   // CHECK: [[F32TOF16]]
123   // NATIVE-HALF: fdiv half
124   h1 = (h0 / i0);
125 
126   // CHECK: [[F16TOF32]]
127   // CHECK: [[F16TOF32]]
128   // CHECK: fadd float
129   // CHECK: [[F32TOF16]]
130   // NATIVE-HALF: fadd half
131   h1 = (h2 + h0);
132   // CHECK: [[F16TOF32]]
133   // CHECK: fadd float
134   // CHECK: [[F32TOF16]]
135   // NATIVE-HALF: fadd half
136   h1 = ((__fp16)-2.0 + h0);
137   // CHECK: [[F16TOF32]]
138   // CHECK: fadd float
139   // CHECK: [[F32TOF16]]
140   // NATIVE-HALF: fpext half
141   // NATIVE-HALF: fadd float
142   h1 = (h2 + f0);
143   // CHECK: [[F16TOF32]]
144   // CHECK: fadd float
145   // CHECK: [[F32TOF16]]
146   // NATIVE-HALF: fpext half
147   // NATIVE-HALF: fadd float
148   h1 = (f2 + h0);
149   // CHECK: [[F16TOF32]]
150   // CHECK: fadd float
151   // CHECK: [[F32TOF16]]
152   // NATIVE-HALF: fadd half
153   h1 = (h0 + i0);
154 
155   // CHECK: [[F16TOF32]]
156   // CHECK: [[F16TOF32]]
157   // CHECK: fsub float
158   // CHECK: [[F32TOF16]]
159   // NATIVE-HALF: fsub half
160   h1 = (h2 - h0);
161   // CHECK: [[F16TOF32]]
162   // CHECK: fsub float
163   // CHECK: [[F32TOF16]]
164   // NATIVE-HALF: fsub half
165   h1 = ((__fp16)-2.0f - h0);
166   // CHECK: [[F16TOF32]]
167   // CHECK: fsub float
168   // CHECK: [[F32TOF16]]
169   // NATIVE-HALF: fpext half
170   // NATIVE-HALF: fsub float
171   h1 = (h2 - f0);
172   // CHECK: [[F16TOF32]]
173   // CHECK: fsub float
174   // CHECK: [[F32TOF16]]
175   // NATIVE-HALF: fpext half
176   // NATIVE-HALF: fsub float
177   h1 = (f2 - h0);
178   // CHECK: [[F16TOF32]]
179   // CHECK: fsub float
180   // CHECK: [[F32TOF16]]
181   // NATIVE-HALF: fsub half
182   h1 = (h0 - i0);
183 
184   // CHECK: [[F16TOF32]]
185   // CHECK: [[F16TOF32]]
186   // CHECK: fcmp olt float
187   // NATIVE-HALF: fcmp olt half
188   test = (h2 < h0);
189   // CHECK: [[F16TOF32]]
190   // CHECK: fcmp olt float
191   // NATIVE-HALF: fcmp olt half
192   test = (h2 < (__fp16)42.0);
193   // CHECK: [[F16TOF32]]
194   // CHECK: fcmp olt float
195   // NATIVE-HALF: fpext half
196   // NATIVE-HALF: fcmp olt float
197   test = (h2 < f0);
198   // CHECK: [[F16TOF32]]
199   // CHECK: fcmp olt float
200   // NATIVE-HALF: fpext half
201   // NATIVE-HALF: fcmp olt float
202   test = (f2 < h0);
203   // CHECK: [[F16TOF32]]
204   // CHECK: fcmp olt float
205   // NATIVE-HALF: fcmp olt half
206   test = (i0 < h0);
207   // CHECK: [[F16TOF32]]
208   // CHECK: fcmp olt float
209   // NATIVE-HALF: fcmp olt half
210   test = (h0 < i0);
211 
212   // CHECK: [[F16TOF32]]
213   // CHECK: [[F16TOF32]]
214   // CHECK: fcmp ogt float
215   // NATIVE-HALF: fcmp ogt half
216   test = (h0 > h2);
217   // CHECK: [[F16TOF32]]
218   // CHECK: fcmp ogt float
219   // NATIVE-HALF: fcmp ogt half
220   test = ((__fp16)42.0 > h2);
221   // CHECK: [[F16TOF32]]
222   // CHECK: fcmp ogt float
223   // NATIVE-HALF: fpext half
224   // NATIVE-HALF: fcmp ogt float
225   test = (h0 > f2);
226   // CHECK: [[F16TOF32]]
227   // CHECK: fcmp ogt float
228   // NATIVE-HALF: fpext half
229   // NATIVE-HALF: fcmp ogt float
230   test = (f0 > h2);
231   // CHECK: [[F16TOF32]]
232   // CHECK: fcmp ogt float
233   // NATIVE-HALF: fcmp ogt half
234   test = (i0 > h0);
235   // CHECK: [[F16TOF32]]
236   // CHECK: fcmp ogt float
237   // NATIVE-HALF: fcmp ogt half
238   test = (h0 > i0);
239 
240   // CHECK: [[F16TOF32]]
241   // CHECK: [[F16TOF32]]
242   // CHECK: fcmp ole float
243   // NATIVE-HALF: fcmp ole half
244   test = (h2 <= h0);
245   // CHECK: [[F16TOF32]]
246   // CHECK: fcmp ole float
247   // NATIVE-HALF: fcmp ole half
248   test = (h2 <= (__fp16)42.0);
249   // CHECK: [[F16TOF32]]
250   // CHECK: fcmp ole float
251   // NATIVE-HALF: fpext half
252   // NATIVE-HALF: fcmp ole float
253   test = (h2 <= f0);
254   // CHECK: [[F16TOF32]]
255   // CHECK: fcmp ole float
256   // NATIVE-HALF: fpext half
257   // NATIVE-HALF: fcmp ole float
258   test = (f2 <= h0);
259   // CHECK: [[F16TOF32]]
260   // CHECK: fcmp ole float
261   // NATIVE-HALF: fcmp ole half
262   test = (i0 <= h0);
263   // CHECK: [[F16TOF32]]
264   // CHECK: fcmp ole float
265   // NATIVE-HALF: fcmp ole half
266   test = (h0 <= i0);
267 
268 
269   // CHECK: [[F16TOF32]]
270   // CHECK: [[F16TOF32]]
271   // CHECK: fcmp oge float
272   // NATIVE-HALF: fcmp oge half
273   test = (h0 >= h2);
274   // CHECK: [[F16TOF32]]
275   // CHECK: fcmp oge float
276   // NATIVE-HALF: fcmp oge half
277   test = (h0 >= (__fp16)-2.0);
278   // CHECK: [[F16TOF32]]
279   // CHECK: fcmp oge float
280   // NATIVE-HALF: fpext half
281   // NATIVE-HALF: fcmp oge float
282   test = (h0 >= f2);
283   // CHECK: [[F16TOF32]]
284   // CHECK: fcmp oge float
285   // NATIVE-HALF: fpext half
286   // NATIVE-HALF: fcmp oge float
287   test = (f0 >= h2);
288   // CHECK: [[F16TOF32]]
289   // CHECK: fcmp oge float
290   // NATIVE-HALF: fcmp oge half
291   test = (i0 >= h0);
292   // CHECK: [[F16TOF32]]
293   // CHECK: fcmp oge float
294   // NATIVE-HALF: fcmp oge half
295   test = (h0 >= i0);
296 
297   // CHECK: [[F16TOF32]]
298   // CHECK: [[F16TOF32]]
299   // CHECK: fcmp oeq float
300   // NATIVE-HALF: fcmp oeq half
301   test = (h1 == h2);
302   // CHECK: [[F16TOF32]]
303   // CHECK: fcmp oeq float
304   // NATIVE-HALF: fcmp oeq half
305   test = (h1 == (__fp16)1.0);
306   // CHECK: [[F16TOF32]]
307   // CHECK: fcmp oeq float
308   // NATIVE-HALF: fpext half
309   // NATIVE-HALF: fcmp oeq float
310   test = (h1 == f1);
311   // CHECK: [[F16TOF32]]
312   // CHECK: fcmp oeq float
313   // NATIVE-HALF: fpext half
314   // NATIVE-HALF: fcmp oeq float
315   test = (f1 == h1);
316   // CHECK: [[F16TOF32]]
317   // CHECK: fcmp oeq float
318   // NATIVE-HALF: fcmp oeq half
319   test = (i0 == h0);
320   // CHECK: [[F16TOF32]]
321   // CHECK: fcmp oeq float
322   // NATIVE-HALF: fcmp oeq half
323   test = (h0 == i0);
324 
325   // CHECK: [[F16TOF32]]
326   // CHECK: [[F16TOF32]]
327   // CHECK: fcmp une float
328   // NATIVE-HALF: fcmp une half
329   test = (h1 != h2);
330   // CHECK: [[F16TOF32]]
331   // CHECK: fcmp une float
332   // NATIVE-HALF: fcmp une half
333   test = (h1 != (__fp16)1.0);
334   // CHECK: [[F16TOF32]]
335   // CHECK: fcmp une float
336   // NATIVE-HALF: fpext half
337   // NATIVE-HALF: fcmp une float
338   test = (h1 != f1);
339   // CHECK: [[F16TOF32]]
340   // CHECK: fcmp une float
341   // NATIVE-HALF: fpext half
342   // NATIVE-HALF: fcmp une float
343   test = (f1 != h1);
344   // CHECK: [[F16TOF32]]
345   // CHECK: fcmp une float
346   // NATIVE-HALF: fcmp une half
347   test = (i0 != h0);
348   // CHECK: [[F16TOF32]]
349   // CHECK: fcmp une float
350   // NATIVE-HALF: fcmp une half
351   test = (h0 != i0);
352 
353   // CHECK: [[F16TOF32]]
354   // CHECK: fcmp une float
355   // CHECK: [[F16TOF32]]
356   // CHECK: [[F16TOF32]]
357   // CHECK: [[F32TOF16]]
358   // NATIVE-HALF: fcmp une half {{.*}}, 0xH0000
359   h1 = (h1 ? h2 : h0);
360   // Check assignments (inc. compound)
361   h0 = h1;
362   // NOTNATIVE: store {{.*}} half 0xHC000
363   // NATIVE-HALF: store {{.*}} half 0xHC000
364   h0 = (__fp16)-2.0f;
365   // CHECK: [[F32TOF16]]
366   // NATIVE-HALF: fptrunc float
367   h0 = f0;
368 
369   // CHECK: sitofp i32 {{.*}} to float
370   // CHECK: [[F32TOF16]]
371   // NATIVE-HALF: sitofp i32 {{.*}} to half
372   h0 = i0;
373   // CHECK: [[F16TOF32]]
374   // CHECK: fptosi float {{.*}} to i32
375   // NATIVE-HALF: fptosi half {{.*}} to i32
376   i0 = h0;
377 
378   // CHECK: [[F16TOF32]]
379   // CHECK: [[F16TOF32]]
380   // CHECK: fadd float
381   // CHECK: [[F32TOF16]]
382   // NATIVE-HALF: fadd half
383   h0 += h1;
384   // CHECK: [[F16TOF32]]
385   // CHECK: fadd float
386   // CHECK: [[F32TOF16]]
387   // NATIVE-HALF: fadd half
388   h0 += (__fp16)1.0f;
389   // CHECK: [[F16TOF32]]
390   // CHECK: fadd float
391   // CHECK: [[F32TOF16]]
392   // NATIVE-HALF: fpext half
393   // NATIVE-HALF: fadd float
394   // NATIVE-HALF: fptrunc float
395   h0 += f2;
396   // CHECK: [[F16TOF32]]
397   // CHECK: sitofp i32 {{.*}} to float
398   // CHECK: fadd float
399   // CHECK: fptosi float {{.*}} to i32
400   // NATIVE-HALF: sitofp i32 {{.*}} to half
401   // NATIVE-HALF: fadd half
402   // NATIVE-HALF: fptosi half {{.*}} to i32
403   i0 += h0;
404   // CHECK: sitofp i32 {{.*}} to float
405   // CHECK: [[F16TOF32]]
406   // CHECK: fadd float
407   // CHECK: [[F32TOF16]]
408   // NATIVE-HALF: sitofp i32 {{.*}} to half
409   // NATIVE-HALF: fadd half
410   h0 += i0;
411 
412   // CHECK: [[F16TOF32]]
413   // CHECK: [[F16TOF32]]
414   // CHECK: fsub float
415   // CHECK: [[F32TOF16]]
416   // NATIVE-HALF: fsub half
417   h0 -= h1;
418   // CHECK: [[F16TOF32]]
419   // CHECK: fsub float
420   // CHECK: [[F32TOF16]]
421   // NATIVE-HALF: fsub half
422   h0 -= (__fp16)1.0;
423   // CHECK: [[F16TOF32]]
424   // CHECK: fsub float
425   // CHECK: [[F32TOF16]]
426   // NATIVE-HALF: fpext half
427   // NATIVE-HALF: fsub float
428   // NATIVE-HALF: fptrunc float
429   h0 -= f2;
430   // CHECK: [[F16TOF32]]
431   // CHECK: sitofp i32 {{.*}} to float
432   // CHECK: fsub float
433   // CHECK: fptosi float {{.*}} to i32
434   // NATIVE-HALF: sitofp i32 {{.*}} to half
435   // NATIVE-HALF: fsub half
436   // NATIVE-HALF: fptosi half {{.*}} to i32
437   i0 -= h0;
438   // CHECK: sitofp i32 {{.*}} to float
439   // CHECK: [[F16TOF32]]
440   // CHECK: fsub float
441   // CHECK: [[F32TOF16]]
442   // NATIVE-HALF: sitofp i32 {{.*}} to half
443   // NATIVE-HALF: fsub half
444   h0 -= i0;
445 
446   // CHECK: [[F16TOF32]]
447   // CHECK: [[F16TOF32]]
448   // CHECK: fmul float
449   // CHECK: [[F32TOF16]]
450   // NATIVE-HALF: fmul half
451   h0 *= h1;
452   // CHECK: [[F16TOF32]]
453   // CHECK: fmul float
454   // CHECK: [[F32TOF16]]
455   // NATIVE-HALF: fmul half
456   h0 *= (__fp16)1.0;
457   // CHECK: [[F16TOF32]]
458   // CHECK: fmul float
459   // CHECK: [[F32TOF16]]
460   // NATIVE-HALF: fpext half
461   // NATIVE-HALF: fmul float
462   // NATIVE-HALF: fptrunc float
463   h0 *= f2;
464   // CHECK: [[F16TOF32]]
465   // CHECK: sitofp i32 {{.*}} to float
466   // CHECK: fmul float
467   // CHECK: fptosi float {{.*}} to i32
468   // NATIVE-HALF: sitofp i32 {{.*}} to half
469   // NATIVE-HALF: fmul half
470   // NATIVE-HALF: fptosi half {{.*}} to i32
471   i0 *= h0;
472   // CHECK: sitofp i32 {{.*}} to float
473   // CHECK: [[F16TOF32]]
474   // CHECK: fmul float
475   // CHECK: [[F32TOF16]]
476   // NATIVE-HALF: sitofp i32 {{.*}} to half
477   // NATIVE-HALF: fmul half
478   h0 *= i0;
479 
480   // CHECK: [[F16TOF32]]
481   // CHECK: [[F16TOF32]]
482   // CHECK: fdiv float
483   // CHECK: [[F32TOF16]]
484   // NATIVE-HALF: fdiv half
485   h0 /= h1;
486   // CHECK: [[F16TOF32]]
487   // CHECK: fdiv float
488   // CHECK: [[F32TOF16]]
489   // NATIVE-HALF: fdiv half
490   h0 /= (__fp16)1.0;
491   // CHECK: [[F16TOF32]]
492   // CHECK: fdiv float
493   // CHECK: [[F32TOF16]]
494   // NATIVE-HALF: fpext half
495   // NATIVE-HALF: fdiv float
496   // NATIVE-HALF: fptrunc float
497   h0 /= f2;
498   // CHECK: [[F16TOF32]]
499   // CHECK: sitofp i32 {{.*}} to float
500   // CHECK: fdiv float
501   // CHECK: fptosi float {{.*}} to i32
502   // NATIVE-HALF: sitofp i32 {{.*}} to half
503   // NATIVE-HALF: fdiv half
504   // NATIVE-HALF: fptosi half {{.*}} to i32
505   i0 /= h0;
506   // CHECK: sitofp i32 {{.*}} to float
507   // CHECK: [[F16TOF32]]
508   // CHECK: fdiv float
509   // CHECK: [[F32TOF16]]
510   // NATIVE-HALF: sitofp i32 {{.*}} to half
511   // NATIVE-HALF: fdiv half
512   h0 /= i0;
513 
514   // Check conversions to/from double
515   // NOTNATIVE: fptrunc double {{.*}} to half
516   // NATIVE-HALF: fptrunc double {{.*}} to half
517   h0 = d0;
518 
519   // CHECK: [[MID:%.*]] = fptrunc double {{%.*}} to float
520   // NOTNATIVE: fptrunc float [[MID]] to half
521   // NATIVE-HALF: [[MID:%.*]] = fptrunc double {{%.*}} to float
522   // NATIVE-HALF: fptrunc float {{.*}} to half
523   h0 = (float)d0;
524 
525   // NOTNATIVE: fpext half {{.*}} to double
526   // NATIVE-HALF: fpext half {{.*}} to double
527   d0 = h0;
528 
529   // NOTNATIVE: [[MID:%.*]] = fpext half {{.*}} to float
530   // CHECK: fpext float [[MID]] to double
531   // NATIVE-HALF: [[MID:%.*]] = fpext half {{.*}} to float
532   // NATIVE-HALF: fpext float [[MID]] to double
533   d0 = (float)h0;
534 
535   // NOTNATIVE: [[V1:%.*]] = load i16, ptr @s0
536   // NOTNATIVE: [[CONV:%.*]] = sitofp i16 [[V1]] to float
537   // NOTNATIVE: [[TRUNC:%.*]] = fptrunc float [[CONV]] to half
538   // NOTNATIVE: store volatile half [[TRUNC]], ptr @h0
539   h0 = s0;
540 }
541 
542 // CHECK-LABEL: define{{.*}} void @testTypeDef(
543 // CHECK: %[[CONV:.*]] = fpext <4 x half> %{{.*}} to <4 x float>
544 // CHECK: %[[CONV1:.*]] = fpext <4 x half> %{{.*}} to <4 x float>
545 // CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV]], %[[CONV1]]
546 // CHECK: fptrunc <4 x float> %[[ADD]] to <4 x half>
547 
548 void testTypeDef() {
549   __fp16 t0 __attribute__((vector_size(8)));
550   float16_t t1 __attribute__((vector_size(8)));
551   t1 = t0 + t1;
552 }
553