blob: c349d100b4da15db4d918ed0681e3d07258865c3 [file] [log] [blame]
/*
* Copyright (C) 2008-2009 Advanced Micro Devices, Inc. All Rights Reserved.
*
* This file is part of libacml_mv.
*
* libacml_mv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libacml_mv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libacml_mv. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <emmintrin.h>
#include <math.h>
#include <errno.h>
#include "../inc/libm_util_amd.h"
#include "../inc/libm_special.h"
double _sin_cos_special(double x, const char *name)
{
UT64 xu;
unsigned int is_snan;
xu.f64 = x;
if((xu.u64 & EXPBITS_DP64) == EXPBITS_DP64)
{
// x is Inf or NaN
if((xu.u64 & MANTBITS_DP64) == 0x0)
{
// x is Inf
_mm_setcsr(_mm_getcsr() | MXCSR_ES_INVALID);
#ifdef WIN64
xu.u64 = INDEFBITPATT_DP64;
__amd_handle_error(DOMAIN, EDOM, name, x, 0, xu.f64);
#else
xu.u64 = QNANBITPATT_DP64;
name = *(&name); // dummy statement to avoid warning
#endif
}
else {
// x is NaN
is_snan = (((xu.u64 & QNAN_MASK_64) == QNAN_MASK_64) ? 0 : 1);
if(is_snan){
xu.u64 |= QNAN_MASK_64;
#ifdef WIN64
#else
_mm_setcsr(_mm_getcsr() | MXCSR_ES_INVALID);
#endif
}
#ifdef WIN64
__amd_handle_error(DOMAIN, EDOM, name, x, 0, xu.f64);
#endif
}
}
return xu.f64;
}
float _sinf_cosf_special(float x, const char *name)
{
UT32 xu;
unsigned int is_snan;
xu.f32 = x;
if((xu.u32 & EXPBITS_SP32) == EXPBITS_SP32)
{
// x is Inf or NaN
if((xu.u32 & MANTBITS_SP32) == 0x0)
{
// x is Inf
_mm_setcsr(_mm_getcsr() | MXCSR_ES_INVALID);
#ifdef WIN64
xu.u32 = INDEFBITPATT_SP32;
__amd_handle_errorf(DOMAIN, EDOM, name, x, 0, 0.0f, 0, xu.f32, 0);
#else
xu.u32 = QNANBITPATT_SP32;
name = *(&name); // dummy statement to avoid warning
#endif
}
else {
// x is NaN
is_snan = (((xu.u32 & QNAN_MASK_32) == QNAN_MASK_32) ? 0 : 1);
if(is_snan) {
xu.u32 |= QNAN_MASK_32;
_mm_setcsr(_mm_getcsr() | MXCSR_ES_INVALID);
}
#ifdef WIN64
__amd_handle_errorf(DOMAIN, EDOM, name, x, is_snan, 0.0f, 0, xu.f32, 0);
#endif
}
}
return xu.f32;
}
float _sinf_special(float x)
{
return _sinf_cosf_special(x, "sinf");
}
double _sin_special(double x)
{
return _sin_cos_special(x, "sin");
}
float _cosf_special(float x)
{
return _sinf_cosf_special(x, "cosf");
}
double _cos_special(double x)
{
return _sin_cos_special(x, "cos");
}
void _sincosf_special(float x, float *sy, float *cy)
{
float xu = _sinf_cosf_special(x, "sincosf");
*sy = xu;
*cy = xu;
return;
}
void _sincos_special(double x, double *sy, double *cy)
{
double xu = _sin_cos_special(x, "sincos");
*sy = xu;
*cy = xu;
return;
}