Hi, I think there are two problems in lazy floating point switching: 1. Missed restoring of PSR after invoked CMP commands in syscall_lazy_fp_switch procedure. 2. Mistaken clearing of PSR[EF] bit in _ISR_Handler
The following is a piece of real code, generated by gcc-9.1.0 from ordinary C++ code containing cycle for(;;) with floating point operations inside ... 4f102d84: b1 a6 09 58 fmuld %f24, %f24, %f24 4f102d88: 95 a5 88 5c faddd %f22, %f28, %f10 4f102d8c: 92 02 61 08 add %o1, 0x108, %o1 4f102d90: 91 a2 08 da fsubd %f8, %f26, %f8 4f102d94: 80 a0 80 09 cmp %g2, %o1 <---- (1) 4f102d98: 95 a2 88 58 faddd %f10, %f24, %f10 4f102d9c: 91 a2 09 54 fmuld %f8, %f20, %f8 4f102da0: 95 a0 05 4a fsqrtd %f10, %f10 4f102da4: d5 3b bf f8 std %f10, [ %sp + -8 ] 4f102da8: 01 00 00 00 nop 4f102dac: 91 a2 08 4a faddd %f8, %f10, %f8 4f102db0: ad a4 89 c8 fdivd %f18, %f8, %f22 4f102db4: ed 3b bf f8 std %f22, [ %sp + -8 ] 4f102db8: 01 00 00 00 nop 4f102dbc: d1 3a 7f e0 std %f8, [ %o1 + -32 ] 4f102dc0: d1 18 40 00 ldd [ %g1 ], %f8 4f102dc4: 91 a2 08 ce fsubd %f8, %f14, %f8 4f102dc8: 91 a2 09 56 fmuld %f8, %f22, %f8 <---- (2) 4f102dcc: d1 3a 7f c8 std %f8, [ %o1 + -56 ] <---- (3) 4f102dd0: d5 18 60 08 ldd [ %g1 + 8 ], %f10 4f102dd4: 99 a2 88 cc fsubd %f10, %f12, %f12 4f102dd8: 99 a3 09 56 fmuld %f12, %f22, %f12 4f102ddc: d9 3a 7f d0 std %f12, [ %o1 + -48 ] 4f102de0: d1 18 60 10 ldd [ %g1 + 0x10 ], %f8 4f102de4: a1 a2 08 d0 fsubd %f8, %f16, %f16 4f102de8: a1 a4 09 56 fmuld %f16, %f22, %f16 4f102dec: e1 3a 7f d8 std %f16, [ %o1 + -40 ] 4f102df0: 12 bf ff d8 bne 4f102d50 <---- (4) 4f102df4: 01 00 00 00 nop ... (1) CMP instruction is invoked and sets icc field properly. (2) Asynchronous interrupt occurs, _ISR_Handler clear PSR[EF] bit (3) First floating point instruction after interrupt causes the lazy fp switch procedure which uses CMP instructions inside and does not restores PSR on return. (4) "dirty" PSR[icc] is checked and our program makes wrong branch, so we get undefined program behavior. The above is applied at least to gcc versions 7.4.0 and 9.1.0. With gcc 4.4.7 this situation does not appear because it generates a bit different code where there are no fp operations between cmp and branch instructions (even more - nearly all cmp are followed by branches immediately). The second problem is - why PSR[EF] bit gets cleared after return from interrupt although interrupted task was a floating point task? The second patch about this - EF bit is leared in delayed slot regardless of branch is done or not. These two patches resolve described problems and I hope they both are correct. Any comments are welcome. Maksim E. Kozlov (2): sparc: Fix missed restoring of PSR in syscall_lazy_fp_switch sparc: Fix mistakenly cleared PSR[EF] bit. cpukit/score/cpu/sparc/cpu_asm.S | 3 ++- cpukit/score/cpu/sparc/syscall.S | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) -- 2.17.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel