1#include <assert.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <stdint.h>
5#include <inttypes.h>
6#include "opcodes.h"
7#include "rounding.h"
8
9/* Test "convert to fixed"  with rounding mode given in insn (m3 field)
10   Covers all generally available rounding modes that can be mapped to
11   IRRoundingMode. As a consequence m3=1 which is "round to nearest with
12   ties away from 0" is not tested here.
13*/
14
15const char *
16rtext(unsigned m3_round)
17{
18   switch (m3_round) {
19   case 0: return "[-> per fpc]";
20   case 1: return "[-> nearest away]";
21   case 3: return "[-> prepare short]";   // floating point extension fac needed
22   case 4: return "[-> nearest even]";
23   case 5: return "[-> 0]";
24   case 6: return "[-> +inf]";
25   case 7: return "[-> -inf]";
26   }
27   assert(0);
28}
29
30#define convert_to_int(opcode,src_type,dst_type,dst_fmt,round,value) \
31do { \
32   src_type src = value; \
33   dst_type dst;         \
34   unsigned cc;          \
35                         \
36   __asm__ volatile (opcode " %[dst]," #round ",%[src]\n\t"     \
37                     "ipm %[cc]\n\t"                  \
38                     "srl %[cc],28\n\t"               \
39                     : [dst] "=d"(dst), [cc] "=d"(cc) \
40                     : [src] "f"(src)                 \
41                     : "cc");                         \
42                                                      \
43   printf("%s %f\t-> %"dst_fmt"\tcc = %u  %s\n",    \
44          opcode, src, dst, cc, rtext(round));        \
45} while (0)
46
47#define round_to_int(opcode,type,round,value)                   \
48do {                                                            \
49   type src = value;                                            \
50   type dst;                                                    \
51                                                                \
52   __asm__ volatile (opcode " %[dst]," #round ",%[src]\n\t"     \
53                     : [dst] "=f"(dst)                          \
54                     : [src] "f"(src));                         \
55                                                                \
56   printf("%s %.5f\t-> %g  %s\n",                               \
57          opcode, src, dst, rtext(round));                      \
58} while (0)
59
60
61#define cfebr(value, round) \
62        convert_to_int("cfebr",float,int32_t,PRId32,round,value)
63#define cfdbr(value, round) \
64        convert_to_int("cfdbr",double,int32_t,PRId32,round,value)
65#define cgebr(value, round) \
66        convert_to_int("cgebr",float,int64_t,PRId64,round,value)
67#define cgdbr(value, round) \
68        convert_to_int("cgdbr",double,int64_t,PRId64,round,value)
69
70#define fiebr(value, round) \
71        round_to_int("fiebr",float,round,value)
72#define fidbr(value, round) \
73        round_to_int("fidbr",double,round,value)
74
75void
76set_rounding_mode(unsigned mode)
77{
78   register unsigned r asm("1") = mode;
79   __asm__ volatile ( SFPC(1) : : "d"(r) );
80}
81
82
83int main(void)
84{
85   int j;
86   static const float fval[] = {
87      1.25f, 1.5f, 2.5f, 1.75f, -1.25f, -1.5f, -2.5f, -1.75f, 0.0f,
88   };
89   static const double dval[] = {
90      1.25, 1.5, 2.5, 1.75, -1.25, -1.5, -2.5, -1.75, 0.0,
91   };
92
93   /* Note when testing M3_NEAR need to set the FPC rounding mode
94      to something else. FPC rounding mode is NEAR by default.
95      Setting the FPC rounding mode to != NEAR is the only way to make
96      sure the M3 field is not ignored. */
97
98   /* f32 -> i32 */
99   for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
100      set_rounding_mode(FPC_BFP_ROUND_ZERO);
101      cfebr(fval[j], M3_BFP_ROUND_NEAREST_EVEN);
102      set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
103      cfebr(fval[j], M3_BFP_ROUND_ZERO);
104      cfebr(fval[j], M3_BFP_ROUND_POSINF);
105      cfebr(fval[j], M3_BFP_ROUND_NEGINF);
106   }
107
108   /* f32 -> i64 */
109   for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
110      set_rounding_mode(FPC_BFP_ROUND_ZERO);
111      cgebr(fval[j], M3_BFP_ROUND_NEAREST_EVEN);
112      set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
113      cgebr(fval[j], M3_BFP_ROUND_ZERO);
114      cgebr(fval[j], M3_BFP_ROUND_POSINF);
115      cgebr(fval[j], M3_BFP_ROUND_NEGINF);
116   }
117
118   /* f64 -> i32 */
119   for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
120      set_rounding_mode(FPC_BFP_ROUND_ZERO);
121      cfdbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN);
122      set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
123      cfdbr(dval[j], M3_BFP_ROUND_ZERO);
124      cfdbr(dval[j], M3_BFP_ROUND_POSINF);
125      cfdbr(dval[j], M3_BFP_ROUND_NEGINF);
126   }
127
128   /* f64 -> i64 */
129   for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
130      set_rounding_mode(FPC_BFP_ROUND_ZERO);
131      cgdbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN);
132      set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
133      cgdbr(dval[j], M3_BFP_ROUND_ZERO);
134      cgdbr(dval[j], M3_BFP_ROUND_POSINF);
135      cgdbr(dval[j], M3_BFP_ROUND_NEGINF);
136   }
137
138   /* f32 -> f32, round to int */
139   for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
140      set_rounding_mode(FPC_BFP_ROUND_ZERO);
141      fiebr(dval[j], M3_BFP_ROUND_NEAREST_EVEN);
142      set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
143      fiebr(dval[j], M3_BFP_ROUND_ZERO);
144      fiebr(dval[j], M3_BFP_ROUND_POSINF);
145      fiebr(dval[j], M3_BFP_ROUND_NEGINF);
146   }
147
148   /* f64 -> f64, round to int */
149   for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
150      set_rounding_mode(FPC_BFP_ROUND_ZERO);
151      fidbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN);
152      set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
153      fidbr(dval[j], M3_BFP_ROUND_ZERO);
154      fidbr(dval[j], M3_BFP_ROUND_POSINF);
155      fidbr(dval[j], M3_BFP_ROUND_NEGINF);
156   }
157
158   return 0;
159}
160