+#elif defined(GLIBC232_STYLE_UCONTEXT)
+ return &context->uc_sigmask;
+#endif
+}
+
+unsigned long
+os_context_fp_control(os_context_t *context)
+{
+ /* So this may look like nice, well behaved code. However, closer
+ inspection reveals that gpr is simply the general purpose
+ registers, and PT_FPSCR is an offset that is larger than 32
+ (the number of ppc registers), but that happens to get the
+ right answer. -- CSR, 2002-07-11 */
+#if defined(GLIBC231_STYLE_UCONTEXT)
+ return context->uc_mcontext.regs->gpr[PT_FPSCR];
+#elif defined(GLIBC232_STYLE_UCONTEXT)
+ return context->uc_mcontext.uc_regs->gregs[PT_FPSCR];
+#endif
+}
+
+void
+os_restore_fp_control(os_context_t *context)
+{
+ /* KLUDGE: mtfsf has to be run against a float register, so we
+ * construct the float we need to use as an integer, then cast
+ * a pointer to its storage to a double and load that. For
+ * this to work, control must be the same width as a double,
+ * 64 bits. And why aren't we using a union here, anyway? */
+ unsigned long long control;
+ double d;
+
+ /* FIXME: We are only preserving enabled traps and rounding
+ * mode here. Do we also want to preserve "fast mode"? */
+ control = os_context_fp_control(context) &
+ (FLOAT_TRAPS_BYTE_MASK | FLOAT_ROUNDING_MODE_MASK);
+
+ d = *((double *) &control);
+ asm volatile ("mtfsf 0xff,%0" : : "f" (d));