Files
caa20dd196 Adsk contrib - Add support for neon intrinsic integration (#1828)
* Merging the previous ARM Neon branch

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Testing each SIMD variants using a small code snippet and first pass on unifying the way related cmake variables

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Removing the usage of USE_SSE in favor of the new OCIO_USE_SSE2 as they serve the same purpose

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Using try_compile instead of check_cxx_source_compiles as it was given false positive.  Stubbing cpuinfo for Apple ARM plateform. Handling Apple M1 correctly and adding support for SSE2NEON.

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Comments clean up and refactor some comments and documentations

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Added something in the documentation for Rosetta and small change in cmake

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Fixing the build under Rosetta and fixing issue in the MacOS CI.

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Using try_compile for CheckSupportSSEUsingSSE2NEON to standardize the code and fixed CheckSupport compiler flags.

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* use emmintrin.h for only sse2 features

Signed-off-by: Mark Reid <mindmark@gmail.com>
Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Allow F16C to be completely turned off

Signed-off-by: Mark Reid <mindmark@gmail.com>
Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Seperate SIMD test code from code that adds unit tests.

This isolates the compulation units and
avoids executing illegal hardware instructions

Signed-off-by: Mark Reid <mindmark@gmail.com>
Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* remove uneeded checks

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* use software implementations of f16c intrinsics for SSE2

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Added preprocessor checks for ARM as it is needed for universal build on APPLE platform

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Adding missing checks for "not arm64"

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Ease the future maintainability a the new OCIO_USE_xyz be moving the logic into CPUInfoConfig.h.in as well as fixing issue on ARM when building with OCIO_USE_SSE2NEON=OFF.

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Fixing some spacing, documentations and making some cmake conditions clearer.

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Adding a build in ci_workflow for macos USE_OCIO_SSE2NEON=OFF

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* typo

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Changing back all the macOS (except one) builds to x86_64 only as it takes double the time to do the universal build.
OCIO no longuer build a universal binary by default

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Update the CMakeLists.txt logic to accomodate all scenario and fixing documentations.

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

* Update documentation and remove ocio_use_sse2neon from the CI matrix

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>

---------

Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>
Signed-off-by: Mark Reid <mindmark@gmail.com>
Signed-off-by: Cédrik Fuoco <105517825+cedrik-fuoco-adsk@users.noreply.github.com>
Co-authored-by: Mark Reid <mindmark@gmail.com>
Co-authored-by: Doug Walker <doug.walker@autodesk.com>
2023-08-31 21:10:29 -04:00

678 lines
22 KiB
C++

// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#if OCIO_USE_SSE2
#include <sstream>
#include <OpenColorIO/OpenColorIO.h>
#include "MathUtils.h"
#include "SSE.h"
#include "testutils/UnitTest.h"
namespace OCIO = OCIO_NAMESPACE;
OCIO_ADD_TEST(SSE, sse2_log2_test)
{
const float values[8] = { 1e-010f, .1f, .5f, 1.f,
11.f, 112.f, 2425.f, 2e015f };
// The sse approx should have about 15 good digits of mantissa
const float rtol = powf(2.f, -14.f);
float cpuResult;
float sseResult[4];
__m128 mm_sseResult;
for (unsigned i = 0; i < 8; ++i)
{
cpuResult = logf(values[i]) / logf(2.f);
mm_sseResult = OCIO::sseLog2(_mm_set1_ps(values[i]));
_mm_storeu_ps(sseResult, mm_sseResult);
OCIO_CHECK_CLOSE(cpuResult, sseResult[0], rtol);
}
}
namespace
{
std::string GetErrorMessage(const std::string & operation, float expected, float actual)
{
std::ostringstream oss;
oss << "Output differs on " << operation << " : "
<< "expected: " << expected << " != " << "actual: " << actual;
return oss.str();
}
bool IsInfinity(float floatToTest)
{
const float posinf = std::numeric_limits<float>::infinity();
const float neginf = -std::numeric_limits<float>::infinity();
return (posinf == floatToTest
|| neginf == floatToTest);
}
void CheckFloat(const std::string& operation,
const float expected,
const float actual,
const unsigned precision)
{
if ((IsInfinity(expected) && IsInfinity(actual)) ||
(OCIO::IsNan(expected) && OCIO::IsNan(actual)))
{
return;
}
const float rtol = powf(2.f, -((float)precision));
OCIO_CHECK_ASSERT_MESSAGE(OCIO::EqualWithAbsError(expected, actual, rtol),
GetErrorMessage(operation, expected, actual));
}
void CheckSSE(const std::string & operation,
float expected,
float sseResult[4],
unsigned precision)
{
CheckFloat(operation, expected, sseResult[0], precision);
CheckFloat(operation, expected, sseResult[1], precision);
CheckFloat(operation, expected, sseResult[2], precision);
CheckFloat(operation, expected, sseResult[3], precision);
}
void CheckPower(const float base, const float exponent)
{
const float cpuResult = powf(base, exponent);
__m128 mm_sseResult = OCIO::ssePower(_mm_set1_ps(base), _mm_set1_ps(exponent));
float sseResult[4];
_mm_storeu_ps(sseResult, mm_sseResult);
std::ostringstream oss;
oss << "power(" << base << " , " << exponent << ")";
std::string operation = oss.str();
CheckSSE(operation, cpuResult, sseResult, 12);
}
} // anon.
OCIO_ADD_TEST(SSE, sse2_power_test)
{
const float values[] = {
1e-010f, .1f, .5f, 1.f,
.7f, .112f, .2425f, .3f
};
const unsigned num_values = sizeof(values) / sizeof(float);
for (unsigned i = 0; i < num_values; ++i)
{
CheckPower(values[i], 10.f);
}
}
namespace
{
unsigned GetULPDifference(const float a, const float b)
{
return abs((int)(OCIO::FloatAsInt(a) - OCIO::FloatAsInt(b)));
}
void EvaluateExp2(const float x, float* result)
{
__m128 mm_sseResult = OCIO::sseExp2(_mm_set1_ps(x));
_mm_storeu_ps(result, mm_sseResult);
}
bool AreAllInfinity(const float* sseResult)
{
return IsInfinity(sseResult[0]) &&
IsInfinity(sseResult[1]) &&
IsInfinity(sseResult[2]) &&
IsInfinity(sseResult[3]);
}
bool AreAllZero(const float* sseResult)
{
return (sseResult[0] == 0.0f) &&
(sseResult[1] == 0.0f) &&
(sseResult[2] == 0.0f) &&
(sseResult[3] == 0.0f);
}
bool AreAllInRange(const float* sseResult, const float lower_bound, const float upper_bound)
{
return ((sseResult[0] > lower_bound) && (sseResult[0] < upper_bound)) &&
((sseResult[1] > lower_bound) && (sseResult[1] < upper_bound)) &&
((sseResult[2] > lower_bound) && (sseResult[2] < upper_bound)) &&
((sseResult[3] > lower_bound) && (sseResult[3] < upper_bound));
}
bool AreAllClose(const float* sseResult, const float reference, const unsigned ulp_tolerance)
{
for (unsigned i = 0; i < 4; ++i)
{
if (GetULPDifference(sseResult[i], reference) > ulp_tolerance)
{
return false;
}
}
return true;
}
std::string GetOperation(const char* fct, const float arg1)
{
std::ostringstream oss;
oss << fct << "(" << arg1 << ")";
return oss.str();
}
std::string GetOperation(const char* fct, const float arg1, const float arg2)
{
std::ostringstream oss;
oss << fct << "(" << arg1 << " , " << arg2 << ")";
return oss.str();
}
std::string GetErrorMessage(const std::string& operation, const float expected, const float* actual)
{
std::ostringstream oss;
oss << "Output differs on " << operation << " : " << "result: [ "
<< actual[0] << " , " << actual[1] << " , " << actual[2] << " , " << actual[3]
<< " ], expected: " << expected;
return oss.str();
}
} // anon.
OCIO_ADD_TEST(SSE, sse2_exp2_test)
{
const unsigned ulp_tolerance = 50;
const float values[] = {
1e-5f, 1e-10f, 1e-15f, 1e-20f,
0.005f, 0.1f, 0.5f, 1.0f,
0.67f, 0.112f, 0.2425f, 0.33f,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
float sseResult[4];
// Check positive test values
for (unsigned i = 0; i < num_values; ++i)
{
const float expected = powf(2.0f, values[i]);
EvaluateExp2(values[i], sseResult);
OCIO_CHECK_ASSERT_MESSAGE(AreAllClose(sseResult, expected, ulp_tolerance),
GetErrorMessage(GetOperation("exp2", values[i]), expected, sseResult));
}
// Check negative test values
for (unsigned i = 0; i < num_values; ++i)
{
const float expected = powf(2.0f, -values[i]);
EvaluateExp2(-values[i], sseResult);
OCIO_CHECK_ASSERT_MESSAGE(AreAllClose(sseResult, expected, ulp_tolerance),
GetErrorMessage(GetOperation("exp2", -values[i]), expected, sseResult));
}
//
// Check for edge cases
//
// log2_max_float should be exactly 128.0f
const float log2_max_float = (float)(log((double)std::numeric_limits<float>::max()) / log(2.0));
// log2_min_float should be exactly -126.0f
const float log2_min_float = (float)(log((double)std::numeric_limits<float>::min()) / log(2.0));
// Check the log2_max_float and log2_min_float limits
{
EvaluateExp2(log2_max_float, sseResult);
OCIO_CHECK_ASSERT(AreAllInfinity(sseResult));
EvaluateExp2(log2_min_float, sseResult);
OCIO_CHECK_ASSERT(AreAllZero(sseResult));
}
// The valid domain of exp2 is actually reduced by one ULP
// Verify that the log2_max_float and log2_min_float limits, contracted by one ULP,
// return valid representable floating-point numbers.
//
// Note: We want log2_min_float_inside_one_ulp to be -125.9999..., but since addULP ignores the sign and
// just modifies the mantissa, we actually need to subtract one.
const float log2_max_float_inside_one_ulp = OCIO::AddULP(log2_max_float, -1);
const float log2_min_float_inside_one_ulp = OCIO::AddULP(log2_min_float, -1);
{
// The result should be a large number, but not infinity
// Create a tight bound for the large number based on the log2_max_float limit
const float large_threshold = (float)pow(2.0, (double)OCIO::AddULP(log2_max_float, -2));
EvaluateExp2(log2_max_float_inside_one_ulp, sseResult);
OCIO_CHECK_ASSERT(AreAllInRange(sseResult, large_threshold,
std::numeric_limits<float>::infinity()));
// The result should be a small number, but not zero
// Create a tight bound for the small number based on the log2_min_float limit
const float small_threshold = (float)pow(2.0, (double)OCIO::AddULP(log2_min_float, -2));
EvaluateExp2(log2_min_float_inside_one_ulp, sseResult);
OCIO_CHECK_ASSERT(AreAllInRange(sseResult, 0.0f, small_threshold));
}
// Verify that the log2_max_float and log2_min_float limits, expanded by one ULP,
// still return Infinity and zero, respectively.
//
// Note: As above, it is perhaps counter-intuitive, but we want to make
// log2_min_float_outside_one_ulp just slightly more negative than -126 and
// so need to increment the mantissa.
const float log2_max_float_outside_one_ulp = OCIO::AddULP(log2_max_float, 1);
const float log2_min_float_outside_one_ulp = OCIO::AddULP(log2_min_float, 1);
{
EvaluateExp2(log2_max_float_outside_one_ulp, sseResult);
OCIO_CHECK_ASSERT(AreAllInfinity(sseResult));
EvaluateExp2(log2_min_float_outside_one_ulp, sseResult);
OCIO_CHECK_ASSERT(AreAllZero(sseResult));
}
}
void EvaluateAtan(const float x, float* result)
{
__m128 mm_sseResult = OCIO::sseAtan(_mm_set1_ps(x));
_mm_storeu_ps(result, mm_sseResult);
}
OCIO_ADD_TEST(SSE, sse2_atan_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float tan_pi_3 = (float) 1.7320508075688772935274463415059;
const float tan_pi_4 = (float) 1.0;
const float tan_pi_6 = (float) 0.57735026918962576450914878050196;
const float tan_pi_12 = (float) 0.26794919243112270647255365849413;
const float values[] = {
0.0f, 1e-20f, 1e-10f, 1e-5f,
0.005f, 0.1f, 0.5f, 1.0f,
tan_pi_3, tan_pi_4, tan_pi_6, tan_pi_12,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
float sseResult[4];
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values; ++i)
{
const float x = sign_values[si] * values[i];
const float expected = atanf(x);
EvaluateAtan(x, sseResult);
const std::string operation = GetOperation("atan", x);
CheckSSE(operation, expected, sseResult, 14);
}
}
}
OCIO_ADD_TEST(SSE, scalar_atan_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float tan_pi_3 = (float) 1.7320508075688772935274463415059;
const float tan_pi_4 = (float) 1.0;
const float tan_pi_6 = (float) 0.57735026918962576450914878050196;
const float tan_pi_12 = (float) 0.26794919243112270647255365849413;
const float values[] = {
0.0f, 1e-20f, 1e-10f, 1e-5f,
0.005f, 0.1f, 0.5f, 1.0f,
tan_pi_3, tan_pi_4, tan_pi_6, tan_pi_12,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values; ++i)
{
const float x = sign_values[si] * values[i];
const float expected = atanf(x);
const float result = OCIO::sseAtan(x);
std::string operation = GetOperation("atan", x);
CheckFloat(operation, expected, result, 14);
}
}
}
void EvaluateAtan2(const float y, const float x, float* result)
{
__m128 mm_sseResult = OCIO::sseAtan2(_mm_set1_ps(y), _mm_set1_ps(x));
_mm_storeu_ps(result, mm_sseResult);
}
OCIO_ADD_TEST(SSE, sse2_atan2_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float tan_pi_3 = (float) 1.7320508075688772935274463415059;
const float tan_pi_4 = (float) 1.0;
const float tan_pi_6 = (float) 0.57735026918962576450914878050196;
const float tan_pi_12 = (float) 0.26794919243112270647255365849413;
const float values_x[] = {
0.0f, 1e-20f, 1e-15f, 1e-10f,
0.005f, 0.1f, 0.5f, 1.0f,
tan_pi_3, tan_pi_4, tan_pi_6, tan_pi_12,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values_x = sizeof(values_x) / sizeof(float);
const float values_y[] = {
0.0f, 1e-20f, 1e-15f, 1e-10f,
0.005f, 0.1f, 0.5f, 1.0f,
tan_pi_3, tan_pi_4, tan_pi_6, tan_pi_12,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values_y = sizeof(values_y) / sizeof(float);
float sseResult[4];
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values_x; ++i)
{
const float x = sign_values[si] * values_x[i];
for (unsigned sj = 0; sj < 2; ++sj)
{
for (unsigned j = 0; j < num_values_y; ++j)
{
const float y = sign_values[sj] * values_y[j];
const float expected = atan2f(y, x);
EvaluateAtan2(y, x, sseResult);
const std::string operation = GetOperation("atan2", y, x);
CheckSSE(operation, expected, sseResult, 14);
}
}
}
}
}
OCIO_ADD_TEST(SSE, scalar_atan2_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float tan_pi_3 = (float) 1.7320508075688772935274463415059;
const float tan_pi_4 = (float) 1.0;
const float tan_pi_6 = (float) 0.57735026918962576450914878050196;
const float tan_pi_12 = (float) 0.26794919243112270647255365849413;
const float values_x[] = {
0.0f, 1e-20f, 1e-15f, 1e-10f,
0.005f, 0.1f, 0.5f, 1.0f,
tan_pi_3, tan_pi_4, tan_pi_6, tan_pi_12,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values_x = sizeof(values_x) / sizeof(float);
const float values_y[] = {
0.0f, 1e-20f, 1e-15f, 1e-10f,
0.005f, 0.1f, 0.5f, 1.0f,
tan_pi_3, tan_pi_4, tan_pi_6, tan_pi_12,
1.5f, 3.2f, 7.11f, 13.23f,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values_y = sizeof(values_y) / sizeof(float);
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values_x; ++i)
{
const float x = sign_values[si] * values_x[i];
for (unsigned sj = 0; sj < 2; ++sj)
{
for (unsigned j = 0; j < num_values_y; ++j)
{
const float y = sign_values[sj] * values_y[j];
const float expected = atan2f(y, x);
const float result = OCIO::sseAtan2(y, x);
const std::string operation = GetOperation("atan2", y, x);
CheckFloat(operation, expected, result, 14);
}
}
}
}
}
void EvaluateCos(const float x, float* result)
{
__m128 mm_sseResult = OCIO::sseCos(_mm_set1_ps(x));
_mm_storeu_ps(result, mm_sseResult);
}
OCIO_ADD_TEST(SSE, sse2_cos_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float three_pi = (float) 9.4247779607693797153879301498385;
const float two_pi = (float) 6.283185307179586476925286766559;
const float pi = (float) 3.1415926535897932384626433832795;
const float pi_2 = (float) 1.5707963267948966192313216916398;
const float pi_3 = (float) 1.0471975511965977461542144610932;
const float pi_4 = (float) 0.78539816339744830961566084581988;
const float pi_6 = (float) 0.52359877559829887307710723054658;
const float pi_12 = (float) 0.26179938779914943653855361527329;
const float values[] = {
0.0f, 1e-20f, 1e-10f, 1e-5f,
0.005f, 0.1f, 0.5f, 1.0f,
0.67f, 0.112f, 0.2425f, 0.33f,
pi, pi_2, pi_3, pi_4,
pi_6, pi_12, two_pi, three_pi,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
float sseResult[4];
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values; ++i)
{
const float x = sign_values[si] * values[i];
const float expected = cosf(x);
EvaluateCos(x, sseResult);
const std::string operation = GetOperation("cos", x);
CheckSSE(operation, expected, sseResult, 16);
}
}
}
void EvaluateSin(const float x, float* result)
{
__m128 mm_sseResult = OCIO::sseSin(_mm_set1_ps(x));
_mm_storeu_ps(result, mm_sseResult);
}
OCIO_ADD_TEST(SSE, sse2_sin_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float three_pi = (float) 9.4247779607693797153879301498385;
const float two_pi = (float) 6.283185307179586476925286766559;
const float pi = (float) 3.1415926535897932384626433832795;
const float pi_2 = (float) 1.5707963267948966192313216916398;
const float pi_3 = (float) 1.0471975511965977461542144610932;
const float pi_4 = (float) 0.78539816339744830961566084581988;
const float pi_6 = (float) 0.52359877559829887307710723054658;
const float pi_12 = (float) 0.26179938779914943653855361527329;
const float values[] = {
0.0f, 1e-20f, 1e-10f, 1e-5f,
0.005f, 0.1f, 0.5f, 1.0f,
0.67f, 0.112f, 0.2425f, 0.33f,
pi, pi_2, pi_3, pi_4,
pi_6, pi_12, two_pi, three_pi,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
float sseResult[4];
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values; ++i)
{
const float x = sign_values[si] * values[i];
const float expected = sinf(x);
EvaluateSin(x, sseResult);
const std::string operation = GetOperation("sin", x);
CheckSSE(operation, expected, sseResult, 16);
}
}
}
void EvaluateSinCos(const float x, float* resultSin, float* resultCos)
{
__m128 sseResultSin, sseResultCos;
OCIO::sseSinCos(_mm_set1_ps(x), sseResultSin, sseResultCos);
_mm_storeu_ps(resultSin, sseResultSin);
_mm_storeu_ps(resultCos, sseResultCos);
}
OCIO_ADD_TEST(SSE, sse2_sin_cos_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float three_pi = (float) 9.4247779607693797153879301498385;
const float two_pi = (float) 6.283185307179586476925286766559;
const float pi = (float) 3.1415926535897932384626433832795;
const float pi_2 = (float) 1.5707963267948966192313216916398;
const float pi_3 = (float) 1.0471975511965977461542144610932;
const float pi_4 = (float) 0.78539816339744830961566084581988;
const float pi_6 = (float) 0.52359877559829887307710723054658;
const float pi_12 = (float) 0.26179938779914943653855361527329;
const float values[] = {
0.0f, 1e-20f, 1e-10f, 1e-5f,
0.005f, 0.1f, 0.5f, 1.0f,
0.67f, 0.112f, 0.2425f, 0.33f,
pi, pi_2, pi_3, pi_4,
pi_6, pi_12, two_pi, three_pi,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
float sseResultSin[4];
float sseResultCos[4];
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values; ++i)
{
const float x = sign_values[si] * values[i];
const float expectedSin = sinf(x);
const float expectedCos = cosf(x);
EvaluateSinCos(x, sseResultSin, sseResultCos);
const std::string operation = GetOperation("sincos", x);
CheckSSE(operation, expectedSin, sseResultSin, 16);
CheckSSE(operation, expectedCos, sseResultCos, 16);
}
}
}
OCIO_ADD_TEST(SSE, scalar_sin_cos_test)
{
const float sign_values[] = { -1.0f, 1.0f };
const float three_pi = (float) 9.4247779607693797153879301498385;
const float two_pi = (float) 6.283185307179586476925286766559;
const float pi = (float) 3.1415926535897932384626433832795;
const float pi_2 = (float) 1.5707963267948966192313216916398;
const float pi_3 = (float) 1.0471975511965977461542144610932;
const float pi_4 = (float) 0.78539816339744830961566084581988;
const float pi_6 = (float) 0.52359877559829887307710723054658;
const float pi_12 = (float) 0.26179938779914943653855361527329;
const float values[] = {
0.0f, 1e-20f, 1e-10f, 1e-5f,
0.005f, 0.1f, 0.5f, 1.0f,
0.67f, 0.112f, 0.2425f, 0.33f,
pi, pi_2, pi_3, pi_4,
pi_6, pi_12, two_pi, three_pi,
27.001f, 32.513f, 44.999f, 56.191f,
61.0019f, 77.7f, 83.654f, 98.989f
};
const unsigned num_values = sizeof(values) / sizeof(float);
float resultSin, resultCos;
for (unsigned si = 0; si < 2; ++si)
{
for (unsigned i = 0; i < num_values; ++i)
{
const float x = sign_values[si] * values[i];
const float expectedSin = sinf(x);
const float expectedCos = cosf(x);
OCIO::sseSinCos(x, resultSin, resultCos);
const std::string operation = GetOperation("sincos", x);
CheckFloat(operation, expectedSin, resultSin, 16);
CheckFloat(operation, expectedCos, resultCos, 16);
}
}
}
#endif