	.file "acos.s"
/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/* $Header: acos.s 1.2 89/10/10 $
 *
 *		ARCCOSINE FUNCTION
 *
 * Functional Description:
 *
 *	This routine implements the arc cosine function for the C language.
 *
 * Input:	Argument is located at 4(%esp)
 *
 * Output:	Double Precision value is returned in ST(0)
 *
 * Created:
 *	06/03/86	GS - Quantitative Technology Corporation for
 *				Sequent Computer Systems
 *	09/04/86	Phil Hochstetler - converted to C library conventions
 *
 *	05/22/87	Gary Tracy - converted to stack model C interface
 *			  under this model, the caller is responsible for
 *			  saving and restoring any required 387 state.
 *			  this need not be done if:
 *				1.  the callee does no calls.
 *				2.  the sum of 387 registers used by the caller
 *				    and callee does not exceed 8.
 *
 *
 * Method:
 *			        _____________
 *			  \    /     1 - x
 *	acos(x) = 2*atan2( \  /   ----------    , 1).
 *			    \/       1 + x
 *
 *	Special cases checked:
 *	     			|x| > 1  = Error
 * 	      			acos(-1) = PI
 */
#include "sys.s"

STR1:
	.byte	0x61,0x63,0x6f,0x73,0x00
STR2:
	.byte 	0x61,0x63,0x6f,0x73,0x3a,0x20,0x44,0x4f,0x4d,0x41
	.byte	0x49,0x4e,0x20,0x65,0x72,0x72,0x6f,0x72,0x0a,0x00
	.data
	.align 2

ENTRY(acos)

	fldl	4(%esp)			/put argument onto stack
	fld1				/put 1.0 onto stack
	fld	%st(1)
	fabs				/|x| --> st(0)

	/Assert Registers have the following values
	/ St(0) = |x|
	/ St(1) = 1
	/ St(2) = x

	fcom				/compare 1.0 and |x|
	fstsw	%ax			/store status of compare
	sahf
	fxch	%st(2)			/replace the argument on top
	fst	%st(2)
	jz	acos_test_for_neg_one	/if |x| == 1 then check for neg one
	jc 	acos_continue		/if |x| < 1 then continue the calc

	fstp	%st(0)			/clear the floating point stack
	fstp	%st(0)
	fstp	%st(0)

	subl	$0x20,%esp		/make room for struct exception exc
	fldl	0x24(%esp)		/move parm to exc.arg1
	fstpl	0x8(%esp)
	movl	$0x1,(%esp)		/move DOMAIN to exc.type
	movl	$STR1,0x4(%esp)		/move "acos" to exc.name
	fldz
	fstpl	0x18(%esp)		/move 0.0 to exc.retval
	leal	(%esp),%eax		/push &exc onto stack
	pushl	%eax
	call	matherr
	popl	%ecx
	testl	%eax,%eax
	jne	acos_exit

	pushl	$0x13			/ length of error string
	pushl	$STR2			/ the address of the error string
	pushl	$0x2			/ file descriptor # 2
	call	write
	addl	$0xc,%esp
	movl	$0x21,errno
acos_exit:
	fldl	0x18(%esp)
	addl	$0x20,%esp
	ret

acos_test_for_neg_one:
	/Assert |x| = 1
	ftst				/Compare x to 0.0
	fstsw	%ax			/Store the outcome of the test
	sahf
	jnc	acos_continue		/If x = 1 then continue


					/Else load PI to return as answer
	fstp	%st(0)			/       Clear the stack 
	fstp	%st(0)
	fstp	%st(0)
	fldz
	fldpi				/	load result (acos(-1) = PI)
	jmp 	acos_return

acos_continue:

/*
 *    Compute 	sqrt((1-x)/(1-x))
 */
	subl	$0x10,%esp		/Allocate local stack space
	fsubr	%st(1),%st   		/st(0) = 1 - x
	fxch	%st(1)			/st(0) = 1, st(1) = 1-x
	fadd	%st(2),%st   		/st(0) = 1 + x
	fdivr	%st(1),%st   		/st(0) = (1-x)/(1+x)
	fsqrt

	fstpl	(%esp)			/save first arg for atan2
	fld1				/load 1 on stack
	fstl	8(%esp)			/save second arg for atan2
	fwait
 	call	atan2			/form atan2(sqrt((1-x)/(1+x)),1)
	fst	%st(2)			/st(2) = atan2(sqrt((1-x)/(1+x)),1)
	fadd	%st,%st(2)		/st(2) = 2 * atan2(sqrt((1-x)/(1+x)),1)
	addl	$0x10,%esp		/deallocate local stack space
	fstp	%st(0)
	fstp	%st(0)

acos_return:
	fstp	%st(1)			/stack model requires empty stack
	ret
