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/* Determine FP mode based on sdc1 behavior
17   returns 1 if FR = 1 mode is detected. */
18static int get_fp_mode(void) {
19   unsigned long long result = 0;
20   __asm__ volatile(
21      ".set push\n\t"
22      ".set noreorder\n\t"
23      ".set oddspreg\n\t"
24      "lui $t0, 0x3FF0\n\t"
25      "ldc1 $f0, %0\n\t"
26      "mtc1 $t0, $f1\n\t"
27      "sdc1 $f0, %0\n\t"
28      ".set pop\n\t"
29      : "+m"(result)
30      :
31      : "t0", "$f0", "$f1", "memory");
32
33   return (result != 0x3FF0000000000000ull);
34}
35
36static void fatal_error(const char* msg) {
37   fprintf(stderr, "Error: %s\n", msg);
38   exit(1);
39}
40
41static void test(int* fr_prctl, int* fr_detected) {
42   *fr_prctl = prctl(PR_GET_FP_MODE);
43   *fr_detected = get_fp_mode();
44
45   if (*fr_prctl < 0) {
46      fatal_error("prctl(PR_GET_FP_MODE) fails.");
47   }
48
49   printf("fr_prctl: %d, fr_detected: %d\n", *fr_prctl, *fr_detected);
50
51   if (*fr_prctl != *fr_detected) {
52      fatal_error("fr_prctl != fr_detected");
53   }
54}
55
56int main() {
57   int fr_prctl, fr_detected;
58
59   test(&fr_prctl, &fr_detected);
60
61   /* FP64 */
62   if (fr_prctl == 1) {
63
64      /* Change mode to FP32 */
65      if (prctl(PR_SET_FP_MODE, 0) != 0) {
66         fatal_error("prctl(PR_SET_FP_MODE, 0) fails.");
67      }
68
69      test(&fr_prctl, &fr_detected);
70
71      /* Change back FP mode */
72      if (prctl(PR_SET_FP_MODE, 1) != 0) {
73         fatal_error("prctl(PR_SET_FP_MODE, 1) fails.");
74      }
75
76      test(&fr_prctl, &fr_detected);
77   }
78
79   return 0;
80}
81#else
82int main() {
83   return 0;
84}
85#endif
86