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 #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 *
     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
     76 set_rounding_mode(unsigned mode)
     77 {
     78    register unsigned r asm("1") = mode;
     79    __asm__ volatile ( SFPC(1) : : "d"(r) );
     80 }
     81 
     82 
     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