Skip to content

Commit adbed20

Browse files
committed
Add floating point register preservation test for all platforms
Test verifies that callee-saved FP registers are properly preserved across stack switches by: - Performing FP computations on arrays (encourages vectorization/SIMD) - Calling stackman_switch (should preserve FP state) - Re-running same computation - Verifying bit-exact results match Uses arrays with loops to encourage compiler to: - Utilize multiple FP registers simultaneously - Potentially generate SIMD instructions (SSE/AVX/NEON/RVV) - Create maximum FP register pressure This catches ABI violations on any platform where callee-saved FP registers might not be properly preserved in assembly.
1 parent e05c3cb commit adbed20

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

tests/test.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,92 @@ void test_06()
290290

291291
}
292292

293+
/* Test floating point register preservation across stack switches.
294+
* This test verifies that callee-saved FP registers are properly
295+
* preserved across stack switches on all platforms.
296+
*
297+
* Uses arrays to encourage compiler to use multiple FP registers
298+
* and potentially SIMD instructions where available.
299+
*/
300+
typedef struct fp_test_context {
301+
void *saved_sp;
302+
int switch_done;
303+
} fp_test_context;
304+
305+
void *test_07_cb(void* context, int opcode, void *sp)
306+
{
307+
fp_test_context *c = (fp_test_context*)context;
308+
309+
if (opcode == STACKMAN_OP_SAVE) {
310+
c->saved_sp = sp;
311+
return sp; /* No stack switch */
312+
} else {
313+
c->switch_done = 1;
314+
return sp;
315+
}
316+
}
317+
318+
/* Aggressive FP computation using arrays to encourage vectorization
319+
* and use of multiple FP registers including SIMD if available
320+
*/
321+
void test_07_compute(double *input, double *output, int count)
322+
{
323+
int i;
324+
/* Multiple operations to stress FP register usage */
325+
for (i = 0; i < count; i++) {
326+
double a = input[i];
327+
double b = a * 1.234567;
328+
double c = b + 0.987654;
329+
double d = c * c;
330+
double e = d - a;
331+
output[i] = e / (a + 1.0);
332+
}
333+
}
334+
335+
void test_07(void)
336+
{
337+
fp_test_context ctx;
338+
double input[16], output1[16], output2[16];
339+
int i;
340+
341+
/* Initialize input with varying values */
342+
for (i = 0; i < 16; i++) {
343+
input[i] = (i + 1) * 3.14159 + 0.123456 * i;
344+
}
345+
346+
/* First computation - fills FP registers */
347+
test_07_compute(input, output1, 16);
348+
349+
/* Additional FP work to maximize register pressure */
350+
double sum1 = 0.0, sum2 = 0.0;
351+
for (i = 0; i < 16; i++) {
352+
sum1 += output1[i] * (i + 1);
353+
sum2 += input[i] / (i + 2);
354+
}
355+
356+
/* Stack switch - all FP registers must be preserved */
357+
memset(&ctx, 0, sizeof(ctx));
358+
stackman_switch(&test_07_cb, &ctx);
359+
assert(ctx.switch_done);
360+
361+
/* Second computation - should produce identical results */
362+
test_07_compute(input, output2, 16);
363+
364+
/* Verify outputs match exactly */
365+
for (i = 0; i < 16; i++) {
366+
assert(output1[i] == output2[i]);
367+
}
368+
369+
/* Verify accumulated sums still work */
370+
double sum3 = 0.0, sum4 = 0.0;
371+
for (i = 0; i < 16; i++) {
372+
sum3 += output2[i] * (i + 1);
373+
sum4 += input[i] / (i + 2);
374+
}
375+
assert(sum1 == sum3);
376+
assert(sum2 == sum4);
377+
}
378+
293379
int main(int argc, char*argv[])
294380
{
295381
int stack_marker = 0;
@@ -308,5 +394,7 @@ int main(int argc, char*argv[])
308394
#endif
309395
test_06();
310396
printf("test_06 ok\n");
397+
test_07();
398+
printf("test_07 ok\n");
311399
return 0;
312400
}

0 commit comments

Comments
 (0)