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 
8 /* Test "convert to fixed"  with "per fpc" rounding.
9    Covers all generally available rounding modes.
10 */
11 
12 void
set_rounding_mode(unsigned mode)13 set_rounding_mode(unsigned mode)
14 {
15    register unsigned r asm("1") = mode;
16    __asm__ volatile ( SFPC(1) : : "d"(r) );
17 }
18 
19 unsigned
get_rounding_mode(void)20 get_rounding_mode(void)
21 {
22    unsigned fpc;
23 
24    __asm__ volatile ("stfpc  %0\n\t" : "=m"(fpc));
25 
26    return fpc & 0x7;
27 }
28 
29 
30 const char *
rtext(unsigned fpc_round)31 rtext(unsigned fpc_round)
32 {
33    switch (fpc_round) {
34    case 0: return "[-> near]";
35    case 1: return "[-> zero]";
36    case 2: return "[-> +inf]";
37    case 3: return "[-> -inf]";
38    }
39    assert(0);
40 }
41 
42 #define convert_to_int(opcode,src_type,dst_type,dst_fmt,round,value) \
43 do { \
44    src_type src = value; \
45    dst_type dst;         \
46    unsigned cc;          \
47                          \
48    __asm__ volatile (opcode " %[dst]," #round ",%[src]\n\t"     \
49                      "ipm %[cc]\n\t"                  \
50                      "srl %[cc],28\n\t"               \
51                      : [dst] "=d"(dst), [cc] "=d"(cc) \
52                      : [src] "f"(src)                 \
53                      : "cc");                         \
54                                                       \
55    printf("%s %f\t-> %"dst_fmt"\tcc = %u\n",    \
56           opcode, src, dst, cc);        \
57 } while (0)
58 
59 
60 #define cfebr(value) \
61         convert_to_int("cfebr",float,int32_t,PRId32,0,value)
62 #define cfdbr(value) \
63         convert_to_int("cfdbr",double,int32_t,PRId32,0,value)
64 #define cgebr(value) \
65         convert_to_int("cgebr",float,int64_t,PRId64,0,value)
66 #define cgdbr(value) \
67         convert_to_int("cgdbr",double,int64_t,PRId64,0,value)
68 
main(void)69 int main(void)
70 {
71    int i, j;
72    static const unsigned rmodes[] = { 0, 1, 2, 3 };
73    static const float fval[] = {
74       1.25f, 1.5f, 2.5f, 1.75f, -1.25f, -1.5f, -2.5f, -1.75f, 0.0f,
75    };
76    static const double dval[] = {
77       1.25, 1.5, 2.5, 1.75, -1.25, -1.5, -2.5, -1.75, 0.0,
78    };
79 
80 
81    for (i = 0; i < sizeof rmodes / sizeof rmodes[0]; ++i) {
82       printf("setting rounding mode to %s\n", rtext(rmodes[i]));
83       set_rounding_mode(rmodes[i]);
84       assert(get_rounding_mode() == rmodes[i]);
85 
86       /* f32 -> i32 */
87       for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
88          cfebr(fval[j]);
89          assert(get_rounding_mode() == rmodes[i]);
90       }
91 
92       /* f32 -> i64 */
93       for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
94          cgebr(fval[j]);
95          assert(get_rounding_mode() == rmodes[i]);
96       }
97 
98       /* f64 -> i32 */
99       for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
100          cfdbr(dval[j]);
101          assert(get_rounding_mode() == rmodes[i]);
102       }
103 
104       /* f64 -> i64 */
105       for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
106          cgdbr(dval[j]);
107          assert(get_rounding_mode() == rmodes[i]);
108       }
109 
110    }
111 
112    return 0;
113 }
114