3.4. Intrinsics and Built-in Functions¶
The compiler intrinsics supported by the armcl compiler are fully detailed in the Arm Optimizing C/C++ Compiler User’s Guide in section 5.13.
To make the use of compiler intrinsics in your C/C++ source file more portable, it is recommended that they be written in compliance with the Arm C Language Extensions - Release ACLE Q2 2018 specification when at all possible. Both the armcl and tiarmclang compilers are shipped with their own versions of the arm_acle.h header which must be included in a C/C++ compilation unit before the first reference to an ACLE compiler intrinsic in a C/C++ source file.
This section of the “Migrating C and C++ Source Code” chapter of the migration guide walks through all of compiler intrinsics supported by the armcl compiler explaining how many can be converted into a form that can be successfully compiled with the tiarmclang compiler. There are several armcl intrinsics that do not have a functionally equivalent form that is supported by the tiarmclang compiler.
3.4.1. ACLE Compiler Intrinsics¶
This section of the “Migrating C and C++ Source Code” chapter will describe how many of the intrinsics that are supported by the armcl compiler can be converted to their functionally equivalent ACLE form. Some armcl intrinsics are already ACLE compliant and some may not have a functionally equivalent ACLE counterpart.
In general, you should refer to the Arm Optimizing C/C++ Compiler User’s Guide (section 5.13) to find the armcl intrinsic that needs to be converted and then consult the Arm C Language Extensions - Release ACLE Q2 2018 specification to find the armcl intrinsic’s ACLE counterpart, if one exists.
The remainder of this section will show some examples of arcml intrinsics that can be converted into their ACLE form.
3.4.1.1. Renaming¶
Many of the armcl-specific compiler intrinsics can be converted into ACLE compliant form simply by renaming the intrinsic in the C/C++ source file. For example, a C/C++ source file that contains a reference to the armcl’s _qaddsubx intrinsic can be made ACLE compliant by including the arm_acle.h header file before the reference to the intrinsic in the compilation unit and renaming _qaddsubx to the ACLE name for the same intrinsic, __qasx.
The following table lists those armcl-specific compiler intrinsics that can be converted simply by including the arm_acle.h header file in the compilation unit and using the ACLE name for the intrinsic in place of its armcl-specific name (note that in many cases, the only difference between the armcl and ACLE names for an intrinsic is that the ACLE name uses an additional underscore in the beginning of the name):
armcl Intrinsic Name |
ACLE Intrinsic Name |
---|---|
_smulbb |
__smulbb |
_smulbt |
__smulbt |
_smultb |
__smultb |
_smultt |
__smultt |
_smulwb |
__smulwb |
_smulwt |
__smulwt |
_sadd |
__qadd |
_ssub |
__qsub |
_smlabb |
__smlabb |
_smlabt |
__smlabt |
_smlatb |
__smlatb |
_smlatt |
__smlatt |
_smlawb |
__smlawb |
_smlawt |
__smlawt |
_ssat16 |
__ssat16 |
_usat16 |
__usat16 |
_sel |
__sel |
_qadd8 |
__qadd8 |
_qsub8 |
__qsub8 |
_sadd8 |
__sadd8 |
_shadd8 |
__shadd8 |
_shsub8 |
__shsub8 |
_ssub8 |
__ssub8 |
_uadd8 |
__uadd8 |
_uhadd8 |
__uhadd8 |
_uhsub8 |
__uhsub8 |
_uqadd8 |
__uqadd8 |
_uqsub8 |
__uqsub8 |
_usub8 |
__usub8 |
_usad8 |
__usad8 |
_qadd16 |
__qadd16 |
_qaddsubx |
__qasx |
_qsubaddx |
__qsax |
_qsub16 |
__qsub16 |
_sadd16 |
__sadd16 |
_saddsubx |
__sasx |
_shadd16 |
__shadd16 |
_shaddsubx |
__shasx |
_shsubaddx |
__shsax |
_shsub16 |
__shsub16 |
_ssubaddx |
__ssax |
_ssub16 |
__ssub16 |
_uadd16 |
__uadd16 |
_uaddsubx |
__uasx |
_uhadd16 |
__uhadd16 |
_uhaddsubx |
__uhasx |
_uhsubaddx |
__uhsax |
_uhsub16 |
__uhsub16 |
_uqadd16 |
__uqadd16 |
_uqaddsubx |
_uqasx |
_uqsubaddx |
__uqsax |
_uqsub16 |
__uqsub16 |
_usubaddx |
__usax |
_usub16 |
__usub16 |
_smuad |
__smuad |
_smuadx |
__smuadx |
_smusd |
__smusd |
_smusdx |
__smusdx |
_MCR |
__arm_mcr |
_MCR2 |
__arm_mcr2 |
_MCRR |
__arm_mcrr |
_MCRR2 |
__arm_mcrr2 |
_MRC |
__arm_mrc |
_MRC2 |
_arm_mrc2 |
_MRRC |
__arm_mrrc |
_MRRC2 |
__arm_mrrc2 |
3.4.1.2. Conversions that Require More Attention¶
Here are a couple of examples of armcl intrinsics that require some more work than just renaming the intrinsic:
_dmb -> __dmb
armcl intrinsic form
void _dmb(void);
ACLE intrinsic form
void __dmb(unsigned int k);
In this case, the ACLE form takes an unsigned int constant argument that is encoded into the 4-bit “option” field of the DMB instruction’s opcode. The armcl’s _dmb intrinsic implicitly encodes 0xf into this “option” field.
_usata -> __ssat
armcl intrinsic form
uint32_t _usata(int32_t x, unsigned int shift, unsigned int k);
ACLE intrinsic form
int32_t __ssat(int32_t x, unsigned int k);
In this case, the conversion can be cleanly made if the shift operand to armcl’s _ssata intrinsic is zero. That is, armcl’s “_ssata(x,0,k)” is equivalent to the ACLE “__ssat(x,k)”. However, if the armcl intrinsic uses a non-zero shift, you will need to define _ssata as a function (see the ti_compatibility.h header file for an example implementation).
3.4.1.3. Some armcl Intrinsics May Just Need the arm_acle.h Header to be Included¶
Some armcl intrinsics are already ACLE compliant, but since the tiarmclang compiler does not implicitly declare intrinsics, you must #include the arm_acle.h header file in your source file prior to the first use of an ACLE intrinsic.
Here are a few examples of such intrinsics:
__nop
void __nop(void);
__rev16
uint32_t __rev16(uint32_t x);
__ror
uint32_t __ror(uint32_t x, uint32_t y);
3.4.2. Non-ACLE Compiler Intrinsics¶
This section will account for non-ACLE intrinsics that are supported by the armcl compiler. Many of these intrinsics can be made available in an application built with the tiarmclang compiler by including the ti_compatibility.h header file in your source file prior to the use of a given non-ACLE intrinsic.
The following is a list of a few of the non-ACLE compiler intrinsics supported by armcl that require conversion to a form that tiarmclang supports. Each item indicates the name of the armcl intrinsic followed by the form of the non-ACLE intrinsic. The definition of each armcl intrinsic listed can be found in the tiarmclang compiler’s ti_compatibility.h header file. For a full list of armcl’s non-ACLE intrinsics that are supported, please refer to the tiarmclang’s ti_compatibility.h header file.
_abs_s
int dst = _abs_s(int src);
__bitband
char *dst = __bitband(void *x, unsigned int y, unsigned int z);
_call_swi
void _call_swi(unsigned int src);
__curpc
void *dst = __curpc(void);
_disable_FIQ
unsigned int cpsr = _disable_FIQ(void);
_disable_IRQ
unsigned int pri = _disable_IRQ(void);
_disable_interrupts
unsigned int fmsk = _disable_interrupts(void);
_enable_FIQ
unsigned int cpsr = _enable_FIQ(void);
_enable_IRQ
unsigned int pri = _enable_IRQ(void);
_enable_interrupts
unsigned int fmsk = _enable_interrupts(void);
__get_PRIMASK
unsigned int dst = __get_PRIMASK(void);
__ldrex
float dst= _itof(unsigned int src);
3.4.2.1. Non-ACLE armcl Compiler Intrinsics Not Supported in tiarmclang¶
The following non-ACLE compiler intrinsics are supported in the armcl compiler, but have no viable form that is supported in tiarmclang nor are they supported in the ti_compatibility.h header file:
_addc
_delay_cycles
__sqrt
__sqrtf
_subc
3.4.2.2. Accessing armcl Compiler Intrinsics Via the ti_compatibility.h Header File¶
The idea behind the ti_compatibility.h header file that you can find in the /include area of your tiarmclang tools installation is to define armcl-specific compiler intrinsics that are not available in tiarmclang in terms of macros or static functions that are always inlined. Where applicable, the ACLE equivalent forms of the armcl compiler intrinsics will be used.
For example, suppose a C/C++ source file references armcl’s _smpy compiler intrinsic. The ti_compatibility.h header file can be included in the C/C++ source file before the reference to _smpy. When the C/C++ source file is compiled with tiarmclang, the relevant code from ti_compatibility.h kicks in and the static function named _smpy defined in ti_compatibility.h will be inlined at each point where the _smpy intrinsic is referenced in the C/C++ source code.
All of the armcl compiler intrinsics, including both ACLE-related and non-ACLE-related intrinsics, that are mentioned in the above discussions as having a viable conversion to a form that is compatible with tiarmclang are represented in the ti_compatibility.h header file that is included with the tiarmclang tools installation. That is, you can find a definition of each armcl-specific intrinsic that has a viable conversion in the ti_compatibility.h header file. Each such armcl intrinsic is defined via a macro or a static function that is always inlined. Please see the ti_compatibility.h header file itself for more details about how each conversion is implemented.