Home | History | Annotate | Download | only in s390x
      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
     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
     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 *
     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 
     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