Home | History | Annotate | Download | only in mips64
      1 #if defined(__mips_hard_float)
      2 
      3 #include <elf.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <sys/prctl.h>
      7 
      8 #if !defined(PR_SET_FP_MODE)
      9 #   define PR_SET_FP_MODE 45
     10 #endif
     11 
     12 #if !defined(PR_GET_FP_MODE)
     13 #   define PR_GET_FP_MODE 46
     14 #endif
     15 
     16 #define TEST_LD(instruction, source)                              \
     17 {                                                                 \
     18    unsigned int result1, result2;                                 \
     19    __asm__ volatile(                                              \
     20       ".set push\n\t"                                             \
     21       ".set noreorder\n\t"                                        \
     22       "li $t0, 0x5a5a\n\t"                                        \
     23       "mtc1 $t0, $f0\n\t"                                         \
     24       "mtc1 $t0, $f1\n\t"                                         \
     25       "move $t0, %2\n\t"                                          \
     26       instruction"\n\t"                                           \
     27       "swc1 $f0, %0\n\t"                                          \
     28       "swc1 $f1, %1\n\t"                                          \
     29       ".set pop\n\t"                                              \
     30       : "=m"(result1), "=m"(result2)                              \
     31       : "r" (&source)                                             \
     32       : "t0", "$f0", "$f1");                                      \
     33    printf(instruction" :: lo32(f1): %x, lo32(f0): %x\n",          \
     34           result2, result1);                                      \
     35 }
     36 
     37 #define _TEST_ST(instruction)                                     \
     38    __asm__ volatile(                                              \
     39       ".set push\n\t"                                             \
     40       ".set noreorder\n\t"                                        \
     41       "li $t0, 0x5a5a\n\t"                                        \
     42       "dmtc1 $t0, $f1\n\t"                                        \
     43       "move $t0, %0\n\t"                                          \
     44       "ldc1 $f0, 0($t0)\n\t"                                      \
     45       "move $t0, %1\n\t"                                          \
     46       instruction"\n\t"                                           \
     47       ".set pop\n\t"                                              \
     48       :                                                           \
     49       : "r" (&source64), "r" (&result)                            \
     50       : "t0", "$f0", "$f1", "memory")
     51 
     52 #define TEST_ST64(instruction)                                    \
     53 {                                                                 \
     54    unsigned long result;                                          \
     55    _TEST_ST(instruction);                                         \
     56    printf(instruction" :: mem: %lx\n", result);                   \
     57 }
     58 
     59 #define TEST_ST32(instruction)                                    \
     60 {                                                                 \
     61    unsigned int result;                                           \
     62    _TEST_ST(instruction);                                         \
     63    printf(instruction" :: mem: %x\n", result);                    \
     64 }
     65 
     66 #define TEST_MT(instruction)                                      \
     67 {                                                                 \
     68    unsigned int result1, result2;                                 \
     69    __asm__ volatile(                                              \
     70       ".set push\n\t"                                             \
     71       ".set noreorder\n\t"                                        \
     72       "li $t0, 0x5a5a\n\t"                                        \
     73       "mtc1 $t0, $f0\n\t"                                         \
     74       "mtc1 $t0, $f1\n\t"                                         \
     75       "ld $t0, %2\n\t"                                            \
     76       instruction"\n\t"                                           \
     77       "swc1 $f0, %0\n\t"                                          \
     78       "swc1 $f1, %1\n\t"                                          \
     79       ".set pop\n\t"                                              \
     80       : "=m"(result1), "=m"(result2)                              \
     81       : "m" (source64)                                            \
     82       : "t0", "$f0", "$f1");                                      \
     83    printf(instruction" :: lo32(f1): %x, lo32(f0): %x\n",          \
     84           result2, result1);                                      \
     85 }
     86 
     87 #define TEST_MF(instruction)                                      \
     88 {                                                                 \
     89    unsigned long result;                                          \
     90    __asm__ volatile(                                              \
     91       ".set push\n\t"                                             \
     92       ".set noreorder\n\t"                                        \
     93       "li $t0, 0x5a5a\n\t"                                        \
     94       "dmtc1 $t0, $f1\n\t"                                        \
     95       "ldc1 $f0, %1\n\t"                                          \
     96       "move $t0, $0\n\t"                                          \
     97       instruction"\n\t"                                           \
     98       "sd $t0, %0\n\t"                                            \
     99       ".set pop\n\t"                                              \
    100       : "=m" (result)                                             \
    101       : "m" (source64)                                            \
    102       : "t0", "$f0", "$f1");                                      \
    103    printf(instruction" :: t0: %lx\n", result);                    \
    104 }
    105 
    106 #define TEST_MOVE(instruction)                                    \
    107 {                                                                 \
    108    unsigned int result1, result2;                                 \
    109    __asm__ volatile(                                              \
    110       ".set push\n\t"                                             \
    111       ".set noreorder\n\t"                                        \
    112       "li $t0, 0x5a5a\n\t"                                        \
    113       "mtc1 $t0, $f0\n\t"                                         \
    114       "li $t0, 0x6b6b\n\t"                                        \
    115       "mtc1 $t0, $f1\n\t"                                         \
    116       "li $t0, 0x7c7c\n\t"                                        \
    117       "dmtc1 $t0, $f2\n\t"                                        \
    118       "ldc1 $f2, %2\n\t"                                          \
    119       instruction"\n\t"                                           \
    120       "swc1 $f0, %0\n\t"                                          \
    121       "swc1 $f1, %1\n\t"                                          \
    122       ".set pop\n\t"                                              \
    123       : "=m"(result1), "=m"(result2)                              \
    124       : "m" (source64)                                            \
    125       : "t0", "$f0", "$f1", "$f2");                               \
    126    printf(instruction" :: lo32(f1): %x, lo32(f0): %x\n",          \
    127           result2, result1);                                      \
    128 }
    129 
    130 unsigned long source64 = 0x1234567890abcdefull;
    131 unsigned int  source32 = 0x12345678u;
    132 
    133 /* Determine FP mode based on sdc1 behavior
    134    returns 1 if FR = 1 mode is detected (assumes FRE = 0) */
    135 static int get_fp_mode(void) {
    136    unsigned long result = 0;
    137    __asm__ volatile(
    138       ".set push\n\t"
    139       ".set noreorder\n\t"
    140       "lui $t0, 0x3ff0\n\t"
    141       "ldc1 $f0, %0\n\t"
    142       "mtc1 $t0, $f1\n\t"
    143       "sdc1 $f0, %0\n\t"
    144       ".set pop\n\t"
    145       : "+m"(result)
    146       :
    147       : "t0", "$f0", "$f1", "memory");
    148 
    149    return (result != 0x3ff0000000000000ull);
    150 }
    151 
    152 static void fatal_error(const char* msg) {
    153    fprintf(stderr, "Error: %s\n", msg);
    154    exit(1);
    155 }
    156 
    157 static void test(int* fr_prctl, int* fr_detected) {
    158 
    159    *fr_prctl = prctl(PR_GET_FP_MODE);
    160    *fr_detected = get_fp_mode();
    161 
    162    if (*fr_prctl < 0) {
    163       fatal_error("prctl(PR_GET_FP_MODE) fails.");
    164    }
    165 
    166    printf("fr_prctl: %d, fr_detected: %d\n", *fr_prctl, *fr_detected);
    167 
    168    if (*fr_prctl != *fr_detected) {
    169       fatal_error("fr_prctl != fr_detected");
    170    }
    171 
    172    TEST_LD("lwc1 $f0, 0($t0)", source32);
    173    TEST_LD("lwc1 $f1, 0($t0)", source32);
    174 
    175    TEST_LD("lwxc1 $f0, $0($t0)", source32);
    176    TEST_LD("lwxc1 $f1, $0($t0)", source32);
    177 
    178    TEST_LD("ldc1 $f0, 0($t0)", source64);
    179    TEST_LD("ldc1 $f1, 0($t0)", source64);
    180 
    181    TEST_LD("ldxc1 $f0, $0($t0)", source64);
    182    TEST_LD("ldxc1 $f1, $0($t0)", source64);
    183 
    184    TEST_ST32("swc1 $f0, 0($t0)");
    185    TEST_ST32("swc1 $f1, 0($t0)");
    186 
    187    TEST_ST32("swxc1 $f0, $0($t0)");
    188    TEST_ST32("swxc1 $f1, $0($t0)");
    189 
    190    TEST_ST64("sdc1 $f0, 0($t0)");
    191    TEST_ST64("sdc1 $f1, 0($t0)");
    192 
    193    TEST_ST64("sdxc1 $f0, $0($t0)");
    194    TEST_ST64("sdxc1 $f1, $0($t0)");
    195 
    196    TEST_MT("mtc1 $t0, $f0");
    197    TEST_MT("mtc1 $t0, $f1");
    198 
    199    TEST_MT("dmtc1 $t0, $f0");
    200    TEST_MT("dmtc1 $t0, $f1");
    201 
    202    TEST_MF("mfc1 $t0, $f0");
    203    TEST_MF("mfc1 $t0, $f1");
    204 
    205    TEST_MF("dmfc1 $t0, $f0");
    206    TEST_MF("dmfc1 $t0, $f1");
    207 
    208    TEST_MOVE("movn.s $f0, $f2, $t0");
    209    TEST_MOVE("movn.s $f0, $f1, $t0");
    210    TEST_MOVE("movn.s $f1, $f2, $t0");
    211    TEST_MOVE("movn.s $f0, $f2, $0");
    212    TEST_MOVE("movn.s $f0, $f1, $0");
    213    TEST_MOVE("movn.s $f1, $f2, $0");
    214 
    215    TEST_MOVE("movn.d $f0, $f2, $t0");
    216    TEST_MOVE("movn.d $f0, $f1, $t0");
    217    TEST_MOVE("movn.d $f1, $f2, $t0");
    218    TEST_MOVE("movn.d $f0, $f2, $0");
    219    TEST_MOVE("movn.d $f0, $f1, $0");
    220    TEST_MOVE("movn.d $f1, $f2, $0");
    221 
    222    TEST_MOVE("movz.s $f0, $f2, $t0");
    223    TEST_MOVE("movz.s $f0, $f1, $t0");
    224    TEST_MOVE("movz.s $f1, $f2, $t0");
    225    TEST_MOVE("movz.s $f0, $f2, $0");
    226    TEST_MOVE("movz.s $f0, $f1, $0");
    227    TEST_MOVE("movz.s $f1, $f2, $0");
    228 
    229    TEST_MOVE("movz.d $f0, $f2, $t0");
    230    TEST_MOVE("movz.d $f0, $f1, $t0");
    231    TEST_MOVE("movz.d $f1, $f2, $t0");
    232    TEST_MOVE("movz.d $f0, $f2, $0");
    233    TEST_MOVE("movz.d $f0, $f1, $0");
    234    TEST_MOVE("movz.d $f1, $f2, $0");
    235 }
    236 
    237 int main() {
    238    int fr_prctl, fr_detected;
    239 
    240    test(&fr_prctl, &fr_detected);
    241 
    242    /* FP64 */
    243    if (fr_prctl == 1) {
    244 
    245       /* Change mode to FP32 */
    246       if (prctl(PR_SET_FP_MODE, 0) != 0) {
    247          fatal_error("prctl(PR_SET_FP_MODE, 0) fails.");
    248       }
    249 
    250       test(&fr_prctl, &fr_detected);
    251 
    252       /* Change back FP mode */
    253       if (prctl(PR_SET_FP_MODE, 1) != 0) {
    254          fatal_error("prctl(PR_SET_FP_MODE, 1) fails.");
    255       }
    256 
    257       test(&fr_prctl, &fr_detected);
    258    }
    259 
    260    return 0;
    261 }
    262 #else
    263 int main() {
    264    return 0;
    265 }
    266 #endif
    267