/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8     -*-â
âvi: set et ft=asm ts=8 tw=8 fenc=utf-8                                     :viâ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¡
â                                                                              â
â  Musl Libc                                                                   â
â  Copyright Â© 2005-2014 Rich Felker, et al.                                   â
â                                                                              â
â  Permission is hereby granted, free of charge, to any person obtaining       â
â  a copy of this software and associated documentation files (the             â
â  "Software"), to deal in the Software without restriction, including         â
â  without limitation the rights to use, copy, modify, merge, publish,         â
â  distribute, sublicense, and/or sell copies of the Software, and to          â
â  permit persons to whom the Software is furnished to do so, subject to       â
â  the following conditions:                                                   â
â                                                                              â
â  The above copyright notice and this permission notice shall be              â
â  included in all copies or substantial portions of the Software.             â
â                                                                              â
â  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,             â
â  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF          â
â  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.      â
â  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY        â
â  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,        â
â  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE           â
â  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                      â
â                                                                              â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ*/
#include "libc/macros.internal.h"

//	Clears floating point exception status, e.g.
//
//	    feclearexcept(FE_ALL_EXCEPT);
//
//	@param excepts may bitwise-or the following:
//		- `FE_INVALID`
//		- `FE_DIVBYZERO`
//		- `FE_OVERFLOW`
//		- `FE_UNDERFLOW`
//		- `FE_INEXACT`
//		- `FE_ALL_EXCEPT` (all of the above)
//	@return	0 on success, or nonzero on error
feclearexcept:
#ifdef __x86_64__
//	maintain exceptions in the sse mxcsr, clear x87 exceptions
	mov	%edi,%ecx
	and	$0x3f,%ecx
	fnstsw	%ax
	test	%eax,%ecx
	jz	1f
	fnclex
1:	stmxcsr	-8(%rsp)
	and	$0x3f,%eax
	or	%eax,-8(%rsp)
	test	%ecx,-8(%rsp)
	jz	1f
	not	%ecx
	and	%ecx,-8(%rsp)
	ldmxcsr	-8(%rsp)
1:	xor	%eax,%eax
	ret
#elif defined(__aarch64__)
	and	w0,w0,#0x1f
	mrs	x1,fpsr
	bic	w1,w1,w0
	msr	fpsr,x1
	mov	w0,#0
	ret
#else
#error "unsupported architecture"
#endif
	.endfn	feclearexcept,globl

//	Checks for floating point exception.
//
//	This function may be used to check the thread-local
//	floating-point exception status bits, e.g.
//
//	    feclearexcept(FE_ALL_EXCEPT);
//	    volatile double x = 0, y = 1 / x;
//	    assert(fetestexcept(FE_ALL_EXCEPT) == FE_DIVBYZERO);
//
//	@param excepts may bitwise-or the following:
//		- `FE_INVALID`
//		- `FE_DIVBYZERO`
//		- `FE_OVERFLOW`
//		- `FE_UNDERFLOW`
//		- `FE_INEXACT`
//		- `FE_ALL_EXCEPT` (all of the above)
//	@return	mask of which exception status codes are currently set,
//		or zero if there aren't any floating point exceptions
fetestexcept:
#ifdef __x86_64__
	and	$0x3f,%edi
	push	%rax
	stmxcsr	(%rsp)
	pop	%rsi
	fnstsw	%ax
	or	%esi,%eax
	and	%edi,%eax
	ret
#elif defined(__aarch64__)
	and	w0,w0,#0x1f
	mrs	x1,fpsr
	and	w0,w0,w1
	ret
#endif
	.endfn	fetestexcept,globl

feraiseexcept:
#ifdef __x86_64__
	and	$0x3f,%edi
	stmxcsr	-8(%rsp)
	or	%edi,-8(%rsp)
	ldmxcsr	-8(%rsp)
	xor	%eax,%eax
	ret
#elif defined(__aarch64__)
	and	w0,w0,#0x1f
	mrs	x1,fpsr
	orr	w1,w1,w0
	msr	fpsr,x1
	mov	w0,#0
	ret
#endif
	.endfn	feraiseexcept,globl

__fesetround:
#ifdef __x86_64__
	push	%rax
	xor	%eax,%eax
	mov	%edi,%ecx
	fnstcw	(%rsp)
	andb	$0xf3,1(%rsp)
	or	%ch,1(%rsp)
	fldcw	(%rsp)
	stmxcsr	(%rsp)
	shl	$3,%ch
	andb	$0x9f,1(%rsp)
	or	%ch,1(%rsp)
	ldmxcsr	(%rsp)
	pop	%rcx
	ret
#elif defined(__aarch64__)
	mrs	x1,fpcr
	bic	w1,w1,#0xc00000
	orr	w1,w1,w0
	msr	fpcr,x1
	mov	w0,#0
	ret
#endif
	.endfn	__fesetround,globl,hidden

fegetround:
#ifdef __x86_64__
	push	%rax
	stmxcsr	(%rsp)
	pop	%rax
	shr	$3,%eax
	and	$0xc00,%eax
	ret
#elif defined(__aarch64__)
	mrs	x0,fpcr
	and	w0,w0,#0xc00000
	ret
#endif
	.endfn	fegetround,globl

fegetenv:
#ifdef __x86_64__
	xor	%eax,%eax
	fnstenv	(%rdi)
	stmxcsr	28(%rdi)
	ret
#elif defined(__aarch64__)
	mrs	x1,fpcr
	mrs	x2,fpsr
	stp	w1,w2,[x0]
	mov	w0,#0
	ret
#endif
	.endfn	fegetenv,globl

fesetenv:
#ifdef __x86_64__
	xor	%eax,%eax
	inc	%rdi
	jz	1f
	fldenv	-1(%rdi)
	ldmxcsr	27(%rdi)
	ret
1:	push	%rax
	push	%rax
	pushq	$0xffff
	pushq	$0x37f
	fldenv	(%rsp)
	pushq	$0x1f80
	ldmxcsr	(%rsp)
	add	$40,%rsp
	ret
#elif defined(__aarch64__)
	mov	x1,#0
	mov	x2,#0
	cmn	x0,#1
	b.eq	1f
	ldp	w1,w2,[x0]
1:	msr	fpcr,x1
	msr	fpsr,x2
	mov	w0,#0
	ret
#endif
	.endfn	fesetenv,globl
