SPRUIG6J January   2018  – December 2023

 

  1.   1
  2.   C7000 Host Emulation
  3. About This Document
    1. 1.1 Related Documentation
    2. 1.2 Disclaimer
    3. 1.3 Trademarks
  4. Getting Started with Host Emulation
    1. 2.1 System Requirements
    2. 2.2 Installation Instructions
    3. 2.3 Summary of Differences: Host Emulation Coding vs. Native C7000 Coding
  5. General Coding Requirements
    1. 3.1 Required Header Files
    2. 3.2 Package Dependencies
    3. 3.3 Example Program
  6. Intrinsics
    1. 4.1 OpenCL-Like Intrinsics
    2. 4.2 Streaming Address Generator Intrinsics
    3. 4.3 C6000 Legacy Intrinsics
    4. 4.4 Memory System Intrinsics
  7. TI Vector Types
    1. 5.1 Constructors
    2. 5.2 Accessors
    3. 5.3 Vector Operators
    4. 5.4 Print Debug Function
  8. Streaming Engine and Streaming Address Generator
  9. Lookup Table and Histogram Interface
    1. 7.1 Lookup Table and Histogram Data
  10. C6000 Migration
    1. 8.1 __float2_t Legacy Data Type
  11. Matrix Multiply Accelerator (MMA) Interface
  12. 10Compiler Errors and Warnings
    1. 10.1 Key Terms Found in Compiler Errors and Warnings
    2. 10.2 Host Emulation Specific Syntax
  13. 11Revision History
  14.   35

__float2_t Legacy Data Type

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.

Table 8-1 Legacy Intrinsics with Distinct Definitions in Host Emulation
Intrinsic NamePrevious DefinitionFunction
_ftof2_ftodConstruct __float2_t type from 2 floating point values
_lltof2_lltodConvert long long values to __float2_t type
_f2toll_dtollConvert __float2_t type to long long
_hif2_hifAccess high 32-bit float from __float2_t type
_lof2_lofAccess low 32-bit float from __float2_t type
_fdmv_f2_fdmvAlternative to using PACK instruction to construct __float2_type from 2 floats
_fdmvd_f2_fdmvdAlternative to using PACKWDLY4 instruction to construct __float2_type from 2 flaots
_hif2_128_hid128Access high __float2_t type from __x128_t type
_lof2_128_lod128Access low __float2_t type from __x128_t type
_f2to128_dto128Construct __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;
}