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
12void
13set_rounding_mode(unsigned mode)
14{
15   register unsigned r asm("1") = mode;
16   __asm__ volatile ( SFPC(1) : : "d"(r) );
17}
18
19unsigned
20get_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
30const char *
31rtext(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) \
43do { \
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
69int main(void)
70{
71   int i, j;
72   static const unsigned rmodes[] = { 0, 1, 2, 3 };
73   static const float fval[] = {
74      1.4f, 1.5f, 2.5f, 1.6f, -1.4f, -1.5f, -2.5f, -1.6f, 0.0f,
75   };
76   static const double dval[] = {
77      1.4, 1.5, 2.5, 1.6, -1.4, -1.5, -2.5, -1.6, 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