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 
15 const char *
rtext(unsigned m3_round)16 rtext(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) \
31 do { \
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)                   \
48 do {                                                            \
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 
75 void
set_rounding_mode(unsigned mode)76 set_rounding_mode(unsigned mode)
77 {
78    register unsigned r asm("1") = mode;
79    __asm__ volatile ( SFPC(1) : : "d"(r) );
80 }
81 
82 
main(void)83 int 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