[PATCH 4/4] sparc: Optimize non-deferred FP save/restore

Sebastian Huber sebastian.huber at embedded-brains.de
Fri May 29 13:54:30 UTC 2015


Update #2270.
---
 cpukit/score/cpu/sparc/cpu.c             | 16 ++++++++++++
 cpukit/score/cpu/sparc/cpu_asm.S         | 44 ++++++++++++++++++++++++++++++++
 cpukit/score/cpu/sparc/rtems/score/cpu.h | 22 ++++++++++++++--
 3 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c
index bab0040..b2f67c4 100644
--- a/cpukit/score/cpu/sparc/cpu.c
+++ b/cpukit/score/cpu/sparc/cpu.c
@@ -134,6 +134,10 @@ void _CPU_Initialize(void)
 #if (SPARC_HAS_FPU == 1)
   Context_Control_fp *pointer;
   uint32_t            psr;
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+  Per_CPU_Control    *cpu_self;
+  uint32_t            isr_dispatch_disable;
+#endif
 
   sparc_get_psr( psr );
   psr |= SPARC_PSR_EF_MASK;
@@ -146,7 +150,19 @@ void _CPU_Initialize(void)
    */
 
   pointer = &_CPU_Null_fp_context;
+
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+  cpu_self = _Per_CPU_Get();
+  isr_dispatch_disable = cpu_self->cpu_per_cpu.isr_dispatch_disable;
+  cpu_self->cpu_per_cpu.isr_dispatch_disable = 1;
+  pointer->is_valid = 1;
+#endif
+
   _CPU_Context_save_fp( &pointer );
+
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+  cpu_self->cpu_per_cpu.isr_dispatch_disable = isr_dispatch_disable;
+#endif
 #endif
 }
 
diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S
index 3fa0532..fd63f19 100644
--- a/cpukit/score/cpu/sparc/cpu_asm.S
+++ b/cpukit/score/cpu/sparc/cpu_asm.S
@@ -44,7 +44,26 @@
         .align 4
         PUBLIC(_CPU_Context_save_fp)
 SYM(_CPU_Context_save_fp):
+#if CPU_USE_DEFERRED_FP_SWITCH == TRUE
         ld      [%o0], %o1
+#else
+        /*
+         * On SMP configurations we cannot use the deferred floating point
+         * switch.  Save the FP context only in case we have an interrupted
+         * thread (indicated by a non-zero per-CPU ISR dispatch disable flag).
+         * This works since the complete floating point context is volatile on
+         * SPARC.
+         */
+        ld      [%g6 + SPARC_PER_CPU_ISR_DISPATCH_DISABLE], %o2
+        cmp     %o2, 0
+        bne     do_save_fp
+         ld     [%o0], %o1
+        jmp    %o7 + 8
+         nop
+
+do_save_fp:
+#endif
+
         std     %f0, [%o1 + FO_F1_OFFSET]
         std     %f2, [%o1 + F2_F3_OFFSET]
         std     %f4, [%o1 + F4_F5_OFFSET]
@@ -61,6 +80,15 @@ SYM(_CPU_Context_save_fp):
         std     %f26, [%o1 + F26_F27_OFFSET]
         std     %f28, [%o1 + F28_F29_OFFSET]
         std     %f30, [%o1 + F3O_F31_OFFSET]
+
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+        /*
+         * Set the is valid flag of the floating point context to true.  It is
+         * store here to store the fields in sequence.
+         */
+        st      %o2, [%o1 + SPARC_FP_CONTEXT_IS_VALID_OFFSET]
+#endif
+
         jmp     %o7 + 8
          st     %fsr, [%o1 + FSR_OFFSET]
 
@@ -81,6 +109,22 @@ SYM(_CPU_Context_save_fp):
         PUBLIC(_CPU_Context_restore_fp)
 SYM(_CPU_Context_restore_fp):
         ld      [%o0], %o1
+
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+        /*
+         * Check if we have a valid floating point context.  Clear the is valid
+         * flag.  Restore the floating point context if necessary.
+         */
+        ld      [%o1 + SPARC_FP_CONTEXT_IS_VALID_OFFSET], %o2
+        cmp     %o2, 0
+        bne     do_restore_fp
+         st     %g0, [%o1 + SPARC_FP_CONTEXT_IS_VALID_OFFSET]
+        jmp     %o7 + 8
+         nop
+
+do_restore_fp:
+#endif
+
         ldd     [%o1 + FO_F1_OFFSET], %f0
         ldd     [%o1 + F2_F3_OFFSET], %f2
         ldd     [%o1 + F4_F5_OFFSET], %f4
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index 02891b0..e51a4ab 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -609,6 +609,10 @@ typedef struct {
   double      f28_f29;
   /** This will contain the contents of the f30 and f31 register. */
   double      f30_f31;
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+  /** Indicates if the context is valid. */
+  uint32_t    is_valid;
+#endif
   /** This will contain the contents of the floating point status register. */
   uint32_t    fsr;
 } Context_Control_fp;
@@ -651,11 +655,25 @@ typedef struct {
 #define F28_F29_OFFSET   0x70
 /** This macro defines an offset into the FPU context for use in assembly. */
 #define F3O_F31_OFFSET   0x78
+
+#if CPU_USE_DEFERRED_FP_SWITCH == FALSE
+  /** This macro defines an offset into the FPU context for use in assembly. */
+  #define SPARC_FP_CONTEXT_IS_VALID_OFFSET 0x80
+#endif
+
 /** This macro defines an offset into the FPU context for use in assembly. */
-#define FSR_OFFSET       0x80
+#if CPU_USE_DEFERRED_FP_SWITCH == TRUE
+  #define FSR_OFFSET 0x80
+#else
+  #define FSR_OFFSET 0x84
+#endif
 
 /** This defines the size of the FPU context area for use in assembly. */
-#define CONTEXT_CONTROL_FP_SIZE 0x84
+#if CPU_USE_DEFERRED_FP_SWITCH == TRUE
+  #define CONTEXT_CONTROL_FP_SIZE 0x84
+#else
+  #define CONTEXT_CONTROL_FP_SIZE 0x88
+#endif
 
 #ifndef ASM
 
-- 
1.8.4.5




More information about the devel mailing list