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
130unsigned long source64 = 0x1234567890abcdefull;
131unsigned int  source32 = 0x12345678u;
132
133/* Determine FP mode based on sdc1 behavior
134   returns 1 if FR = 1 mode is detected (assumes FRE = 0) */
135static 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
152static void fatal_error(const char* msg) {
153   fprintf(stderr, "Error: %s\n", msg);
154   exit(1);
155}
156
157static 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
237int 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
263int main() {
264   return 0;
265}
266#endif
267