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.