From abedea0ccb8618a3a2065662c890677fd0ca3431 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 13 Sep 2009 22:33:12 -0500 Subject: [PATCH 1/4] math.functions: loosen tests up a bit since exp(1) on FreeBSD x86/64 differs from e in the last bit --- basis/math/functions/functions-tests.factor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basis/math/functions/functions-tests.factor b/basis/math/functions/functions-tests.factor index cde1c64f94..7a6da72005 100644 --- a/basis/math/functions/functions-tests.factor +++ b/basis/math/functions/functions-tests.factor @@ -33,9 +33,9 @@ IN: math.functions.tests [ 0.0 ] [ 1.0 log ] unit-test [ 1.0 ] [ e log ] unit-test -[ t ] [ 1 exp e = ] unit-test -[ t ] [ 1.0 exp e = ] unit-test -[ 1.0 ] [ -1 exp e * ] unit-test +[ t ] [ 1 exp e 1.e-10 ~ ] unit-test +[ t ] [ 1.0 exp e 1.e-10 ~ ] unit-test +[ t ] [ -1 exp e * 1.0 1.e-10 ~ ] unit-test [ 1.0 ] [ 0 cosh ] unit-test [ 1.0 ] [ 0.0 cosh ] unit-test From a2de9d9e54575e30df2c53930dd62d6dd2688b05 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 13 Sep 2009 23:12:47 -0500 Subject: [PATCH 2/4] compiler.cfg.builder: don't run certain tests if float intrinsics are not available --- .../compiler/cfg/builder/builder-tests.factor | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/basis/compiler/cfg/builder/builder-tests.factor b/basis/compiler/cfg/builder/builder-tests.factor index 8da73a1e0e..db0dd65a83 100644 --- a/basis/compiler/cfg/builder/builder-tests.factor +++ b/basis/compiler/cfg/builder/builder-tests.factor @@ -192,14 +192,16 @@ IN: compiler.cfg.builder.tests [ [ ##unbox-alien? ] contains-insn? ] bi ] unit-test -[ f t ] [ - [ { byte-array fixnum } declare alien-cell 4 alien-float ] - [ [ ##box-alien? ] contains-insn? ] - [ [ ##box-float? ] contains-insn? ] bi -] unit-test +\ alien-float "intrinsic" word-prop [ + [ f t ] [ + [ { byte-array fixnum } declare alien-cell 4 alien-float ] + [ [ ##box-alien? ] contains-insn? ] + [ [ ##box-float? ] contains-insn? ] bi + ] unit-test -[ f t ] [ - [ { byte-array fixnum } declare alien-cell { simple-alien } declare 4 alien-float ] - [ [ ##box-alien? ] contains-insn? ] - [ [ ##box-float? ] contains-insn? ] bi -] unit-test \ No newline at end of file + [ f t ] [ + [ { byte-array fixnum } declare alien-cell { simple-alien } declare 4 alien-float ] + [ [ ##box-alien? ] contains-insn? ] + [ [ ##box-float? ] contains-insn? ] bi + ] unit-test +] when \ No newline at end of file From 05b51d27393f10c956c87c0699016175866ec418 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 13 Sep 2009 23:26:09 -0500 Subject: [PATCH 3/4] math.floats.env: modify tests to take buggy Linux/x86-64 pow() into account --- basis/math/floats/env/env-tests.factor | 27 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/basis/math/floats/env/env-tests.factor b/basis/math/floats/env/env-tests.factor index 91b699130a..c1d8913703 100644 --- a/basis/math/floats/env/env-tests.factor +++ b/basis/math/floats/env/env-tests.factor @@ -1,6 +1,7 @@ USING: kernel math math.floats.env math.floats.env.private math.functions math.libm sequences tools.test locals -compiler.units kernel.private fry compiler math.private words ; +compiler.units kernel.private fry compiler math.private words +system ; IN: math.floats.env.tests : set-default-fp-env ( -- ) @@ -29,7 +30,13 @@ set-default-fp-env [ t ] +fp-overflow+ [ 1.0e250 1.0e100 ] [ * ] test-fp-exception-compiled unit-test [ t ] +fp-underflow+ [ 1.0e-250 1.0e-100 ] [ * ] test-fp-exception-compiled unit-test [ t ] +fp-overflow+ [ 2.0 100,000.0 ] [ fpow ] test-fp-exception-compiled unit-test -[ t ] +fp-underflow+ [ 2.0 -100,000.0 ] [ fpow ] test-fp-exception-compiled unit-test + +! No underflow on Linux with this test, just inexact. Reported as an Ubuntu bug: +! https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/429113 +os linux? cpu x86.64? and [ + [ t ] +fp-underflow+ [ 2.0 -100,000.0 ] [ fpow ] test-fp-exception-compiled unit-test +] unless + [ t ] +fp-invalid-operation+ [ 0.0 0.0 ] [ /f ] test-fp-exception-compiled unit-test [ t ] +fp-invalid-operation+ [ -1.0 ] [ fsqrt ] test-fp-exception-compiled unit-test @@ -108,17 +115,17 @@ set-default-fp-env : test-traps-compiled ( traps inputs quot -- quot' ) swapd '[ @ [ _ _ with-fp-traps ] compile-call ] ; -{ +fp-zero-divide+ } [ 1.0 0.0 ] [ /f ] test-traps must-fail -{ +fp-inexact+ } [ 1.0 3.0 ] [ /f ] test-traps must-fail +{ +fp-zero-divide+ } [ 1.0 0.0 ] [ /f ] test-traps must-fail +{ +fp-inexact+ } [ 1.0 3.0 ] [ /f ] test-traps must-fail { +fp-invalid-operation+ } [ -1.0 ] [ fsqrt ] test-traps must-fail -{ +fp-overflow+ } [ 2.0 ] [ 100,000.0 ^ ] test-traps must-fail -{ +fp-underflow+ } [ 2.0 ] [ -100,000.0 ^ ] test-traps must-fail +{ +fp-overflow+ } [ 2.0 ] [ 100,000.0 ^ ] test-traps must-fail +{ +fp-underflow+ +fp-inexact+ } [ 2.0 ] [ -100,000.0 ^ ] test-traps must-fail -{ +fp-zero-divide+ } [ 1.0 0.0 ] [ /f ] test-traps-compiled must-fail -{ +fp-inexact+ } [ 1.0 3.0 ] [ /f ] test-traps-compiled must-fail +{ +fp-zero-divide+ } [ 1.0 0.0 ] [ /f ] test-traps-compiled must-fail +{ +fp-inexact+ } [ 1.0 3.0 ] [ /f ] test-traps-compiled must-fail { +fp-invalid-operation+ } [ -1.0 ] [ fsqrt ] test-traps-compiled must-fail -{ +fp-overflow+ } [ 2.0 ] [ 100,000.0 ^ ] test-traps-compiled must-fail -{ +fp-underflow+ } [ 2.0 ] [ -100,000.0 ^ ] test-traps-compiled must-fail +{ +fp-overflow+ } [ 2.0 ] [ 100,000.0 ^ ] test-traps-compiled must-fail +{ +fp-underflow+ +fp-inexact+ } [ 2.0 ] [ -100,000.0 ^ ] test-traps-compiled must-fail ! Ensure ordered comparisons raise traps :: test-comparison-quot ( word -- quot ) From fb43ae2daf20c0dc1443663e1ad8e80a0c7b05a4 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Sun, 13 Sep 2009 23:37:28 -0500 Subject: [PATCH 4/4] save the FP status out of the signal context and use it as part of the fp trap factor exception. clear the FP status before continuing after an exception --- basis/math/floats/env/ppc/ppc.factor | 2 +- vm/cpu-ppc.hpp | 18 +++++++++++ vm/cpu-x86.hpp | 18 +++++++++++ vm/errors.cpp | 7 ++-- vm/errors.hpp | 5 +-- vm/layouts.hpp | 10 ++++++ vm/mach_signal.cpp | 37 ++++++++++++++++----- vm/os-freebsd-x86.32.hpp | 27 ++++++++++++++++ vm/os-freebsd-x86.64.hpp | 21 ++++++++++++ vm/os-linux-x86.32.hpp | 14 ++++++++ vm/os-linux-x86.64.hpp | 14 ++++++++ vm/os-macosx-ppc.hpp | 45 +++++++++++++++++++++++--- vm/os-macosx-x86.32.hpp | 48 +++++++++++++++++++++++++--- vm/os-macosx-x86.64.hpp | 48 +++++++++++++++++++++++++--- vm/os-netbsd-x86.32.hpp | 3 ++ vm/os-netbsd-x86.64.hpp | 3 ++ vm/os-openbsd-x86.32.hpp | 3 ++ vm/os-openbsd-x86.64.hpp | 3 ++ vm/os-unix.cpp | 2 ++ vm/os-windows-nt.cpp | 3 ++ 20 files changed, 303 insertions(+), 28 deletions(-) diff --git a/basis/math/floats/env/ppc/ppc.factor b/basis/math/floats/env/ppc/ppc.factor index 4ce3f0512e..dd8fd88b13 100644 --- a/basis/math/floats/env/ppc/ppc.factor +++ b/basis/math/floats/env/ppc/ppc.factor @@ -34,7 +34,7 @@ M: ppc-vmx-env (set-fp-env-register) M: ppc (fp-env-registers) 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 } diff --git a/vm/cpu-ppc.hpp b/vm/cpu-ppc.hpp index 6ae2cce27d..db02a72959 100644 --- a/vm/cpu-ppc.hpp +++ b/vm/cpu-ppc.hpp @@ -62,6 +62,24 @@ inline static bool tail_call_site_p(cell return_address) 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); diff --git a/vm/cpu-x86.hpp b/vm/cpu-x86.hpp index e5852f9ad9..7054f90735 100644 --- a/vm/cpu-x86.hpp +++ b/vm/cpu-x86.hpp @@ -50,6 +50,24 @@ inline static bool tail_call_site_p(cell return_address) 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); diff --git a/vm/errors.cpp b/vm/errors.cpp index c9d2a94e56..ebe6201f72 100644 --- a/vm/errors.cpp +++ b/vm/errors.cpp @@ -7,6 +7,7 @@ namespace factor user-space */ cell signal_number; cell signal_fault_addr; +unsigned int signal_fpu_status; stack_frame *signal_callstack_top; void out_of_memory() @@ -130,9 +131,9 @@ void divide_by_zero_error() 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) @@ -158,7 +159,7 @@ void misc_signal_handler_impl() void fp_signal_handler_impl() { - fp_trap_error(signal_callstack_top); + fp_trap_error(signal_fpu_status,signal_callstack_top); } } diff --git a/vm/errors.hpp b/vm/errors.hpp index e4be61cdbf..7f3c4dcd4a 100644 --- a/vm/errors.hpp +++ b/vm/errors.hpp @@ -20,7 +20,7 @@ enum vm_error_type ERROR_RS_UNDERFLOW, ERROR_RS_OVERFLOW, ERROR_MEMORY, - ERROR_FP_TRAP, + ERROR_FP_TRAP, }; void out_of_memory(); @@ -36,7 +36,7 @@ void memory_protection_error(cell addr, stack_frame *native_stack); 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); @@ -45,6 +45,7 @@ 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(); diff --git a/vm/layouts.hpp b/vm/layouts.hpp index 7736143c50..a14c234aaa 100644 --- a/vm/layouts.hpp +++ b/vm/layouts.hpp @@ -67,6 +67,16 @@ inline static cell align8(cell a) /* 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); diff --git a/vm/mach_signal.cpp b/vm/mach_signal.cpp index facf512b77..d8eea06f0b 100644 --- a/vm/mach_signal.cpp +++ b/vm/mach_signal.cpp @@ -32,7 +32,8 @@ static void call_fault_handler( 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 @@ -56,6 +57,8 @@ static void call_fault_handler( } 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 @@ -78,14 +81,15 @@ catch_exception_raise (mach_port_t exception_port, { 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 @@ -93,9 +97,19 @@ catch_exception_raise (mach_port_t exception_port, 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 @@ -105,13 +119,20 @@ catch_exception_raise (mach_port_t exception_port, /* 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; diff --git a/vm/os-freebsd-x86.32.hpp b/vm/os-freebsd-x86.32.hpp index c276ce6174..e386532b0c 100644 --- a/vm/os-freebsd-x86.32.hpp +++ b/vm/os-freebsd-x86.32.hpp @@ -1,4 +1,5 @@ #include +#include namespace factor { @@ -9,6 +10,32 @@ inline static void *ucontext_stack_pointer(void *uap) 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) } diff --git a/vm/os-freebsd-x86.64.hpp b/vm/os-freebsd-x86.64.hpp index 6ee491f3ae..78c08447bd 100644 --- a/vm/os-freebsd-x86.64.hpp +++ b/vm/os-freebsd-x86.64.hpp @@ -1,4 +1,5 @@ #include +#include namespace factor { @@ -9,6 +10,26 @@ inline static void *ucontext_stack_pointer(void *uap) 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) } diff --git a/vm/os-linux-x86.32.hpp b/vm/os-linux-x86.32.hpp index 4ba7c77e4b..e4fd8402a8 100644 --- a/vm/os-linux-x86.32.hpp +++ b/vm/os-linux-x86.32.hpp @@ -9,6 +9,20 @@ inline static void *ucontext_stack_pointer(void *uap) 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]) diff --git a/vm/os-linux-x86.64.hpp b/vm/os-linux-x86.64.hpp index 477e21708c..42adb3c6b8 100644 --- a/vm/os-linux-x86.64.hpp +++ b/vm/os-linux-x86.64.hpp @@ -9,6 +9,20 @@ inline static void *ucontext_stack_pointer(void *uap) 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]) diff --git a/vm/os-macosx-ppc.hpp b/vm/os-macosx-ppc.hpp index 62e71bfa69..31a1e22882 100644 --- a/vm/os-macosx-ppc.hpp +++ b/vm/os-macosx-ppc.hpp @@ -18,28 +18,63 @@ Modified for Factor by Slava Pestov */ #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)); } } diff --git a/vm/os-macosx-x86.32.hpp b/vm/os-macosx-x86.32.hpp index 2275555846..01ad28df4f 100644 --- a/vm/os-macosx-x86.32.hpp +++ b/vm/os-macosx-x86.32.hpp @@ -16,28 +16,68 @@ Modified for Factor by Slava Pestov */ #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)); +} + } diff --git a/vm/os-macosx-x86.64.hpp b/vm/os-macosx-x86.64.hpp index b97eb55f26..f56ada23fd 100644 --- a/vm/os-macosx-x86.64.hpp +++ b/vm/os-macosx-x86.64.hpp @@ -16,28 +16,66 @@ Modified for Factor by Slava Pestov and Daniel Ehrenberg */ #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)); } } diff --git a/vm/os-netbsd-x86.32.hpp b/vm/os-netbsd-x86.32.hpp index ebba4f356d..f2f47ecf6c 100644 --- a/vm/os-netbsd-x86.32.hpp +++ b/vm/os-netbsd-x86.32.hpp @@ -5,4 +5,7 @@ namespace factor #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) { } + } diff --git a/vm/os-netbsd-x86.64.hpp b/vm/os-netbsd-x86.64.hpp index 1a062cc6ef..a9d52a6c2b 100644 --- a/vm/os-netbsd-x86.64.hpp +++ b/vm/os-netbsd-x86.64.hpp @@ -6,4 +6,7 @@ namespace factor #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) { } + } diff --git a/vm/os-openbsd-x86.32.hpp b/vm/os-openbsd-x86.32.hpp index 6065d96a5f..0abd019219 100644 --- a/vm/os-openbsd-x86.32.hpp +++ b/vm/os-openbsd-x86.32.hpp @@ -12,4 +12,7 @@ inline static void *openbsd_stack_pointer(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) { } + } diff --git a/vm/os-openbsd-x86.64.hpp b/vm/os-openbsd-x86.64.hpp index 7338b04e6f..9dce48ee91 100644 --- a/vm/os-openbsd-x86.64.hpp +++ b/vm/os-openbsd-x86.64.hpp @@ -12,4 +12,7 @@ inline static void *openbsd_stack_pointer(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) { } + } diff --git a/vm/os-unix.cpp b/vm/os-unix.cpp index 735c614b7a..189fca0cf7 100644 --- a/vm/os-unix.cpp +++ b/vm/os-unix.cpp @@ -136,6 +136,8 @@ void fpe_signal_handler(int signal, siginfo_t *siginfo, 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 diff --git a/vm/os-windows-nt.cpp b/vm/os-windows-nt.cpp index e2d959aace..c2b4e2af9e 100644 --- a/vm/os-windows-nt.cpp +++ b/vm/os-windows-nt.cpp @@ -34,6 +34,9 @@ FACTOR_STDCALL LONG exception_handler(PEXCEPTION_POINTERS pe) 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;