SPRUIG6K January 2018 – March 2024
With the C7000 compiler, the
__float2_t
legacy type is treated as a
double
at all times. This is valid with the C7000 compiler as a double is 64-bits wide and can fit two 32-bit floating point elements for use with SIMD operations.
This is not the case when using host systems that execute on Intel x86 architectures. When performing loads and stores of doubles on Intel x86 machines, there is an automatic conversion that takes place to convert a 64-bit double to an 80-bit “extended-real” type. This presents a problem when a double is used to store two distinct 32-bit floating point values as normalization can occur on the 80-bit “extended-real” types, which changes the bits stored in memory. If an extension to an 80-bit type with normalization is done on a double that represents two 32-bit floating point types, then the data can no longer be guaranteed and SIMD operations that expect two floating point values will have inconsistent results.
To solve this problem, C7000 Host Emulation contains a separate class definition for the
__float2_t
type that is treated as an opaque container type. Container types can only be modified, accessed, and initialized using special intrinsics. While the
__float2_t
class definition contains public accessor methods, it is recommended that only intrinsics are used to modify
__float2_t
types as any member of the C7000 Host Emulation
__float2_t
type will be undefined with the C7000 compiler. The
__float2_t
class type should be used when a single data structure that represents two 32-bit floating point values is required in a legacy intrinsic. When writing C7000 Host Emulation code that utilizes C6000 legacy constructs, a
double
type should only be used to represent one double precision floating point value.
As a result of having a separate definition for the
__float2_t
type, the
_ftof2
intrinsic must be used to construct a
__float2_t
type. With the C7000 compiler, this intrinsic is defined as
_ftod
which creates a double type from two floating pointer arguments. The accessor methods for
__float2_t
are defined in the same manner.
Table 8-1 lists the intrinsics that are distinctly defined for C7000 Host Emulation. Despite the distinctions made in the definitions of the intrinsics listed in this table, legacy code written for C7000 Host Emulation can be transferred to the C7000 compiler without change.
Intrinsic Name | Previous Definition | Function |
_ftof2 | _ftod | Construct __float2_t type from 2 floating point values |
_lltof2 | _lltod | Convert long long values to __float2_t type |
_f2toll | _dtoll | Convert __float2_t type to long long |
_hif2 | _hif | Access high 32-bit float from __float2_t type |
_lof2 | _lof | Access low 32-bit float from __float2_t type |
_fdmv_f2 | _fdmv | Alternative to using PACK instruction to construct __float2_type from 2 floats |
_fdmvd_f2 | _fdmvd | Alternative to using PACKWDLY4 instruction to construct __float2_type from 2 flaots |
_hif2_128 | _hid128 | Access high __float2_t type from __x128_t type |
_lof2_128 | _lod128 | Access low __float2_t type from __x128_t type |
_f2to128 | _dto128 | Construct __x128_t type from 2 __float2_t types |
The following examples construct and set
__float2_t
variables in valid and invalid ways as indicated in the comments.
/* __float2_t type examples: Host Emulation Code */
#include <c7x.h>
#include <c6x_migration.h>
int main(){
// Valid ways to construct a __float2_t
__float2_t src1 = _ftof2(1.1022, 2.1010);
__float2_t src2 = _ftof2(-1.1, 4.10101);
// Invalid way to construct a __float2_t in Host Emulation
// __float2_t from_double = (double)1.0;
// Legal to set a __float2_t from other pre-constructed
// __float2_t types (done using intrinsic)
src1 = src2;
// It is illegal to set a __float2_t type via a
// constructor call. The following will not compile:
// src1 = __float2_t(1.0, 2.0);
// Correct way to access lo/hi
float lo_correct = _lof2(src1);
// Intrinsic use example
__float2_t res = _daddsp(src1, src2);
return 0;
}