M: ppc (fp-env-registers)
<ppc-fpu-env> <ppc-vmx-env> 2array ;
-CONSTANT: ppc-exception-flag-bits HEX: 3e00,0000
+CONSTANT: ppc-exception-flag-bits HEX: fff8,0000
CONSTANT: ppc-exception-flag>bit
H{
{ +fp-invalid-operation+ HEX: 2000,0000 }
return (insn & 0x1) == 0;
}
+inline static unsigned int fpu_status(unsigned int status)
+{
+ unsigned int r = 0;
+
+ if (status & 0x20000000)
+ r |= FP_TRAP_INVALID_OPERATION;
+ if (status & 0x10000000)
+ r |= FP_TRAP_OVERFLOW;
+ if (status & 0x08000000)
+ r |= FP_TRAP_UNDERFLOW;
+ if (status & 0x04000000)
+ r |= FP_TRAP_ZERO_DIVIDE;
+ if (status & 0x02000000)
+ r |= FP_TRAP_INEXACT;
+
+ return r;
+}
+
/* Defined in assembly */
VM_ASM_API void c_to_factor(cell quot);
VM_ASM_API void throw_impl(cell quot, stack_frame *rewind);
return call_site_opcode(return_address) == jmp_opcode;
}
+inline static unsigned int fpu_status(unsigned int status)
+{
+ unsigned int r = 0;
+
+ if (status & 0x01)
+ r |= FP_TRAP_INVALID_OPERATION;
+ if (status & 0x04)
+ r |= FP_TRAP_ZERO_DIVIDE;
+ if (status & 0x08)
+ r |= FP_TRAP_OVERFLOW;
+ if (status & 0x10)
+ r |= FP_TRAP_UNDERFLOW;
+ if (status & 0x20)
+ r |= FP_TRAP_INEXACT;
+
+ return r;
+}
+
/* Defined in assembly */
VM_ASM_API void c_to_factor(cell quot);
VM_ASM_API void throw_impl(cell quot, stack_frame *rewind_to);
user-space */
cell signal_number;
cell signal_fault_addr;
+unsigned int signal_fpu_status;
stack_frame *signal_callstack_top;
void out_of_memory()
general_error(ERROR_DIVIDE_BY_ZERO,F,F,NULL);
}
-void fp_trap_error(stack_frame *signal_callstack_top)
+void fp_trap_error(unsigned int fpu_status, stack_frame *signal_callstack_top)
{
- general_error(ERROR_FP_TRAP,F,F,signal_callstack_top);
+ general_error(ERROR_FP_TRAP,tag_fixnum(fpu_status),F,signal_callstack_top);
}
PRIMITIVE(call_clear)
void fp_signal_handler_impl()
{
- fp_trap_error(signal_callstack_top);
+ fp_trap_error(signal_fpu_status,signal_callstack_top);
}
}
ERROR_RS_UNDERFLOW,
ERROR_RS_OVERFLOW,
ERROR_MEMORY,
- ERROR_FP_TRAP,
+ ERROR_FP_TRAP,
};
void out_of_memory();
void signal_error(int signal, stack_frame *native_stack);
void type_error(cell type, cell tagged);
void not_implemented_error();
-void fp_trap_error();
+void fp_trap_error(unsigned int fpu_status, stack_frame *signal_callstack_top);
PRIMITIVE(call_clear);
PRIMITIVE(unimplemented);
user-space */
extern cell signal_number;
extern cell signal_fault_addr;
+extern unsigned int signal_fpu_status;
extern stack_frame *signal_callstack_top;
void memory_signal_handler_impl();
/* Not a real type, but code_block's type field can be set to this */
#define PIC_TYPE 69
+/* Constants used when floating-point trap exceptions are thrown */
+enum
+{
+ FP_TRAP_INVALID_OPERATION = 1 << 0,
+ FP_TRAP_OVERFLOW = 1 << 1,
+ FP_TRAP_UNDERFLOW = 1 << 2,
+ FP_TRAP_ZERO_DIVIDE = 1 << 3,
+ FP_TRAP_INEXACT = 1 << 4,
+};
+
inline static bool immediate_p(cell obj)
{
return (obj == F || TAG(obj) == FIXNUM_TYPE);
exception_type_t exception,
exception_data_type_t code,
MACH_EXC_STATE_TYPE *exc_state,
- MACH_THREAD_STATE_TYPE *thread_state)
+ MACH_THREAD_STATE_TYPE *thread_state,
+ MACH_FLOAT_STATE_TYPE *float_state)
{
/* There is a race condition here, but in practice an exception
delivered during stack frame setup/teardown or while transitioning
}
else if(exception == EXC_ARITHMETIC && code != MACH_EXC_INTEGER_DIV)
{
+ signal_fpu_status = fpu_status(mach_fpu_status(float_state));
+ mach_clear_fpu_status(float_state);
MACH_PROGRAM_COUNTER(thread_state) = (cell)fp_signal_handler_impl;
}
else
{
MACH_EXC_STATE_TYPE exc_state;
MACH_THREAD_STATE_TYPE thread_state;
- mach_msg_type_number_t state_count;
+ MACH_FLOAT_STATE_TYPE float_state;
+ mach_msg_type_number_t exc_state_count, thread_state_count, float_state_count;
/* Get fault information and the faulting thread's register contents..
See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html. */
- state_count = MACH_EXC_STATE_COUNT;
+ exc_state_count = MACH_EXC_STATE_COUNT;
if (thread_get_state (thread, MACH_EXC_STATE_FLAVOR,
- (natural_t *)&exc_state, &state_count)
+ (natural_t *)&exc_state, &exc_state_count)
!= KERN_SUCCESS)
{
/* The thread is supposed to be suspended while the exception
return KERN_FAILURE;
}
- state_count = MACH_THREAD_STATE_COUNT;
+ thread_state_count = MACH_THREAD_STATE_COUNT;
if (thread_get_state (thread, MACH_THREAD_STATE_FLAVOR,
- (natural_t *)&thread_state, &state_count)
+ (natural_t *)&thread_state, &thread_state_count)
+ != KERN_SUCCESS)
+ {
+ /* The thread is supposed to be suspended while the exception
+ handler is called. This shouldn't fail. */
+ return KERN_FAILURE;
+ }
+
+ float_state_count = MACH_FLOAT_STATE_COUNT;
+ if (thread_get_state (thread, MACH_FLOAT_STATE_FLAVOR,
+ (natural_t *)&float_state, &float_state_count)
!= KERN_SUCCESS)
{
/* The thread is supposed to be suspended while the exception
/* Modify registers so to have the thread resume executing the
fault handler */
- call_fault_handler(exception,code[0],&exc_state,&thread_state);
+ call_fault_handler(exception,code[0],&exc_state,&thread_state,&float_state);
/* Set the faulting thread's register contents..
See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_state.html. */
+ if (thread_set_state (thread, MACH_FLOAT_STATE_FLAVOR,
+ (natural_t *)&float_state, float_state_count)
+ != KERN_SUCCESS)
+ {
+ return KERN_FAILURE;
+ }
+
if (thread_set_state (thread, MACH_THREAD_STATE_FLAVOR,
- (natural_t *)&thread_state, state_count)
+ (natural_t *)&thread_state, thread_state_count)
!= KERN_SUCCESS)
{
return KERN_FAILURE;
#include <ucontext.h>
+#include <machine/npx.h>
namespace factor
{
return (void *)ucontext->uc_mcontext.mc_esp;
}
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ if (uap->uc_mcontext.mc_fpformat == _MC_FPFMT_387) {
+ struct save87 *x87 = (struct save87 *)(&ucontext->uc_mcontext.mc_fpstate);
+ return x87->en_sw;
+ } else if (uap->uc_mcontext.mc_fpformat == _MC_FPFMT_XMM) {
+ struct savexmm *xmm = (struct savexmm *)(&ucontext->uc_mcontext.mc_fpstate);
+ return xmm->en_sw | xmm->en_mxcsr;
+ } else
+ return 0;
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ if (uap->uc_mcontext.mc_fpformat == _MC_FPFMT_387) {
+ struct save87 *x87 = (struct save87 *)(&ucontext->uc_mcontext.mc_fpstate);
+ x87->en_sw = 0;
+ } else if (uap->uc_mcontext.mc_fpformat == _MC_FPFMT_XMM) {
+ struct savexmm *xmm = (struct savexmm *)(&ucontext->uc_mcontext.mc_fpstate);
+ xmm->en_sw = 0;
+ xmm->en_mxcsr &= 0xffffffc0;
+ }
+}
+
#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)(ucontext))->uc_mcontext.mc_eip)
}
#include <ucontext.h>
+#include <machine/fpu.h>
namespace factor
{
return (void *)ucontext->uc_mcontext.mc_rsp;
}
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ if (uap->uc_mcontext.mc_fpformat == _MC_FPFMT_XMM) {
+ struct savexmm *xmm = (struct savexmm *)(&ucontext->uc_mcontext.mc_fpstate);
+ return xmm->en_sw | xmm->en_mxcsr;
+ } else
+ return 0;
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ if (uap->uc_mcontext.mc_fpformat == _MC_FPFMT_XMM) {
+ struct savexmm *xmm = (struct savexmm *)(&ucontext->uc_mcontext.mc_fpstate);
+ xmm->en_sw = 0;
+ xmm->en_mxcsr &= 0xffffffc0;
+ }
+}
+
#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)(ucontext))->uc_mcontext.mc_rip)
}
return (void *)ucontext->uc_mcontext.gregs[7];
}
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ return ucontext->uc_mcontext.fpregs->swd
+ | ucontext->uc_mcontext.fpregs->mxcsr;
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ ucontext->uc_mcontext.fpregs->swd = 0;
+ ucontext->uc_mcontext.fpregs->mxcsr &= 0xffffffc0;
+}
+
#define UAP_PROGRAM_COUNTER(ucontext) \
(((ucontext_t *)(ucontext))->uc_mcontext.gregs[14])
return (void *)ucontext->uc_mcontext.gregs[15];
}
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ return ucontext->uc_mcontext.fpregs->swd
+ | ucontext->uc_mcontext.fpregs->mxcsr;
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ ucontext_t *ucontext = (ucontext_t *)uap;
+ ucontext->uc_mcontext.fpregs->swd = 0;
+ ucontext->uc_mcontext.fpregs->mxcsr &= 0xffffffc0;
+}
+
#define UAP_PROGRAM_COUNTER(ucontext) \
(((ucontext_t *)(ucontext))->uc_mcontext.gregs[16])
#define MACH_EXC_STATE_TYPE ppc_exception_state_t
#define MACH_EXC_STATE_FLAVOR PPC_EXCEPTION_STATE
#define MACH_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
+
#define MACH_EXC_INTEGER_DIV EXC_PPC_ZERO_DIVIDE
+
#define MACH_THREAD_STATE_TYPE ppc_thread_state_t
#define MACH_THREAD_STATE_FLAVOR PPC_THREAD_STATE
#define MACH_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
+#define MACH_FLOAT_STATE_TYPE ppc_float_state_t
+#define MACH_FLOAT_STATE_FLAVOR PPC_FLOAT_STATE
+#define MACH_FLOAT_STATE_COUNT PPC_FLOAT_STATE_COUNT
+
#if __DARWIN_UNIX03
#define MACH_EXC_STATE_FAULT(exc_state) (exc_state)->__dar
#define MACH_STACK_POINTER(thr_state) (thr_state)->__r1
#define MACH_PROGRAM_COUNTER(thr_state) (thr_state)->__srr0
- #define UAP_PROGRAM_COUNTER(ucontext) \
- MACH_PROGRAM_COUNTER(&(((ucontext_t *)(ucontext))->uc_mcontext->__ss))
+
+ #define UAP_SS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->__ss)
+ #define UAP_FS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->__fs)
+
+ #define FPSCR(float_state) (float_state)->__fpscr
#else
#define MACH_EXC_STATE_FAULT(exc_state) (exc_state)->dar
#define MACH_STACK_POINTER(thr_state) (thr_state)->r1
#define MACH_PROGRAM_COUNTER(thr_state) (thr_state)->srr0
- #define UAP_PROGRAM_COUNTER(ucontext) \
- MACH_PROGRAM_COUNTER(&(((ucontext_t *)(ucontext))->uc_mcontext->ss))
+
+ #define UAP_SS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->ss)
+ #define UAP_FS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->fs)
+
+ #define FPSCR(float_state) (float_state)->fpscr
#endif
+#define UAP_PROGRAM_COUNTER(ucontext) \
+ MACH_PROGRAM_COUNTER(UAP_SS(ucontext))
+
+inline static unsigned int mach_fpu_status(ppc_float_state_t *float_state)
+{
+ return FPSCR(float_state);
+}
+
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ return mach_fpu_status(UAP_FS(uap));
+}
+
inline static cell fix_stack_pointer(cell sp)
{
- return sp;
+ return sp;
+}
+
+inline static void mach_clear_fpu_status(ppc_float_state_t *float_state)
+{
+ FPSCR(float_state) &= 0x0007ffff;
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ mach_clear_fpu_status(UAP_FS(uap));
}
}
#define MACH_EXC_STATE_TYPE i386_exception_state_t
#define MACH_EXC_STATE_FLAVOR i386_EXCEPTION_STATE
#define MACH_EXC_STATE_COUNT i386_EXCEPTION_STATE_COUNT
+
#define MACH_EXC_INTEGER_DIV EXC_I386_DIV
+
#define MACH_THREAD_STATE_TYPE i386_thread_state_t
#define MACH_THREAD_STATE_FLAVOR i386_THREAD_STATE
#define MACH_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
+#define MACH_FLOAT_STATE_TYPE i386_float_state_t
+#define MACH_FLOAT_STATE_FLAVOR i386_FLOAT_STATE
+#define MACH_FLOAT_STATE_COUNT i386_FLOAT_STATE_COUNT
+
#if __DARWIN_UNIX03
#define MACH_EXC_STATE_FAULT(exc_state) (exc_state)->__faultvaddr
#define MACH_STACK_POINTER(thr_state) (thr_state)->__esp
#define MACH_PROGRAM_COUNTER(thr_state) (thr_state)->__eip
- #define UAP_PROGRAM_COUNTER(ucontext) \
- MACH_PROGRAM_COUNTER(&(((ucontext_t *)(ucontext))->uc_mcontext->__ss))
+
+ #define UAP_SS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->__ss)
+ #define UAP_FS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->__fs)
+
+ #define MXCSR(float_state) (float_state)->__fpu_mxcsr
+ #define X87SW(float_state) (float_state)->__fpu_fsw
#else
#define MACH_EXC_STATE_FAULT(exc_state) (exc_state)->faultvaddr
#define MACH_STACK_POINTER(thr_state) (thr_state)->esp
#define MACH_PROGRAM_COUNTER(thr_state) (thr_state)->eip
- #define UAP_PROGRAM_COUNTER(ucontext) \
- MACH_PROGRAM_COUNTER(&(((ucontext_t *)(ucontext))->uc_mcontext->ss))
+
+ #define UAP_SS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->ss)
+ #define UAP_FS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->fs)
+
+ #define MXCSR(float_state) (float_state)->fpu_mxcsr
+ #define X87SW(float_state) (float_state)->fpu_fsw
#endif
+#define UAP_PROGRAM_COUNTER(ucontext) \
+ MACH_PROGRAM_COUNTER(UAP_SS(ucontext))
+
+inline static unsigned int mach_fpu_status(i386_float_state_t *float_state)
+{
+ unsigned short x87sw;
+ memcpy(&x87sw, &X87SW(float_state), sizeof(x87sw));
+ return MXCSR(float_state) | x87sw;
+}
+
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ return mach_fpu_status(UAP_FS(uap));
+}
+
inline static cell fix_stack_pointer(cell sp)
{
return ((sp + 4) & ~15) - 4;
}
+inline static void mach_clear_fpu_status(i386_float_state_t *float_state)
+{
+ MXCSR(float_state) &= 0xffffffc0;
+ memset(&X87SW(float_state), 0, sizeof(X87SW(float_state)));
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ mach_clear_fpu_status(UAP_FS(uap));
+}
+
}
#define MACH_EXC_STATE_TYPE x86_exception_state64_t
#define MACH_EXC_STATE_FLAVOR x86_EXCEPTION_STATE64
#define MACH_EXC_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
+
#define MACH_EXC_INTEGER_DIV EXC_I386_DIV
+
#define MACH_THREAD_STATE_TYPE x86_thread_state64_t
#define MACH_THREAD_STATE_FLAVOR x86_THREAD_STATE64
#define MACH_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT
+#define MACH_FLOAT_STATE_TYPE x86_float_state64_t
+#define MACH_FLOAT_STATE_FLAVOR x86_FLOAT_STATE64
+#define MACH_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT
+
#if __DARWIN_UNIX03
#define MACH_EXC_STATE_FAULT(exc_state) (exc_state)->__faultvaddr
#define MACH_STACK_POINTER(thr_state) (thr_state)->__rsp
#define MACH_PROGRAM_COUNTER(thr_state) (thr_state)->__rip
- #define UAP_PROGRAM_COUNTER(ucontext) \
- MACH_PROGRAM_COUNTER(&(((ucontext_t *)(ucontext))->uc_mcontext->__ss))
+ #define UAP_SS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->__ss)
+ #define UAP_FS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->__fs)
+
+ #define MXCSR(float_state) (float_state)->__fpu_mxcsr
+ #define X87SW(float_state) (float_state)->__fpu_fsw
#else
#define MACH_EXC_STATE_FAULT(exc_state) (exc_state)->faultvaddr
#define MACH_STACK_POINTER(thr_state) (thr_state)->rsp
#define MACH_PROGRAM_COUNTER(thr_state) (thr_state)->rip
- #define UAP_PROGRAM_COUNTER(ucontext) \
- MACH_PROGRAM_COUNTER(&(((ucontext_t *)(ucontext))->uc_mcontext->ss))
+ #define UAP_SS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->ss)
+ #define UAP_FS(ucontext) &(((ucontext_t *)(ucontext))->uc_mcontext->fs)
+
+ #define MXCSR(float_state) (float_state)->fpu_mxcsr
+ #define X87SW(float_state) (float_state)->fpu_fsw
#endif
+#define UAP_PROGRAM_COUNTER(ucontext) \
+ MACH_PROGRAM_COUNTER(UAP_SS(ucontext))
+
+inline static unsigned int mach_fpu_status(x86_float_state64_t *float_state)
+{
+ unsigned short x87sw;
+ memcpy(&x87sw, &X87SW(float_state), sizeof(x87sw));
+ return MXCSR(float_state) | x87sw;
+}
+
+inline static unsigned int uap_fpu_status(void *uap)
+{
+ return mach_fpu_status(UAP_FS(uap));
+}
+
inline static cell fix_stack_pointer(cell sp)
{
- return ((sp + 8) & ~15) - 8;
+ return ((sp + 8) & ~15) - 8;
+}
+
+inline static void mach_clear_fpu_status(x86_float_state64_t *float_state)
+{
+ MXCSR(float_state) &= 0xffffffc0;
+ memset(&X87SW(float_state), 0, sizeof(X87SW(float_state)));
+}
+
+inline static void uap_clear_fpu_status(void *uap)
+{
+ mach_clear_fpu_status(UAP_FS(uap));
}
}
#define ucontext_stack_pointer(uap) ((void *)_UC_MACHINE_SP((ucontext_t *)uap))
+static inline unsigned int uap_fpu_status(void *uap) { return 0; }
+static inline void uap_clear_fpu_status(void *uap) { }
+
}
#define ucontext_stack_pointer(uap) \
((void *)(((ucontext_t *)(uap))->uc_mcontext.__gregs[_REG_URSP]))
+static inline unsigned int uap_fpu_status(void *uap) { return 0; }
+static inline void uap_clear_fpu_status(void *uap) { }
+
}
#define ucontext_stack_pointer openbsd_stack_pointer
#define UAP_PROGRAM_COUNTER(uap) (((struct sigcontext*)(uap))->sc_eip)
+static inline unsigned int uap_fpu_status(void *uap) { return 0; }
+static inline void uap_clear_fpu_status(void *uap) { }
+
}
#define ucontext_stack_pointer openbsd_stack_pointer
#define UAP_PROGRAM_COUNTER(uap) (((struct sigcontext*)(uap))->sc_rip)
+static inline unsigned int uap_fpu_status(void *uap) { return 0; }
+static inline void uap_clear_fpu_status(void *uap) { }
+
}
{
signal_number = signal;
signal_callstack_top = uap_stack_pointer(uap);
+ signal_fpu_status = fpu_status(uap_fpu_status(uap));
+ uap_clear_fpu_status(uap);
UAP_PROGRAM_COUNTER(uap) =
(siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
? (cell)misc_signal_handler_impl
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
+ /* XXX MxCsr is not available in CONTEXT structure on x86.32 */
+ signal_fpu_status = c->FloatSave.StatusWord;
+ c->FloatSave.StatusWord = 0;
c->EIP = (cell)fp_signal_handler_impl;
break;