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