summaryrefslogtreecommitdiffhomepage
path: root/src/fenv/nt64
diff options
context:
space:
mode:
Diffstat (limited to 'src/fenv/nt64')
-rw-r--r--src/fenv/nt64/fenv.S375
1 files changed, 375 insertions, 0 deletions
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