s_cosisin.s   [plain text]


/*
 * Written by Stephen Canon
 *
 * Copyright © 2007, Apple Inc.  All Rights Reserved.
 */

#include <machine/asm.h>

#if defined( __LP64__ )
#define PTR_SIZE	8
#define MOVP		movq
#define ADDP		addq
#define SUBP		subq
#define RESULT_DEST %rdi
#define STACKP	%rsp
#else
#define PTR_SIZE  4
#define MOVP		movl
#define ADDP		addl
#define SUBP		subl
#define RESULT_DEST %edx
#define STACKP	%esp
#endif


// void cosisinl(long double x, long double complex *z)

ENTRY(cosisinl)
  fldt	PTR_SIZE(STACKP)  // load argument

#if defined( __LP64__ )           // in lp64 case, result address is already in %rdi
#else
  MOVP	16+PTR_SIZE(STACKP), RESULT_DEST  // load result address
#endif

  fsincos                         // try sincos
  fnstsw	%ax                     // load status word
  andw	$0x400,%ax                // check status word to see if x was in range for fsincos
  jnz		1f

  fstpt	(RESULT_DEST)             // if the argument was in range, store the result
  fstpt	16(RESULT_DEST)
  ret                             // and return

  1:	fldpi                       // if the argument was out of range, put 2π on the fp stack
  fadd	%st(0)
  fxch	%st(1)

  2:	fprem1                      // while x is out of range, reduce by 2π
  fnstsw	%ax
  andw	$0x400,%ax
  jnz		2b
  fstp	%st(1)                    // clear 2π off the fp stack

  fsincos                         // compute fsincos (argument is surely in range here)

  fstpt	(RESULT_DEST)             // store the result
  fstpt	16(RESULT_DEST)
  ret                             // and return


// void cosisin(double x, double complex *z)

ENTRY(cosisin)
#if defined( __LP64__ )          // in LP64, load x from %xmm0 (result dest will stay in %rdi)
	SUBP	$8, STACKP
	movsd %xmm0, (STACKP)
	fldl	(STACKP)
#else
	fldl	PTR_SIZE(STACKP)  // otherwise, load x and the result dest off the stack
	MOVP	8+PTR_SIZE(STACKP), RESULT_DEST
#endif

	fsincos                         // try sincos
	fnstsw	%ax                     // load status word
	andw	$0x400,%ax                // check status word to see if x was in range for fsincos
	jnz		3f

	fstpl	(RESULT_DEST)             // store the result
	fstpl	8(RESULT_DEST)
#if defined( __LP64__ )
	ADDP	$8, STACKP                // restore the stack, since we touched it in 64-bit mode
#endif
	ret

	3:	fldpi                       // if the argument was out of range, put 2π on the fp stack
	fadd	%st(0)
	fxch	%st(1)

	4:	fprem1                      // while x is out of range, reduce by 2π
	fnstsw	%ax
	andw	$0x400,%ax
	jnz	4b
	fstp	%st(1)                    // clear 2π off the fp stack

	fsincos                         // compute fsincos (argument is surely in range here)

	fstpl	(RESULT_DEST)             // store the result
	fstpl	8(RESULT_DEST)
#if defined( __LP64__ )
	ADDP	$8, STACKP                // restore the stack, since we touched it in 64-bit mode
#endif
	ret


// void cosisinf(float x, float complex *z)

ENTRY(cosisinf)
#if defined( __LP64__ )           // in LP64, load x from %xmm0 (result dest will stay in %rdi)
	SUBP	$4, STACKP
	movss	%xmm0, (STACKP)
	flds	(STACKP)
#else
	flds	PTR_SIZE(STACKP)  // otherwise, load x and the result dest off the stack
	MOVP	4+PTR_SIZE(STACKP), RESULT_DEST
#endif

	fsincos                         // try sincos
	fnstsw	%ax                     // load status word
	andw	$0x400,%ax                // check status word to see if x was in range for fsincos
	jnz		5f

	fstps	(RESULT_DEST)             // store the result
	fstps	4(RESULT_DEST)
#if defined( __LP64__ )
	ADDP	$4, STACKP                // restore the stack, since we touched it in 64-bit mode
#endif
	ret

	5:	fldpi                         // if the argument was out of range, put 2π on the stack
	fadd	%st(0)
	fxch	%st(1)

	6:	fprem1                        // while x is out of range, reduce by 2π
	fnstsw	%ax
	andw	$0x400,%ax
	jnz	6b
	fstp	%st(1)                    // clear 2π off the stack

	fsincos                         // compute fsincos (argument is surely in range here)

	fstps	(RESULT_DEST)             // store the result
	fstps	4(RESULT_DEST)
#if defined( __LP64__ )
	ADDP	$4, STACKP                // restore the stack, since we touched it in 64-bit mode
#endif
	ret