cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

fcvt.c (11820B)


      1/*
      2 * Test Floating Point Conversion
      3 */
      4
      5/* we want additional float type definitions */
      6#define __STDC_WANT_IEC_60559_BFP_EXT__
      7#define __STDC_WANT_IEC_60559_TYPES_EXT__
      8
      9#include <stdio.h>
     10#include <inttypes.h>
     11#include <math.h>
     12#include <float.h>
     13#include <fenv.h>
     14
     15#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
     16
     17static char flag_str[256];
     18
     19static char *get_flag_state(int flags)
     20{
     21    if (flags) {
     22        snprintf(flag_str, sizeof(flag_str), "%s %s %s %s %s",
     23                 flags & FE_OVERFLOW ? "OVERFLOW" : "",
     24                 flags & FE_UNDERFLOW ? "UNDERFLOW" : "",
     25                 flags & FE_DIVBYZERO ? "DIV0" : "",
     26                 flags & FE_INEXACT ? "INEXACT" : "",
     27                 flags & FE_INVALID ? "INVALID" : "");
     28    } else {
     29        snprintf(flag_str, sizeof(flag_str), "OK");
     30    }
     31
     32    return flag_str;
     33}
     34
     35static void print_double_number(int i, double num)
     36{
     37    uint64_t double_as_hex = *(uint64_t *) &num;
     38    int flags = fetestexcept(FE_ALL_EXCEPT);
     39    char *fstr = get_flag_state(flags);
     40
     41    printf("%02d DOUBLE: %02.20e / %#020" PRIx64 " (%#x => %s)\n",
     42           i, num, double_as_hex, flags, fstr);
     43}
     44
     45static void print_single_number(int i, float num)
     46{
     47    uint32_t single_as_hex = *(uint32_t *) &num;
     48    int flags = fetestexcept(FE_ALL_EXCEPT);
     49    char *fstr = get_flag_state(flags);
     50
     51    printf("%02d SINGLE: %02.20e / %#010x  (%#x => %s)\n",
     52           i, num, single_as_hex, flags, fstr);
     53}
     54
     55static void print_half_number(int i, uint16_t num)
     56{
     57    int flags = fetestexcept(FE_ALL_EXCEPT);
     58    char *fstr = get_flag_state(flags);
     59
     60    printf("%02d   HALF: %#04x  (%#x => %s)\n",
     61           i, num, flags, fstr);
     62}
     63
     64static void print_int64(int i, int64_t num)
     65{
     66    uint64_t int64_as_hex = *(uint64_t *) &num;
     67    int flags = fetestexcept(FE_ALL_EXCEPT);
     68    char *fstr = get_flag_state(flags);
     69
     70    printf("%02d   INT64: %20" PRId64 "/%#020" PRIx64 " (%#x => %s)\n",
     71           i, num, int64_as_hex, flags, fstr);
     72}
     73
     74#ifndef SNANF
     75/* Signaling NaN macros, if supported.  */
     76# define SNANF (__builtin_nansf (""))
     77# define SNAN (__builtin_nans (""))
     78# define SNANL (__builtin_nansl (""))
     79#endif
     80
     81float single_numbers[] = { -SNANF,
     82                           -NAN,
     83                           -INFINITY,
     84                           -FLT_MAX,
     85                           -1.111E+31,
     86                           -1.111E+30,
     87                           -1.08700982e-12,
     88                           -1.78051176e-20,
     89                           -FLT_MIN,
     90                           0.0,
     91                           FLT_MIN,
     92                           2.98023224e-08,
     93                           5.96046E-8, /* min positive FP16 subnormal */
     94                           6.09756E-5, /* max subnormal FP16 */
     95                           6.10352E-5, /* min positive normal FP16 */
     96                           1.0,
     97                           1.0009765625, /* smallest float after 1.0 FP16 */
     98                           2.0,
     99                           M_E, M_PI,
    100                           65503.0,
    101                           65504.0, /* max FP16 */
    102                           65505.0,
    103                           131007.0,
    104                           131008.0, /* max AFP */
    105                           131009.0,
    106                           1.111E+30,
    107                           FLT_MAX,
    108                           INFINITY,
    109                           NAN,
    110                           SNANF };
    111
    112static void convert_single_to_half(void)
    113{
    114    int i;
    115
    116    printf("Converting single-precision to half-precision\n");
    117
    118    for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
    119        float input = single_numbers[i];
    120
    121        feclearexcept(FE_ALL_EXCEPT);
    122
    123        print_single_number(i, input);
    124#if defined(__arm__)
    125        uint32_t output;
    126        asm("vcvtb.f16.f32 %0, %1" : "=t" (output) : "x" (input));
    127#else
    128        uint16_t output;
    129        asm("fcvt %h0, %s1" : "=w" (output) : "x" (input));
    130#endif
    131        print_half_number(i, output);
    132    }
    133}
    134
    135static void convert_single_to_double(void)
    136{
    137    int i;
    138
    139    printf("Converting single-precision to double-precision\n");
    140
    141    for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
    142        float input = single_numbers[i];
    143        /* uint64_t output; */
    144        double output;
    145
    146        feclearexcept(FE_ALL_EXCEPT);
    147
    148        print_single_number(i, input);
    149#if defined(__arm__)
    150        asm("vcvt.f64.f32 %P0, %1" : "=w" (output) : "t" (input));
    151#else
    152        asm("fcvt %d0, %s1" : "=w" (output) : "x" (input));
    153#endif
    154        print_double_number(i, output);
    155    }
    156}
    157
    158static void convert_single_to_integer(void)
    159{
    160    int i;
    161
    162    printf("Converting single-precision to integer\n");
    163
    164    for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
    165        float input = single_numbers[i];
    166        int64_t output;
    167
    168        feclearexcept(FE_ALL_EXCEPT);
    169
    170        print_single_number(i, input);
    171#if defined(__arm__)
    172        /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */
    173        output = input;
    174#else
    175        asm("fcvtzs %0, %s1" : "=r" (output) : "w" (input));
    176#endif
    177        print_int64(i, output);
    178    }
    179}
    180
    181/* This allows us to initialise some doubles as pure hex */
    182typedef union {
    183    double d;
    184    uint64_t h;
    185} test_doubles;
    186
    187test_doubles double_numbers[] = {
    188    {SNAN},
    189    {-NAN},
    190    {-INFINITY},
    191    {-DBL_MAX},
    192    {-FLT_MAX-1.0},
    193    {-FLT_MAX},
    194    {-1.111E+31},
    195    {-1.111E+30}, /* half prec */
    196    {-2.0}, {-1.0},
    197    {-DBL_MIN},
    198    {-FLT_MIN},
    199    {0.0},
    200    {FLT_MIN},
    201    {2.98023224e-08},
    202    {5.96046E-8}, /* min positive FP16 subnormal */
    203    {6.09756E-5}, /* max subnormal FP16 */
    204    {6.10352E-5}, /* min positive normal FP16 */
    205    {1.0},
    206    {1.0009765625}, /* smallest float after 1.0 FP16 */
    207    {DBL_MIN},
    208    {1.3789972848607228e-308},
    209    {1.4914738736681624e-308},
    210    {1.0}, {2.0},
    211    {M_E}, {M_PI},
    212    {65503.0},
    213    {65504.0}, /* max FP16 */
    214    {65505.0},
    215    {131007.0},
    216    {131008.0}, /* max AFP */
    217    {131009.0},
    218    {.h = 0x41dfffffffc00000 }, /* to int = 0x7fffffff */
    219    {FLT_MAX},
    220    {FLT_MAX + 1.0},
    221    {DBL_MAX},
    222    {INFINITY},
    223    {NAN},
    224    {.h = 0x7ff0000000000001}, /* SNAN */
    225    {SNAN},
    226};
    227
    228static void convert_double_to_half(void)
    229{
    230    int i;
    231
    232    printf("Converting double-precision to half-precision\n");
    233
    234    for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
    235        double input = double_numbers[i].d;
    236        uint16_t output;
    237
    238        feclearexcept(FE_ALL_EXCEPT);
    239
    240        print_double_number(i, input);
    241
    242        /* as we don't have _Float16 support */
    243#if defined(__arm__)
    244        /* asm("vcvtb.f16.f64 %0, %P1" : "=t" (output) : "x" (input)); */
    245        output = input;
    246#else
    247        asm("fcvt %h0, %d1" : "=w" (output) : "x" (input));
    248#endif
    249        print_half_number(i, output);
    250    }
    251}
    252
    253static void convert_double_to_single(void)
    254{
    255    int i;
    256
    257    printf("Converting double-precision to single-precision\n");
    258
    259    for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
    260        double input = double_numbers[i].d;
    261        uint32_t output;
    262
    263        feclearexcept(FE_ALL_EXCEPT);
    264
    265        print_double_number(i, input);
    266
    267#if defined(__arm__)
    268        asm("vcvt.f32.f64 %0, %P1" : "=w" (output) : "x" (input));
    269#else
    270        asm("fcvt %s0, %d1" : "=w" (output) : "x" (input));
    271#endif
    272
    273        print_single_number(i, output);
    274    }
    275}
    276
    277static void convert_double_to_integer(void)
    278{
    279    int i;
    280
    281    printf("Converting double-precision to integer\n");
    282
    283    for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
    284        double input = double_numbers[i].d;
    285        int64_t output;
    286
    287        feclearexcept(FE_ALL_EXCEPT);
    288
    289        print_double_number(i, input);
    290#if defined(__arm__)
    291        /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */
    292        output = input;
    293#else
    294        asm("fcvtzs %0, %d1" : "=r" (output) : "w" (input));
    295#endif
    296        print_int64(i, output);
    297    }
    298}
    299
    300/* no handy defines for these numbers */
    301uint16_t half_numbers[] = {
    302    0xffff, /* -NaN / AHP -Max */
    303    0xfcff, /* -NaN / AHP */
    304    0xfc01, /* -NaN / AHP */
    305    0xfc00, /* -Inf */
    306    0xfbff, /* -Max */
    307    0xc000, /* -2 */
    308    0xbc00, /* -1 */
    309    0x8001, /* -MIN subnormal */
    310    0x8000, /* -0 */
    311    0x0000, /* +0 */
    312    0x0001, /* MIN subnormal */
    313    0x3c00, /* 1 */
    314    0x7bff, /* Max */
    315    0x7c00, /* Inf */
    316    0x7c01, /* NaN / AHP */
    317    0x7cff, /* NaN / AHP */
    318    0x7fff, /* NaN / AHP +Max*/
    319};
    320
    321static void convert_half_to_double(void)
    322{
    323    int i;
    324
    325    printf("Converting half-precision to double-precision\n");
    326
    327    for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
    328        uint16_t input = half_numbers[i];
    329        double output;
    330
    331        feclearexcept(FE_ALL_EXCEPT);
    332
    333        print_half_number(i, input);
    334#if defined(__arm__)
    335        /* asm("vcvtb.f64.f16 %P0, %1" : "=w" (output) : "t" (input)); */
    336        output = input;
    337#else
    338        asm("fcvt %d0, %h1" : "=w" (output) : "x" (input));
    339#endif
    340        print_double_number(i, output);
    341    }
    342}
    343
    344static void convert_half_to_single(void)
    345{
    346    int i;
    347
    348    printf("Converting half-precision to single-precision\n");
    349
    350    for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
    351        uint16_t input = half_numbers[i];
    352        float output;
    353
    354        feclearexcept(FE_ALL_EXCEPT);
    355
    356        print_half_number(i, input);
    357#if defined(__arm__)
    358        asm("vcvtb.f32.f16 %0, %1" : "=w" (output) : "x" ((uint32_t)input));
    359#else
    360        asm("fcvt %s0, %h1" : "=w" (output) : "x" (input));
    361#endif
    362        print_single_number(i, output);
    363    }
    364}
    365
    366static void convert_half_to_integer(void)
    367{
    368    int i;
    369
    370    printf("Converting half-precision to integer\n");
    371
    372    for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
    373        uint16_t input = half_numbers[i];
    374        int64_t output;
    375
    376        feclearexcept(FE_ALL_EXCEPT);
    377
    378        print_half_number(i, input);
    379#if defined(__arm__)
    380        /* asm("vcvt.s32.f16 %0, %1" : "=t" (output) : "t" (input)); v8.2*/
    381        output = input;
    382#else
    383        asm("fcvt %s0, %h1" : "=w" (output) : "x" (input));
    384#endif
    385        print_int64(i, output);
    386    }
    387}
    388
    389typedef struct {
    390    int flag;
    391    char *desc;
    392} float_mapping;
    393
    394float_mapping round_flags[] = {
    395    { FE_TONEAREST, "to nearest" },
    396    { FE_UPWARD, "upwards" },
    397    { FE_DOWNWARD, "downwards" },
    398    { FE_TOWARDZERO, "to zero" }
    399};
    400
    401int main(int argc, char *argv[argc])
    402{
    403    int i;
    404
    405    printf("#### Enabling IEEE Half Precision\n");
    406
    407    for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
    408        fesetround(round_flags[i].flag);
    409        printf("### Rounding %s\n", round_flags[i].desc);
    410        convert_single_to_half();
    411        convert_single_to_double();
    412        convert_double_to_half();
    413        convert_double_to_single();
    414        convert_half_to_single();
    415        convert_half_to_double();
    416    }
    417
    418    /* convert to integer */
    419    convert_single_to_integer();
    420    convert_double_to_integer();
    421    convert_half_to_integer();
    422
    423    /* And now with ARM alternative FP16 */
    424#if defined(__arm__)
    425    /* See glibc sysdeps/arm/fpu_control.h */
    426    asm("mrc p10, 7, r1, cr1, cr0, 0\n\t"
    427        "orr r1, r1, %[flags]\n\t"
    428        "mcr p10, 7, r1, cr1, cr0, 0\n\t"
    429        : /* no output */ : [flags] "n" (1 << 26) : "r1" );
    430#else
    431    asm("mrs x1, fpcr\n\t"
    432        "orr x1, x1, %[flags]\n\t"
    433        "msr fpcr, x1\n\t"
    434        : /* no output */ : [flags] "n" (1 << 26) : "x1" );
    435#endif
    436
    437    printf("#### Enabling ARM Alternative Half Precision\n");
    438
    439    for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
    440        fesetround(round_flags[i].flag);
    441        printf("### Rounding %s\n", round_flags[i].desc);
    442        convert_single_to_half();
    443        convert_single_to_double();
    444        convert_double_to_half();
    445        convert_double_to_single();
    446        convert_half_to_single();
    447        convert_half_to_double();
    448    }
    449
    450    /* convert to integer */
    451    convert_single_to_integer();
    452    convert_double_to_integer();
    453    convert_half_to_integer();
    454
    455    return 0;
    456}