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 
     48 #define cfebr(value, round) \
     49         convert_to_int("cfebr",float,int32_t,PRId32,round,value)
     50 #define cfdbr(value, round) \
     51         convert_to_int("cfdbr",double,int32_t,PRId32,round,value)
     52 #define cgebr(value, round) \
     53         convert_to_int("cgebr",float,int64_t,PRId64,round,value)
     54 #define cgdbr(value, round) \
     55         convert_to_int("cgdbr",double,int64_t,PRId64,round,value)
     56 
     57 void
     58 set_rounding_mode(unsigned mode)
     59 {
     60    register unsigned r asm("1") = mode;
     61    __asm__ volatile ( SFPC(1) : : "d"(r) );
     62 }
     63 
     64 
     65 int main(void)
     66 {
     67    int j;
     68    static const float fval[] = {
     69       1.4f, 1.5f, 2.5f, 1.6f, -1.4f, -1.5f, -2.5f, -1.6f, 0.0f,
     70    };
     71    static const double dval[] = {
     72       1.4, 1.5, 2.5, 1.6, -1.4, -1.5, -2.5, -1.6, 0.0,
     73    };
     74 
     75    /* Note when testing M3_NEAR need to set the FPC rounding mode
     76       to something else. FPC rounding mode is NEAR by default.
     77       Setting the FPC rounding mode to != NEAR is the only way to make
     78       sure the M3 field is not ignored. */
     79 
     80    /* f32 -> i32 */
     81    for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
     82       set_rounding_mode(FPC_BFP_ROUND_ZERO);
     83       cfebr(fval[j], M3_BFP_ROUND_NEAREST_EVEN);
     84       set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
     85       cfebr(fval[j], M3_BFP_ROUND_ZERO);
     86       cfebr(fval[j], M3_BFP_ROUND_POSINF);
     87       cfebr(fval[j], M3_BFP_ROUND_NEGINF);
     88    }
     89 
     90    /* f32 -> i64 */
     91    for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
     92       set_rounding_mode(FPC_BFP_ROUND_ZERO);
     93       cgebr(fval[j], M3_BFP_ROUND_NEAREST_EVEN);
     94       set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
     95       cgebr(fval[j], M3_BFP_ROUND_ZERO);
     96       cgebr(fval[j], M3_BFP_ROUND_POSINF);
     97       cgebr(fval[j], M3_BFP_ROUND_NEGINF);
     98    }
     99 
    100    /* f64 -> i32 */
    101    for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
    102       set_rounding_mode(FPC_BFP_ROUND_ZERO);
    103       cfdbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN);
    104       set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
    105       cfdbr(dval[j], M3_BFP_ROUND_ZERO);
    106       cfdbr(dval[j], M3_BFP_ROUND_POSINF);
    107       cfdbr(dval[j], M3_BFP_ROUND_NEGINF);
    108    }
    109 
    110    /* f64 -> i64 */
    111    for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
    112       set_rounding_mode(FPC_BFP_ROUND_ZERO);
    113       cgdbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN);
    114       set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN);
    115       cgdbr(dval[j], M3_BFP_ROUND_ZERO);
    116       cgdbr(dval[j], M3_BFP_ROUND_POSINF);
    117       cgdbr(dval[j], M3_BFP_ROUND_NEGINF);
    118    }
    119 
    120    return 0;
    121 }
    122