conversions: Use ARM emulation for aarch64 (#967)

The host compiler will not always calculate reference values
the same, depending on optimization level.  It generates
instructions that do not respond to CPU rounding mode in
the same way.  Use QCOM rounding mode emulation to correctly
calculate reference values on aarch64.
This commit is contained in:
Sreelakshmi Haridas Maruthur
2020-10-19 16:08:06 -06:00
committed by GitHub
parent 90c9ea5d7c
commit b165de7649
3 changed files with 38 additions and 20 deletions

View File

@@ -4,7 +4,7 @@ set (${MODULE_NAME}_SOURCES
Sleep.cpp test_conversions.cpp basic_test_conversions.cpp
)
if("${CLConform_TARGET_ARCH}" STREQUAL "ARM")
if("${CLConform_TARGET_ARCH}" STREQUAL "ARM" OR "${CLConform_TARGET_ARCH}" STREQUAL "ARM64")
list(APPEND ${MODULE_NAME}_SOURCES fplib.cpp)
endif()

View File

@@ -21,11 +21,11 @@
#include "harness/mt19937.h"
#if defined( __arm__ ) && defined( __GNUC__ )
#if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
#include "fplib.h"
#endif
#if defined( __arm__ ) && defined( __GNUC__ )
#if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
/* Rounding modes and saturation for use with qcom 64 bit to float conversion library */
bool qcom_sat;
roundingMode qcom_rm;
@@ -759,12 +759,18 @@ static void ulong2float( void *out, void *in)
((float*) out)[0] = (l == 0 ? 0.0f : (((cl_long)l < 0) ? result * 2.0f : result));
#else
cl_ulong l = ((cl_ulong*) in)[0];
#if defined( __arm__ ) && defined( __GNUC__ )
/* ARM VFP doesn't have hardware instruction for converting from 64-bit integer to float types, hence GCC ARM uses the floating-point emulation code
* despite which -mfloat-abi setting it is. But the emulation code in libgcc.a has only one rounding mode (round to nearest even in this case)
#if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
/* ARM VFP doesn't have hardware instruction for converting from 64-bit
* integer to float types, hence GCC ARM uses the floating-point emulation
* code despite which -mfloat-abi setting it is. But the emulation code in
* libgcc.a has only one rounding mode (round to nearest even in this case)
* and ignores the user rounding mode setting in hardware.
* As a result setting rounding modes in hardware won't give correct rounding results for type covert from 64-bit integer to float using GCC for ARM compiler
* so for testing different rounding modes, we need to use alternative reference function */
* As a result setting rounding modes in hardware won't give correct
* rounding results for type covert from 64-bit integer to float using GCC
* for ARM compiler so for testing different rounding modes, we need to use
* alternative reference function. ARM64 does have an instruction, however
* we cannot guarantee the compiler will use it. On all ARM architechures
* use emulation to calculate reference.*/
((float*) out)[0] = qcom_u64_2_f32(l, qcom_sat, qcom_rm);
#else
((float*) out)[0] = (l == 0 ? 0.0f : (float) l); // Per IEEE-754-2008 5.4.1, 0's always convert to +0.0
@@ -806,12 +812,18 @@ static void long2float( void *out, void *in)
((float*) out)[0] = (l == 0 ? 0.0f : result); // Per IEEE-754-2008 5.4.1, 0's always convert to +0.0
#else
cl_long l = ((cl_long*) in)[0];
#if defined( __arm__ ) && defined( __GNUC__ )
/* ARM VFP doesn't have hardware instruction for converting from 64-bit integer to float types, hence GCC ARM uses the floating-point emulation code
* despite which -mfloat-abi setting it is. But the emulation code in libgcc.a has only one rounding mode (round to nearest even in this case)
#if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
/* ARM VFP doesn't have hardware instruction for converting from 64-bit
* integer to float types, hence GCC ARM uses the floating-point emulation
* code despite which -mfloat-abi setting it is. But the emulation code in
* libgcc.a has only one rounding mode (round to nearest even in this case)
* and ignores the user rounding mode setting in hardware.
* As a result setting rounding modes in hardware won't give correct rounding results for type covert from 64-bit integer to float using GCC for ARM compiler
* so for testing different rounding modes, we need to use alternative reference function */
* As a result setting rounding modes in hardware won't give correct
* rounding results for type covert from 64-bit integer to float using GCC
* for ARM compiler so for testing different rounding modes, we need to use
* alternative reference function. ARM64 does have an instruction, however
* we cannot guarantee the compiler will use it. On all ARM architechures
* use emulation to calculate reference.*/
((float*) out)[0] = (l == 0 ? 0.0f : qcom_s64_2_f32(l, qcom_sat, qcom_rm));
#else
((float*) out)[0] = (l == 0 ? 0.0f : (float) l); // Per IEEE-754-2008 5.4.1, 0's always convert to +0.0

View File

@@ -65,7 +65,7 @@
#define kCallStyleCount (kVectorSizeCount + 1 /* for implicit scalar */)
#if defined( __arm__ ) && defined( __GNUC__ )
#if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
#include "fplib.h"
extern bool qcom_sat;
extern roundingMode qcom_rm;
@@ -884,12 +884,18 @@ cl_int PrepareReference( cl_uint job_id, cl_uint thread_id, void *p )
if( info->sat )
f = gSaturatedConversions[ outType ][ inType ];
#if defined( __arm__ ) && defined( __GNUC__ )
/* ARM VFP doesn't have hardware instruction for converting from 64-bit integer to float types, hence GCC ARM uses the floating-point emulation code
* despite which -mfloat-abi setting it is. But the emulation code in libgcc.a has only one rounding mode (round to nearest even in this case)
* and ignores the user rounding mode setting in hardware.
* As a result setting rounding modes in hardware won't give correct rounding results for type covert from 64-bit integer to float using GCC for ARM compiler
* so for testing different rounding modes, we need to use alternative reference function */
#if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
/* ARM VFP doesn't have hardware instruction for converting from 64-bit
* integer to float types, hence GCC ARM uses the floating-point
* emulation code despite which -mfloat-abi setting it is. But the
* emulation code in libgcc.a has only one rounding mode (round to
* nearest even in this case) and ignores the user rounding mode setting
* in hardware. As a result setting rounding modes in hardware won't
* give correct rounding results for type covert from 64-bit integer to
* float using GCC for ARM compiler so for testing different rounding
* modes, we need to use alternative reference function. ARM64 does have
* an instruction, however we cannot guarantee the compiler will use it.
* On all ARM architechures use emulation to calculate reference.*/
switch (round)
{
/* conversions to floating-point type use the current rounding mode.