From dc2340a06c6b1feb2188da0c76b1a1dc98203a82 Mon Sep 17 00:00:00 2001 From: midipix Date: Dec 25 2023 14:19:02 +0000 Subject: nt64: implemented the float environment interfaces. --- diff --git a/src/fenv/nt64/fenv.S b/src/fenv/nt64/fenv.S new file mode 100644 index 0000000..801db93 --- /dev/null +++ b/src/fenv/nt64/fenv.S @@ -0,0 +1,375 @@ +/**************************************************************************/ +/* mmglue: midipix architecture- and target-specific bits for musl libc */ +/* Copyright (C) 2013--2023 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.MMGLUE. */ +/**************************************************************************/ + + .file "fenv.S" + +/* common exception bits */ +#define FE_INVALID (1 << 0) +#define FE_DENORM (1 << 1) +#define FE_DIVBYZERO (1 << 2) +#define FE_OVERFLOW (1 << 3) +#define FE_UNDERFLOW (1 << 4) +#define FE_INEXACT (1 << 5) + +#define FE_ALL_EXCEPT (0x3F) + +/* X87 FPU rounding control bits */ +#define FPU_RC_TONEAREST (0x0 << 10) +#define FPU_RC_DOWNWARD (0x1 << 10) +#define FPU_RC_UPWARD (0x2 << 10) +#define FPU_RC_TOWARDZERO (0x3 << 10) +#define FPU_RC_MASK FPU_RC_TOWARDZERO + +/* X87 FPU control word */ +#define FPU_CW_MASK (0xFFFF) +#define FPU_CW_RC_MASK (FPU_CW_MASK ^ FPU_RC_MASK) + +/* MXCSR rounding control bits */ +#define MXCSR_RC_TONEAREST (0X0 << 13) +#define MXCSR_RC_DOWNWARD (0x1 << 13) +#define MXCSR_RC_UPWARD (0x2 << 13) +#define MXCSR_RC_TOWARDZERO (0x3 << 13) +#define MXCSR_RC_MASK MXCSR_RC_TOWARDZERO + +/* MXCSR control word */ +#define MXCSR_CW_MASK (0xFFFF) +#define MXCSR_CW_RC_MASK (MXCSR_CW_MASK ^ MXCSR_RC_MASK) + +/* fenv_At struct definition */ +#define FPUCW_MEMBER_OFFSET (0x0) +#define MXCSR_MEMBER_OFFSET (0x1C) + +/* user rounding control flags */ +#define FE_RC_TONEAREST FPU_RC_TONEAREST +#define FE_RC_DOWNWARD FPU_RC_DOWNWARD +#define FE_RC_UPWARD FPU_RC_UPWARD +#define FE_RC_TOWARDZERO FPU_RC_TOWARDZERO +#define FE_RC_MASK FPU_RC_MASK + +/* user default float environment */ +#define FE_DFL_ENV (-1) + + /******************************************************/ + /* */ + /* FSTCW: check for pending floating-point */ + /* exceptions, then store FPU control word. */ + /* */ + /* FNSTCW: store FPU control word without first */ + /* checking for pending floating-point */ + /* exceptions. */ + /* */ + /* FSTSW: check for pending floating-point */ + /* exceptions, then store FPU status word. */ + /* */ + /* FNSTSW: store FPU status word without first */ + /* checking for pending floating-point */ + /* exceptions. */ + /* */ + /* FCLEX: check for pending floating-point */ + /* exceptions, then clear FPU exception */ + /* flags. */ + /* */ + /* FNCLEX: clear FPU exception flags without first */ + /* checking for pending floating-point */ + /* exceptions. */ + /* */ + /* FLDCW: set the FPU Control Word from memory. */ + /* */ + /* FLDENV: set the FPU Environment from memory. */ + /* */ + /* STMXCSR: store the state of the MXCSR register; */ + /* the register's reserved bits are set to */ + /* zero in the destination. */ + /* */ + /* LDMXCSR: set the MXCSR environment from memory. */ + /* */ + /******************************************************/ + + /**********************************************/ + /* int fetestexcept(int exflags); */ + /* */ + /* query which exception flags, as indicated */ + /* by the exflags mask, are currently set. */ + /* */ + /**********************************************/ + + .text + .def fetestexcept; .scl 2; .type 32; .endef + .global fetestexcept + + .cfi_startproc; +fetestexcept: + and $FE_ALL_EXCEPT,%ecx /* normalize exflags */ + push %r10 /* temporary state var */ + stmxcsr (%rsp) /* store mxcsr state */ + pop %rdx /* copy state to rdx */ + fnstsw %ax /* store fpu state */ + or %edx,%eax /* fpu+mxcsr state */ + and %ecx,%eax /* desired flags only */ + ret + .cfi_endproc + + + /**********************************************/ + /* int feclearexcept(int exflags); */ + /* */ + /* clear specific fpu exception flags, as */ + /* indicated by the exflags mask. */ + /* */ + /**********************************************/ + + .text + .def feclearexcept; .scl 2; .type 32; .endef + .global feclearexcept + + .cfi_startproc; +feclearexcept: + fnstsw %ax /* store fpu state */ + and $FE_ALL_EXCEPT,%ecx /* normalize exflags */ + and $FE_ALL_EXCEPT,%eax /* normalize fpu state */ + test %ecx,%eax /* test exflags,state */ + jz 1f /* state already clear? */ + fnclex /* clear fpu state */ +1: push %rdx /* temporary state var */ + stmxcsr (%rsp) /* store mxcsr state */ + pop %rdx /* copy state to rdx */ + or %eax,%edx /* fpu+mxcsr state */ + test %ecx,%edx /* test exflags,state */ + jz 1f /* state already clear? */ + not %ecx /* clear desired flags- */ + and %ecx,%edx /* -from mxcsr state */ + push %rdx /* modified mxcsr var */ + ldmxcsr (%rsp) /* update mxcsr */ + pop %rdx /* dealloc mxcsr var */ +1: xor %eax,%eax /* ret zero either way */ + ret + .cfi_endproc + + + /**********************************************/ + /* int feraiseexcept(int exflags); */ + /* */ + /* set specific fpu exception flags, as */ + /* indicated by the exflags mask. */ + /* */ + /* it is enough to set the flags only in */ + /* either mxcsr or the [legacy] x87 fpu, */ + /* specifically since fetestexcept() does */ + /* take both into account. */ + /* */ + /**********************************************/ + + .text + .def feraiseexcept; .scl 2; .type 32; .endef + .global feraiseexcept + + .cfi_startproc; +feraiseexcept: + and $FE_ALL_EXCEPT,%ecx /* normalize exflags */ + stmxcsr -0x8(%rsp) /* store mxcsr state */ + or %ecx,-0x8(%rsp) /* set desired flags */ + ldmxcsr -0x8(%rsp) /* update mxcsr */ + xor %eax,%eax + ret + .cfi_endproc + + + /**********************************************/ + /* int fegetround(void); */ + /* */ + /* obtain the current rounding mode, which */ + /* should be one of: round-to-neareset, */ + /* round-downwards, round-upwards, or */ + /* round-toward-zero. */ + /* */ + /* when we set the rounding mode we set both */ + /* mxcsr and the [legacy] x87 fpu, and it */ + /* thus suffices to obtain the mode from */ + /* either, which is mxcsr in our case. */ + /**********************************************/ + + .text + .def fegetround; .scl 2; .type 32; .endef + .global fegetround + + .cfi_startproc; +fegetround: + push %rdx /* temporary state var */ + stmxcsr (%rsp) /* store mxcsr state */ + pop %rax /* copy state to rax */ + and $MXCSR_RC_MASK,%rax /* MXCSR RC bits only */ + shr $0x3,%rax /* MXCSR --> FE bits */ + ret + .cfi_endproc + + + /**********************************************/ + /* int fesetround(int rcmode); */ + /* */ + /* set the current rounding mode, which */ + /* should be one of: round-to-neareset, */ + /* round-downwards, round-upwards, or */ + /* round-toward-zero. */ + /**********************************************/ + + .text + .def __fesetround; .scl 2; .type 32; .endef + .global __fesetround + + .cfi_startproc; +__fesetround: + push %rdx /* alloc control var */ + and $FE_RC_MASK,%ecx /* normalize rcarg */ + fnstcw (%rsp) /* current control word */ + andw $FPU_CW_RC_MASK,(%rsp) /* control word only */ + or %ecx,(%rsp) /* set rc bits to rcarg */ + fldcw (%rsp) /* set fpu control word */ + shl $0x3,%ecx /* rcarg: FPU --> MXCSR */ + stmxcsr (%rsp) /* current mxcsr reg */ + andw $MXCSR_CW_RC_MASK,(%rsp) /* control word only */ + or %ecx,(%rsp) /* set rc bits to rcarg */ + ldmxcsr (%rsp) /* set mxcsr ctrl word */ + pop %rdx /* dealloc control var */ + xor %eax,%eax + ret + .cfi_endproc + + + /**********************************************/ + /* int fegetenv(fenv_t *); */ + /* */ + /* popualte a structure of type fenv_t with */ + /* the current X87 FPU environmtnet (fnstenv) */ + /* as well as MXCSR environment (stmxcsr). */ + /**********************************************/ + + .text + .def fegetenv; .scl 2; .type 32; .endef + .global fegetenv + + .cfi_startproc; +fegetenv: + fnstenv FPUCW_MEMBER_OFFSET(%rcx) + stmxcsr MXCSR_MEMBER_OFFSET(%rcx) + xor %eax,%eax + ret + .cfi_endproc + + + /**********************************************/ + /* int fesetenv(cont fenv_t *); */ + /* */ + /* (re)initialize the X87 FPU and MXCSR */ + /* environments from a user structure of */ + /* type fenv_t. */ + /* */ + /* if the pointer to the fenv_t structure is */ + /* FE_DFL_ENV, reset the X87 FPU and MXCSR */ + /* environments to theit default values as */ + /* defined by the architecture. */ + /* */ + /* .__control_word = 0x037f, */ + /* .__unused1 = N/A, */ + /* .__status_word = 0x0, */ + /* .__unused2 = N/A, */ + /* .__tags = 0xffff, */ + /* .__unused3 = N/A, */ + /* .__eip = 0x0, */ + /* .__cs_selector = 0x0, */ + /* .__opcode = 0x0, */ + /* .__unused4 = N/A, */ + /* .__data_offset = 0x0, */ + /* .__data_selector = 0x0, */ + /* .__unused5 = N/A, */ + /* .__mxcsr = 0x1f80 */ + /* */ + /**********************************************/ + + .text + .def fesetenv; .scl 2; .type 32; .endef + .global fesetenv + + .cfi_startproc; +fesetenv: + /* prolog */ + xor %eax,%eax + + /* use fenv_t or reset to default values? */ + cmpq $FE_DFL_ENV,%rcx + jz 1f + + /* use the user-provided fenv_t */ + fldenv FPUCW_MEMBER_OFFSET(%rcx) + ldmxcsr MXCSR_MEMBER_OFFSET(%rcx) + ret + + /* reset environments to the architecture-defined defaults */ +1: subq $0x20,%rsp + + /* X87 FPU */ + movq $0x037f,(0x0)(%rsp) + movq $0xffff,(0x8)(%rsp) + movq $0x0,(0x10)(%rsp) + movq $0x0,(0x18)(%rsp) + fldenv (%rsp) + + /* MXCSR */ + movq $0x1f80,(%rsp) + ldmxcsr (%rsp) + + /* all done */ + addq $0x20,%rsp + ret + .cfi_endproc + + + .section .got$fetestexcept + .global __imp_fetestexcept +__imp_fetestexcept: + .quad fetestexcept + .linkonce discard + + + .section .got$feclearexcept + .global __imp_feclearexcept +__imp_feclearexcept: + .quad feclearexcept + .linkonce discard + + + .section .got$feraiseexcept + .global __imp_feraiseexcept +__imp_feraiseexcept: + .quad feraiseexcept + .linkonce discard + + + .section .got$fegetround + .global __imp_fegetround +__imp_fegetround: + .quad fegetround + .linkonce discard + + + .section .got$__fesetround + .global __imp___fesetround +__imp___fesetround: + .quad __fesetround + .linkonce discard + + + .section .got$fegetenv + .global __imp_fegetenv +__imp_fegetenv: + .quad fegetenv + .linkonce discard + + + .section .got$fesetenv + .global __imp_fesetenv +__imp_fesetenv: + .quad fesetenv + .linkonce discard