factor out x86 and ppc backends for math.floats.env; update both x87 and SSE state on x86

db4
Joe Groff 2009-09-08 15:29:29 -05:00
parent e3509e7f11
commit 0ec342a1c5
8 changed files with 303 additions and 137 deletions

View File

@ -59,7 +59,8 @@ HELP: fp-exception-flags
HELP: set-fp-exception-flags
{ $values { "exceptions" "a sequence of " { $link fp-exception } " symbols" } }
{ $description "Replaces the set of floating-point exception flags with the set specified in " { $snippet "exceptions" } "." } ;
{ $description "Replaces the set of floating-point exception flags with the set specified in " { $snippet "exceptions" } "." }
{ $notes "On Intel platforms, the legacy x87 floating-point unit does not support setting exception flags, so this word only clears the x87 exception flags. However, the SSE unit's flags are set as expected." } ;
HELP: clear-fp-exception-flags
{ $description "Clears all of the floating-point exception flags." } ;
@ -121,7 +122,6 @@ $nl
{ $subsection with-rounding-mode }
{ $subsection denormal-mode }
{ $subsection with-denormal-mode }
{ $notes
"On x86, the above words only modify the SSE unit's state (in particular, the MXCSR register); the x87 unit is unaffected. On PowerPC, the above words only modify the scalar FPU's state (in FPSCR); the AltiVec unit is unaffected." } ;
{ $notes "On PowerPC, the above words only modify the scalar FPU's state (in FPSCR); the AltiVec unit is currently unaffected." } ;
ABOUT: "math.floats.env"

View File

@ -1,7 +1,13 @@
USING: kernel math math.floats.env math.functions math.libm
sets tools.test ;
USING: kernel math math.floats.env math.floats.env.private
math.functions math.libm sets tools.test ;
IN: math.floats.env.tests
: set-default-fp-env ( -- )
{ } { } +round-nearest+ +denormal-keep+ set-fp-env ;
! In case the tests screw up the FP env because of bugs in math.floats.env
set-default-fp-env
[ t ] [
[ 1.0 0.0 / drop ] collect-fp-exceptions
{ +fp-zero-divide+ } set=
@ -129,3 +135,7 @@ IN: math.floats.env.tests
! Ensure traps get cleared
[ 1/0. ] [ 1.0 0.0 /f ] unit-test
! In case the tests screw up the FP env because of bugs in math.floats.env
set-default-fp-env

View File

@ -1,10 +1,9 @@
! (c)Joe Groff bsd license
USING: alien.syntax assocs biassocs combinators continuations
generalizations kernel literals locals math math.bitwise
sequences system ;
sequences system vocabs.loader ;
IN: math.floats.env
SINGLETONS:
+fp-invalid-operation+
+fp-overflow+
@ -41,84 +40,9 @@ UNION: fp-denormal-mode
<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: (fp-env-registers) cpu ( -- registers )
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 ;
: fp-env-register ( -- register ) (fp-env-registers) first ;
:: mask> ( bits assoc -- symbols )
assoc [| k v | bits v mask zero? not ] assoc-filter keys ;
@ -130,38 +54,29 @@ M: ppc denormal-mode-bits HEX: 4 ;
: 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
GENERIC: (set-fp-env-register) ( fp-env -- )
: (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
GENERIC: (get-exception-flags) ( fp-env -- exceptions )
GENERIC# (set-exception-flags) 1 ( fp-env exceptions -- fp-env )
: (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
GENERIC: (get-fp-traps) ( fp-env -- exceptions )
GENERIC# (set-fp-traps) 1 ( fp-env exceptions -- fp-env )
: (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
GENERIC: (get-rounding-mode) ( fp-env -- mode )
GENERIC# (set-rounding-mode) 1 ( fp-env mode -- fp-env )
: change-control-register ( quot -- )
get_fp_control_register swap call set_fp_control_register ; inline
GENERIC: (get-denormal-mode) ( fp-env -- mode )
GENERIC# (set-denormal-mode) 1 ( fp-env mode -- fp-env )
: 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 ;
: change-fp-env-registers ( quot -- )
(fp-env-registers) swap [ (set-fp-env-register) ] compose each ; inline
: get-fp-env ( -- exception-flags fp-traps rounding-mode denormals? )
get_fp_control_register {
: set-fp-traps ( exceptions -- ) [ (set-fp-traps) ] curry change-fp-env-registers ;
: set-rounding-mode ( mode -- ) [ (set-rounding-mode) ] curry change-fp-env-registers ;
: set-denormal-mode ( mode -- ) [ (set-denormal-mode) ] curry change-fp-env-registers ;
: get-fp-env ( -- exception-flags fp-traps rounding-mode denormal-mode )
fp-env-register {
[ (get-exception-flags) ]
[ (get-fp-traps) ]
[ (get-rounding-mode) ]
@ -176,32 +91,32 @@ M: ppc denormal-mode-bits HEX: 4 ;
[ [ (set-rounding-mode) ] when* ]
[ [ (set-denormal-mode) ] when* ]
} spread
] 4 ncurry change-control-register ;
] 4 ncurry change-fp-env-registers ;
PRIVATE>
: fp-exception-flags ( -- exceptions ) get_fp_control_register (get-exception-flags) ;
: set-fp-exception-flags ( exceptions -- ) [ (set-exception-flags) ] curry change-control-register ;
: fp-exception-flags ( -- exceptions ) fp-env-register (get-exception-flags) ;
: set-fp-exception-flags ( exceptions -- ) [ (set-exception-flags) ] curry change-fp-env-registers ;
: 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) ;
: denormal-mode ( -- mode ) fp-env-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) ;
: rounding-mode ( -- mode ) fp-env-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) ;
: fp-traps ( -- exceptions ) fp-env-register (get-fp-traps) ;
:: with-fp-traps ( exceptions quot -- )
fp-traps :> orig
@ -210,3 +125,10 @@ PRIVATE>
: without-fp-traps ( quot -- )
{ } swap with-fp-traps ; inline
<< {
{ [ cpu x86? ] [ "math.floats.env.x86" require ] }
{ [ cpu ppc? ] [ "math.floats.env.ppc" require ] }
[ "CPU architecture unsupported by math.floats.env" throw ]
} cond >>

79
basis/math/floats/env/ppc/ppc.factor vendored Normal file
View File

@ -0,0 +1,79 @@
USING: accessors alien.syntax arrays assocs biassocs
classes.struct combinators kernel literals math math.bitwise
math.floats.env math.floats.env.private system ;
IN: math.floats.env.ppc
STRUCT: ppc-fpu-env
{ padding uint }
{ fpcsr uint } ;
! defined in the vm, cpu-ppc*.S
FUNCTION: void get_ppc_fpu_env ( ppc-fpu-env* env ) ;
FUNCTION: void set_ppc_fpu_env ( ppc-fpu-env* env ) ;
: <ppc-fpu-env> ( -- ppc-fpu-env )
ppc-fpu-env (struct)
[ get_ppc_fpu_env ] keep ;
M: ppc-fpu-env (set-fp-env-register)
set_ppc_fpu_env ;
M: ppc (fp-env-registers)
<ppc-fpu-env> 1array ;
CONSTANT: ppc-exception-flag-bits HEX: 3e00,0000
CONSTANT: 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 }
}
CONSTANT: ppc-fp-traps-bits HEX: f80
CONSTANT: 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 }
}
CONSTANT: ppc-rounding-mode-bits HEX: 3
CONSTANT: ppc-rounding-mode>bit
$[ H{
{ +round-nearest+ HEX: 0 }
{ +round-zero+ HEX: 1 }
{ +round-up+ HEX: 2 }
{ +round-down+ HEX: 3 }
} >biassoc ]
CONSTANT: ppc-denormal-mode-bits HEX: 4
M: ppc-fpu-env (get-exception-flags) ( register -- exceptions )
fpcsr>> ppc-exception-flag>bit mask> ; inline
M: ppc-fpu-env (set-exception-flags) ( register exceptions -- register' )
[ ppc-exception-flag>bit >mask ppc-exception-flag-bits remask ] curry change-fpcsr ; inline
M: ppc-fpu-env (get-fp-traps) ( register -- exceptions )
fpcsr>> not ppc-fp-traps>bit mask> ; inline
M: ppc-fpu-env (set-fp-traps) ( register exceptions -- register' )
[ ppc-fp-traps>bit >mask not ppc-fp-traps-bits remask ] curry change-fpcsr ; inline
M: ppc-fpu-env (get-rounding-mode) ( register -- mode )
fpcsr>> ppc-rounding-mode-bits mask ppc-rounding-mode>bit value-at ; inline
M: ppc-fpu-env (set-rounding-mode) ( register mode -- register' )
[ ppc-rounding-mode>bit at ppc-rounding-mode-bits remask ] curry change-fpcsr ; inline
M: ppc-fpu-env (get-denormal-mode) ( register -- mode )
fpcsr>> ppc-denormal-mode-bits mask zero? +denormal-keep+ +denormal-flush+ ? ; inline
M: ppc-fpu-env (set-denormal-mode) ( register mode -- register' )
[
{
{ +denormal-keep+ [ ppc-denormal-mode-bits unmask ] }
{ +denormal-flush+ [ ppc-denormal-mode-bits bitor ] }
} case
] curry change-fpcsr ; inline

132
basis/math/floats/env/x86/x86.factor vendored Normal file
View File

@ -0,0 +1,132 @@
USING: accessors alien.syntax arrays assocs biassocs
classes.struct combinators cpu.x86.features kernel literals
math math.bitwise math.floats.env math.floats.env.private
system ;
IN: math.floats.env.x86
STRUCT: sse-env
{ mxcsr uint } ;
STRUCT: x87-env
{ status ushort }
{ control ushort } ;
! defined in the vm, cpu-x86*.S
FUNCTION: void get_sse_env ( sse-env* env ) ;
FUNCTION: void set_sse_env ( sse-env* env ) ;
FUNCTION: void get_x87_env ( x87-env* env ) ;
FUNCTION: void set_x87_env ( x87-env* env ) ;
: <sse-env> ( -- sse-env )
sse-env (struct) [ get_sse_env ] keep ;
M: sse-env (set-fp-env-register)
set_sse_env ;
: <x87-env> ( -- x87-env )
x87-env (struct) [ get_x87_env ] keep ;
M: x87-env (set-fp-env-register)
set_x87_env ;
M: x86 (fp-env-registers)
sse2?
[ <sse-env> <x87-env> 2array ]
[ <x87-env> 1array ] if ;
CONSTANT: sse-exception-flag-bits HEX: 3f
CONSTANT: sse-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 }
}
CONSTANT: sse-fp-traps-bits HEX: 1f80
CONSTANT: sse-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 }
}
CONSTANT: sse-rounding-mode-bits HEX: 6000
CONSTANT: sse-rounding-mode>bit
$[ H{
{ +round-nearest+ HEX: 0000 }
{ +round-down+ HEX: 2000 }
{ +round-up+ HEX: 4000 }
{ +round-zero+ HEX: 6000 }
} >biassoc ]
CONSTANT: sse-denormal-mode-bits HEX: 8040
M: sse-env (get-exception-flags) ( register -- exceptions )
mxcsr>> sse-exception-flag>bit mask> ; inline
M: sse-env (set-exception-flags) ( register exceptions -- register' )
[ sse-exception-flag>bit >mask sse-exception-flag-bits remask ] curry change-mxcsr ; inline
M: sse-env (get-fp-traps) ( register -- exceptions )
mxcsr>> bitnot sse-fp-traps>bit mask> ; inline
M: sse-env (set-fp-traps) ( register exceptions -- register' )
[ sse-fp-traps>bit >mask bitnot sse-fp-traps-bits remask ] curry change-mxcsr ; inline
M: sse-env (get-rounding-mode) ( register -- mode )
mxcsr>> sse-rounding-mode-bits mask sse-rounding-mode>bit value-at ; inline
M: sse-env (set-rounding-mode) ( register mode -- register' )
[ sse-rounding-mode>bit at sse-rounding-mode-bits remask ] curry change-mxcsr ; inline
M: sse-env (get-denormal-mode) ( register -- mode )
mxcsr>> sse-denormal-mode-bits mask zero? +denormal-keep+ +denormal-flush+ ? ; inline
M: sse-env (set-denormal-mode) ( register mode -- register' )
[
{
{ +denormal-keep+ [ sse-denormal-mode-bits unmask ] }
{ +denormal-flush+ [ sse-denormal-mode-bits bitor ] }
} case
] curry change-mxcsr ; inline
CONSTANT: x87-exception-bits HEX: 3f
CONSTANT: x87-exception>bit
H{
{ +fp-invalid-operation+ HEX: 01 }
{ +fp-overflow+ HEX: 08 }
{ +fp-underflow+ HEX: 10 }
{ +fp-zero-divide+ HEX: 04 }
{ +fp-inexact+ HEX: 20 }
}
CONSTANT: x87-rounding-mode-bits HEX: 0c00
CONSTANT: x87-rounding-mode>bit
$[ H{
{ +round-nearest+ HEX: 0000 }
{ +round-down+ HEX: 0400 }
{ +round-up+ HEX: 0800 }
{ +round-zero+ HEX: 0c00 }
} >biassoc ]
M: x87-env (get-exception-flags) ( register -- exceptions )
status>> x87-exception>bit mask> ; inline
M: x87-env (set-exception-flags) ( register exceptions -- register' )
drop ;
M: x87-env (get-fp-traps) ( register -- exceptions )
control>> bitnot x87-exception>bit mask> ; inline
M: x87-env (set-fp-traps) ( register exceptions -- register' )
[ x87-exception>bit >mask bitnot x87-exception-bits remask ] curry change-control ; inline
M: x87-env (get-rounding-mode) ( register -- mode )
control>> x87-rounding-mode-bits mask x87-rounding-mode>bit value-at ; inline
M: x87-env (set-rounding-mode) ( register mode -- register' )
[ x87-rounding-mode>bit at x87-rounding-mode-bits remask ] curry change-control ; inline
M: x87-env (get-denormal-mode) ( register -- mode )
drop +denormal-keep+ ; inline
M: x87-env (set-denormal-mode) ( register mode -- register' )
drop ;

View File

@ -245,17 +245,12 @@ DEF(void,primitive_inline_cache_miss_tail,(void)):
mtctr r3
bctr
DEF(unsigned,get_fp_control_register,(void)):
DEF(void,get_ppc_fpu_env,(void*)):
mffs fr0
li r2,-4
stfiwx fr0,r2,r1
lwzx r3,r2,r1
stfd fr0,0(r3)
blr
DEF(void,set_fp_control_register,(unsigned)):
li r2,-4
stwx r3,r2,r1
li r2,-8
lfdx fr0,r2,r1
DEF(void,set_ppc_fpu_env,(const void*)):
lfd fr0,0(r3)
mtfsf 0xff,fr0
blr

View File

@ -68,14 +68,30 @@ DEF(void,primitive_inline_cache_miss_tail,(void)):
add $12,%esp
jmp *%eax
DEF(unsigned,get_fp_control_register,(void)):
push %eax
stmxcsr (%esp)
pop %eax
DEF(void,get_sse_env,(void*)):
movl 4(%esp), %eax
stmxcsr (%eax)
ret
DEF(void,set_fp_control_register,(unsigned reg)):
ldmxcsr 4(%esp)
DEF(void,set_sse_env,(const void*)):
movl 4(%esp), %eax
ldmxcsr (%eax)
ret
DEF(void,get_x87_env,(void*)):
movl 4(%esp), %eax
fnstsw (%eax)
fnstcw 2(%eax)
ret
DEF(void,set_x87_env,(const void*)):
movl 4(%esp), %eax
fldcw 2(%eax)
movb 4(%eax), %dl
test %dl, %dl
jz 1f
fnclex
1:
ret
#include "cpu-x86.S"
@ -84,4 +100,8 @@ DEF(void,set_fp_control_register,(unsigned reg)):
.section .drectve
.ascii " -export:check_sse2"
.ascii " -export:read_timestamp_counter"
.ascii " -export:get_sse_env"
.ascii " -export:set_sse_env"
.ascii " -export:get_x87_env"
.ascii " -export:set_x87_env"
#endif

View File

@ -88,14 +88,22 @@ DEF(void,primitive_inline_cache_miss_tail,(void)):
add $STACK_PADDING,%rsp
jmp *%rax
DEF(unsigned,get_fp_control_register,(void)):
stmxcsr -4(%rsp)
movl -4(%rsp), %eax
DEF(void,get_sse_env,(void*)):
stmxcsr (%rdi)
ret
DEF(void,set_fp_control_register,(unsigned reg)):
movl %edi, -4(%rsp)
ldmxcsr -4(%rsp)
DEF(void,set_sse_env,(const void*)):
ldmxcsr (%rdi)
ret
DEF(void,get_x87_env,(void*)):
fnstsw (%rdi)
fnstcw 2(%rdi)
ret
DEF(void,set_x87_env,(const void*)):
fnclex
fldcw 2(%rdi)
ret
#include "cpu-x86.S"