213 lines
6.2 KiB
Factor
213 lines
6.2 KiB
Factor
! (c)Joe Groff bsd license
|
|
USING: alien.syntax assocs biassocs combinators continuations
|
|
generalizations kernel literals locals math math.bitwise
|
|
sequences system ;
|
|
IN: math.floats.env
|
|
|
|
|
|
SINGLETONS:
|
|
+fp-invalid-operation+
|
|
+fp-overflow+
|
|
+fp-underflow+
|
|
+fp-zero-divide+
|
|
+fp-inexact+ ;
|
|
|
|
UNION: fp-exception
|
|
+fp-invalid-operation+
|
|
+fp-overflow+
|
|
+fp-underflow+
|
|
+fp-zero-divide+
|
|
+fp-inexact+ ;
|
|
|
|
SINGLETONS:
|
|
+round-nearest+
|
|
+round-down+
|
|
+round-up+
|
|
+round-zero+ ;
|
|
|
|
UNION: fp-rounding-mode
|
|
+round-nearest+
|
|
+round-down+
|
|
+round-up+
|
|
+round-zero+ ;
|
|
|
|
SINGLETONS:
|
|
+denormal-keep+
|
|
+denormal-flush+ ;
|
|
|
|
UNION: fp-denormal-mode
|
|
+denormal-keep+
|
|
+denormal-flush+ ;
|
|
|
|
<PRIVATE
|
|
|
|
! These functions are provided in the VM; see cpu-*.S
|
|
FUNCTION: uint get_fp_control_register ( ) ;
|
|
FUNCTION: void set_fp_control_register ( uint reg ) ;
|
|
|
|
HOOK: exception-flag-bits cpu ( -- bits )
|
|
HOOK: exception-flag>bit cpu ( -- assoc )
|
|
HOOK: fp-traps-bits cpu ( -- bits )
|
|
HOOK: fp-traps>bit cpu ( -- assoc )
|
|
HOOK: >fp-traps cpu ( mask -- enable )
|
|
HOOK: rounding-mode-bits cpu ( -- bits )
|
|
HOOK: rounding-mode>bit cpu ( -- assoc )
|
|
HOOK: denormal-mode-bits cpu ( -- bits )
|
|
|
|
M: x86 exception-flag-bits HEX: 3f ;
|
|
M: x86 exception-flag>bit
|
|
H{
|
|
{ +fp-invalid-operation+ HEX: 01 }
|
|
{ +fp-overflow+ HEX: 08 }
|
|
{ +fp-underflow+ HEX: 10 }
|
|
{ +fp-zero-divide+ HEX: 04 }
|
|
{ +fp-inexact+ HEX: 20 }
|
|
} ;
|
|
|
|
M: x86 fp-traps-bits HEX: 1f80 ;
|
|
M: x86 fp-traps>bit
|
|
H{
|
|
{ +fp-invalid-operation+ HEX: 0080 }
|
|
{ +fp-overflow+ HEX: 0400 }
|
|
{ +fp-underflow+ HEX: 0800 }
|
|
{ +fp-zero-divide+ HEX: 0200 }
|
|
{ +fp-inexact+ HEX: 1000 }
|
|
} ;
|
|
|
|
M: x86 >fp-traps bitnot ;
|
|
|
|
M: x86 rounding-mode-bits HEX: 6000 ;
|
|
M: x86 rounding-mode>bit
|
|
$[ H{
|
|
{ +round-nearest+ HEX: 0000 }
|
|
{ +round-down+ HEX: 2000 }
|
|
{ +round-up+ HEX: 4000 }
|
|
{ +round-zero+ HEX: 6000 }
|
|
} >biassoc ] ;
|
|
|
|
M: x86 denormal-mode-bits HEX: 8040 ;
|
|
|
|
M: ppc exception-flag-bits HEX: 3e00,0000 ;
|
|
M: ppc exception-flag>bit
|
|
H{
|
|
{ +fp-invalid-operation+ HEX: 2000,0000 }
|
|
{ +fp-overflow+ HEX: 1000,0000 }
|
|
{ +fp-underflow+ HEX: 0800,0000 }
|
|
{ +fp-zero-divide+ HEX: 0400,0000 }
|
|
{ +fp-inexact+ HEX: 0200,0000 }
|
|
} ;
|
|
|
|
M: ppc fp-traps-bits HEX: f80 ;
|
|
M: ppc fp-traps>bit
|
|
H{
|
|
{ +fp-invalid-operation+ HEX: 8000 }
|
|
{ +fp-overflow+ HEX: 4000 }
|
|
{ +fp-underflow+ HEX: 2000 }
|
|
{ +fp-zero-divide+ HEX: 1000 }
|
|
{ +fp-inexact+ HEX: 0800 }
|
|
} ;
|
|
|
|
M: ppc >fp-traps ;
|
|
|
|
M: ppc rounding-mode-bits HEX: 3 ;
|
|
M: ppc rounding-mode>bit
|
|
$[ H{
|
|
{ +round-nearest+ HEX: 0 }
|
|
{ +round-zero+ HEX: 1 }
|
|
{ +round-up+ HEX: 2 }
|
|
{ +round-down+ HEX: 3 }
|
|
} >biassoc ] ;
|
|
|
|
M: ppc denormal-mode-bits HEX: 4 ;
|
|
|
|
:: mask> ( bits assoc -- symbols )
|
|
assoc [| k v | bits v mask zero? not ] assoc-filter keys ;
|
|
: >mask ( symbols assoc -- bits )
|
|
over empty?
|
|
[ 2drop 0 ]
|
|
[ [ at ] curry [ bitor ] map-reduce ] if ;
|
|
|
|
: remask ( x new-bits mask-bits -- x' )
|
|
[ unmask ] [ mask ] bi-curry bi* bitor ; inline
|
|
|
|
: (get-exception-flags) ( register -- exceptions )
|
|
exception-flag>bit mask> ; inline
|
|
: (set-exception-flags) ( register exceptions -- register' )
|
|
exception-flag>bit >mask exception-flag-bits remask ; inline
|
|
|
|
: (get-fp-traps) ( register -- exceptions )
|
|
>fp-traps fp-traps>bit mask> ; inline
|
|
: (set-fp-traps) ( register exceptions -- register' )
|
|
fp-traps>bit >mask >fp-traps fp-traps-bits remask ; inline
|
|
|
|
: (get-rounding-mode) ( register -- mode )
|
|
rounding-mode-bits mask rounding-mode>bit value-at ; inline
|
|
: (set-rounding-mode) ( register mode -- register' )
|
|
rounding-mode>bit at rounding-mode-bits remask ; inline
|
|
|
|
: (get-denormal-mode) ( register -- mode )
|
|
denormal-mode-bits mask zero? +denormal-keep+ +denormal-flush+ ? ; inline
|
|
: (set-denormal-mode) ( register ? -- register' )
|
|
{
|
|
{ +denormal-keep+ [ denormal-mode-bits unmask ] }
|
|
{ +denormal-flush+ [ denormal-mode-bits bitor ] }
|
|
} case ; inline
|
|
|
|
: change-control-register ( quot -- )
|
|
get_fp_control_register swap call set_fp_control_register ; inline
|
|
|
|
: set-fp-traps ( exceptions -- ) [ (set-fp-traps) ] curry change-control-register ;
|
|
: set-rounding-mode ( exceptions -- ) [ (set-rounding-mode) ] curry change-control-register ;
|
|
: set-denormal-mode ( mode -- ) [ (set-denormal-mode) ] curry change-control-register ;
|
|
|
|
: get-fp-env ( -- exception-flags fp-traps rounding-mode denormals? )
|
|
get_fp_control_register {
|
|
[ (get-exception-flags) ]
|
|
[ (get-fp-traps) ]
|
|
[ (get-rounding-mode) ]
|
|
[ (get-denormal-mode) ]
|
|
} cleave ;
|
|
|
|
: set-fp-env ( exception-flags fp-traps rounding-mode denormal-mode -- )
|
|
[
|
|
{
|
|
[ [ (set-exception-flags) ] when* ]
|
|
[ [ (set-fp-traps) ] when* ]
|
|
[ [ (set-rounding-mode) ] when* ]
|
|
[ [ (set-denormal-mode) ] when* ]
|
|
} spread
|
|
] 4 ncurry change-control-register ;
|
|
|
|
PRIVATE>
|
|
|
|
: fp-exception-flags ( -- exceptions ) get_fp_control_register (get-exception-flags) ;
|
|
: set-fp-exception-flags ( exceptions -- ) [ (set-exception-flags) ] curry change-control-register ;
|
|
: clear-fp-exception-flags ( -- ) { } set-fp-exception-flags ; inline
|
|
|
|
: collect-fp-exceptions ( quot -- exceptions )
|
|
clear-fp-exception-flags call fp-exception-flags ; inline
|
|
|
|
: denormal-mode ( -- mode ) get_fp_control_register (get-denormal-mode) ;
|
|
|
|
:: with-denormal-mode ( mode quot -- )
|
|
denormal-mode :> orig
|
|
mode set-denormal-mode
|
|
quot [ orig set-denormal-mode ] [ ] cleanup ; inline
|
|
|
|
: rounding-mode ( -- mode ) get_fp_control_register (get-rounding-mode) ;
|
|
|
|
:: with-rounding-mode ( mode quot -- )
|
|
rounding-mode :> orig
|
|
mode set-rounding-mode
|
|
quot [ orig set-rounding-mode ] [ ] cleanup ; inline
|
|
|
|
: fp-traps ( -- exceptions ) get_fp_control_register (get-fp-traps) ;
|
|
|
|
:: with-fp-traps ( exceptions quot -- )
|
|
fp-traps :> orig
|
|
exceptions set-fp-traps
|
|
quot [ orig set-fp-traps ] [ ] cleanup ; inline
|
|
|
|
: without-fp-traps ( quot -- )
|
|
{ } swap with-fp-traps ; inline
|