Blame src/fenv/nt64/fenv.S

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