ARM Optimizing
C/C++ Compiler
v16.12.0.STS User's Guide
SPNU151N - REVISED DECEMBER 2016
5 ARM C/C++ Language Implementation
The C/C++ compiler supports the C/C++ language standard that was developed by a committee of the American National Standards Institute (ANSI) and subsequently adopted by the International Standards Organization (IS0).
The C++ language supported by the ARM is defined by the ANSI/ISO/IEC 14882:2003 standard with certain exceptions.
5.1 Characteristics of ARM C
The C compiler supports the 1989 and 1999 versions of the C language:
- C89. Compiling with the --c89 option causes the compiler to conform to the ISO/IEC 9899:1990 C standard, which was previously ratified as ANSI X3.159-1989. The names "C89" and "C90" refer to the same programming language. "C89" is used in this document.
- C99. Compiling with the --c99 option causes the compiler to conform to the ISO/IEC 9899:1999 C standard. This standard supports several features not part of C89, such as inline functions, new data types, and one-line comments beginning with //.
The C language is also described in the second edition of Kernighan and Ritchie's The C Programming Language (K&R). The compiler can also accept many of the language extensions found in the GNU C compiler (see Section 5.16).
The compiler supports some features of C99 in the default relaxed ANSI mode with C89 support. It supports all language features of C99 in C99 mode. See Section 5.15.
The ANSI/ISO standard identifies some features of the C language that may be affected by characteristics of the target processor, run-time environment, or host environment. This set of features can differ among standard compilers.
Unsupported features of the C library are:
- The run-time library has minimal support for wide and multibyte characters. The type wchar_t is implemented as unsigned short (16 bits), but can be an int if you set the --wchar_t=32 option. The wide character set is equivalent to the set of values of type char. The library includes the header files <wchar.h> and <wctype.h>, but does not include all the functions specified in the standard.
- The run-time library includes the header file <locale.h>, but with a minimal implementation. The only supported locale is the C locale. That is, library behavior that is specified to vary by locale is hard-coded to the behavior of the C locale, and attempting to install a different locale by way of a call to setlocale() will return NULL.
- Some run-time functions and features in the C99 specification are not supported. See Section 5.15.
5.1.1 Implementation-Defined Behavior
The C standard requires that conforming implementations provide documentation on how the compiler handles instances of implementation-defined behavior.
The TI compiler officially supports a freestanding environment. The C standard does not require a freestanding environment to supply every C feature; in particular the library need not be complete. However, the TI compiler strives to provide most features of a hosted environment.
The section numbers in the lists that follow correspond to section numbers in Appendix J of the C99 standard. The numbers in parentheses at the end of each item are sections in the C99 standard that discuss the topic. Certain items listed in Appendix J of the C99 standard have been omitted from this list.
J.3.1 Translation
- The compiler and related tools emit diagnostic messages with several distinct formats. Diagnostic messages are emitted to stderr; any text on stderr may be assumed to be a diagnostic. If any errors are present, the tool will exit with an exit status indicating failure (non-zero). (3.10, 5.1.1.3)
- Nonempty sequences of white-space characters are preserved and are not replaced by a single space character in translation phase 3. (5.1.1.2)
J.3.2 Environment
- The compiler does not support multibyte characters in identifiers, so there is no mapping from multibyte characters to the source character set. However, the compiler accepts multibyte characters in comments, string literals, and character constants in the physical source file. (5.1.1.2)
- The name of the function called at program startup is "main" (5.1.2.1)
- Program termination does not affect the environment; there is no way to return an exit code to the environment. By default, the program is known to have halted when execution reaches the special C$$EXIT label. (5.1.2.1)
- In relaxed ANSI mode, the compiler accepts "void main(void)" and "void main(int argc, char *argv[])" as alternate definitions of main. The alternate definitions are rejected in strict ANSI mode. (5.1.2.2.1)
- If space is provided for program arguments at link time with the --args option and the program is run under a system that can populate the .args section (such as CCS), argv[0] will contain the filename of the executable, argv[1] through argv[argc-1] will contain the command-line arguments to the program, and argv[argc] will be NULL. Otherwise, the value of argv and argc are undefined. (5.1.2.2.1)
- Interactive devices include stdin, stdout, and stderr (when attached to a system that honors CIO requests). Interactive devices are not limited to those output locations; the program may access hardware peripherals that interact with the external state. (5.1.2.3)
- Signals are not supported. The function signal is not supported. (7.14) (7.14.1.1)
- The library function getenv is implemented through the CIO interface. If the program is run under a system that supports CIO, the system performs getenv calls on the host system and passes the result back to the program. Otherwise the operation of getenv is undefined. No method of changing the environment from inside the target program is provided. (7.20.4.5)
- The system function is not supported. (7.20.4.6).
J.3.3. Identifiers
- The compiler does not support multibyte characters in identifiers. (6.4.2)
- The number of significant initial characters in an identifier is unlimited. (5.2.4.1, 6.4.2)
J.3.4 Characters
- The number of bits in a byte (CHAR_BIT) is 8. See Section 5.5 for details about data types. (3.6)
- The execution character set is the same as the basic execution character set: plain ASCII. Characters in the ISO 8859 extended character set are also supported. (5.2.1)
- The values produced for the standard alphabetic escape sequences are as follows: (5.2.2)
- The value of a char object into which any character other than a member of the basic execution character set has been stored is the ASCII value of that character. (6.2.5)
- Plain char is identical to unsigned char, but can be changed to signed char with the --plain_char=signed option. (6.2.5, 6.3.1.1)
- The source character set and execution character set are both plain ASCII, so the mapping between them is one-to-one. The compiler does accept multibyte characters in comments, string literals, and character constants. (6.4.4.4, 5.1.1.2)
- The compiler currently supports only one locale, "C". (6.4.4.4).
- The compiler currently supports only one locale, "C". (6.4.5).
Escape Sequence | ASCII Meaning | Integer Value |
---|---|---|
\a | BEL (bell) | 7 |
\b | BS (backspace) | 8 |
\f | FF (form feed) | 12 |
\n | LF (line feed) | 10 |
\r | CR (carriage return) | 13 |
\t | HT (horizontal tab) | 9 |
\v | VT (vertical tab) | 11 |
J.3.5 Integers
- No extended integer types are provided. (6.2.5)
- Integer types are represented as two's complement, and there are no trap representations. (6.2.6.2)
- No extended integer types are provided, so there is no change to the integer ranks. (6.3.1.1)
- When an integer is converted to a signed integer type which cannot represent the value, the value is truncated (without raising a signal) by discarding the bits which cannot be stored in the destination type; the lowest bits are not modified. (6.3.1.3)
- Right shift of a signed integer value performs an arithmetic (signed) shift. The bitwise operations other than right shift operate on the bits in exactly the same way as on an unsigned value. That is, after the usual arithmetic conversions, the bitwise operation is performed without regard to the format of the integer type, in particular the sign bit. (6.5)
J.3.6 Floating point
- The accuracy of floating-point operations (+ - * /) is bit-exact. The accuracy of library functions that return floating-point results is not specified. (5.2.4.2.2)
- The compiler does not provide non-standard values for FLT_ROUNDS (5.2.4.2.2)
- The compiler does not provide non-standard negative values of FLT_EVAL_METHOD (5.2.4.2.2)
- The rounding direction when an integer is converted to a floating-point number is IEEE-754 "round to even". (6.3.1.4)
- The rounding direction when a floating-point number is converted to a narrower floating-point number is IEEE-754 "round to even". (6.3.1.5)
- For floating-point constants that are not exactly representable, the implementation uses the nearest representable value. (6.4.4.2)
- The compiler does not contract float expressions. (6.5)
- The default state for the FENV_ACCESS pragma is off. (7.6.1)
- The TI compiler does not define any additional float exceptions (7.6, 7.12)
- The default state for the FP_CONTRACT pragma is off. (7.12.2)
- The "inexact" floating-point exception cannot be raised if the rounded result equals the mathematical result. (F.9)
- The "underflow" and "inexact" floating-point exceptions cannot be raised if the result is tiny but not inexact. (F.9)
J.3.7 Arrays and pointers
- When converting a pointer to an integer or vice versa, the pointer is considered an unsigned integer of the same size, and the normal integer conversion rules apply.
- When converting a pointer to an integer or vice versa, if the bitwise representation of the destination can hold all of the bits in the bitwise representation of the source, the bits are copied exactly. (6.3.2.3)
- The size of the result of subtracting two pointers to elements of the same array is the size of ptrdiff_t, which is defined in Section 5.5. (6.5.6)
J.3.8 Hints
- When the optimizer is used, the register storage-class specifier is ignored. When the optimizer is not used, the compiler will preferentially place register storage class objects into registers to the extent possible. The compiler reserves the right to place any register storage class object somewhere other than a register. (6.7.1)
- The inline function specifier is ignored unless the optimizer is used. For other restrictions on inlining, see Section 2.11.3. (6.7.4)
J.3.9 Structures, unions, enumerations, and bit-fields
- A "plain" int bit-field is treated as a signed int bit-field. (6.7.2, 6.7.2.1)
- In addition to _Bool, signed int, and unsigned int, the compiler allows char, signed char, unsigned char, signed short, unsigned shot, signed long, unsigned long, signed long long, unsigned long long, and enum types as bit-field types. (6.7.2.1)
- Bit-fields may not straddle a storage-unit boundary.(6.7.2.1)
- Bit-fields are allocated in endianness order within a unit. See Section 6.2.2. (6.7.2.1)
- Non-bit-field members of structures are aligned as specified in See Section 6.2.1. (6.7.2.1)
- The integer type underlying each enumerated type is described in Section 5.5.1. (6.7.2.2)
J.3.10 Qualifiers
- The TI compiler does not shrink or grow volatile accesses. It is the user's responsibility to make sure the access size is appropriate for devices that only tolerate accesses of certain widths. The TI compiler does not change the number of accesses to a volatile variable unless absolutely necessary. This is significant for read-modify-write expressions such as += ; for an architecture which does not have a corresponding read-modify-write instruction, the compiler will be forced to use two accesses, one for the read and one for the write. Even for architectures with such instructions, it is not guaranteed that the compiler will be able to map such expressions to an instruction with a single memory operand. It is not guaranteed that the memory system will lock that memory location for the duration of the instruction. In a multi-core system, some other core may write the location after a RMW instruction reads it, but before it writes the result. The TI compiler will not reorder two volatile accesses, but it may reorder a volatile and a non-volatile access, so volatile cannot be used to create a critical section. Use some sort of lock if you need to create a critical section. (6.7.3)
J.3.11 Preprocessing directives
- Include directives may have one of two forms, " " or < >. For both forms, the compiler will look for a real file on-disk by that name using the include file search path. See Section 2.5.2. (6.4.7).
- The value of a character constant in a constant expression that controls conditional inclusion matches the value of the same character constant in the execution character set (both are ASCII). (6.10.1).
- The compiler uses the file search path to search for an included < > delimited header file. See Section 2.5.2. (6.10.2).
- he compiler uses the file search path to search for an included " " delimited header file. See Section 2.5.2. (6.10.2). (6.10.2).
- There is no arbitrary nesting limit for #include processing. (6.10.2).
- See Section 5.10 for a description of the recognized non-standard pragmas. (6.10.6).
- The date and time of translation are always available from the host. (6.10.8).
J.3.12 Library functions
- Almost all of the library functions required for a hosted implementation are provided by the TI library, with exceptions noted in Section 5.15.1. (5.1.2.1).
- The format of the diagnostic printed by the assert macro is "Assertion failed, (assertion macro argument), file file, line line". (7.2.1.1).
- No strings other than "C" and "" may be passed as the second argument to the setlocale function (7.11.1.1).
- No signal handling is supported. (7.14.1.1).
- The +INF, -INF, +inf, -inf, NAN, and nan styles can be used to print an infinity or NaN. (7.19.6.1, 7.24.2.1).
- The output for %p conversion in the fprintf or fwprintf function is the same as %x of the appropriate size. (7.19.6.1, 7.24.2.1).
- The termination status returned to the host environment by the abort, exit, or _Exit function is not returned to the host environment. (7.20.4.1, 7.20.4.3, 7.20.4.4).
- The system function is not supported. (7.20.4.6).
J.3.13 Architecture
- The values or expressions assigned to the macros specified in the headers float.h, limits.h, and stdint.h are described along with the sizes and format of integer types are described in Section 5.5. (5.2.4.2, 7.18.2, 7.18.3)
- The number, order, and encoding of bytes in any object are described in Section 6.2.1. (6.2.6.1)
- The value of the result of the sizeof operator is the storage size for each type, in terms of bytes. See Section 6.2.1. (6.5.3.4)
5.2 Characteristics of ARM C++
The ARM compiler supports C++ as defined in the ANSI/ISO/IEC 14882:2003 standard, including these features:
- Complete C++ standard library support, with exceptions noted below.
- Templates
- Exceptions, which are enabled with the --exceptions option; see Section 5.7.
- Run-time type information (RTTI), which can be enabled with the --rtti compiler option.
The exceptions to the standard are as follows:
- The compiler does not support embedded C++ run-time-support libraries.
- The library supports wide chars (wchar_t), in that template functions and classes that are defined for char are also available for wchar_t. For example, wide char stream classes wios, wiostream, wstreambuf and so on (corresponding to char classes ios, iostream, streambuf) are implemented. However, there is no low-level file I/O for wide chars. Also, the C library interface to wide char support (through the C++ headers <cwchar> and <cwctype>) is limited as described above in the C library.
- Two-phase name binding in templates, as described in [tesp.res] and [temp.dep] of the standard, is not implemented.
- The export keyword for templates is not implemented.
- A typedef of a function type cannot include member function cv-qualifiers.
- A partial specialization of a class member template cannot be added outside of the class definition.
5.3 Using MISRA C 2004
MISRA C is a set of software development guidelines for the C programming language. It promotes best practices in developing safety-related electronic systems in road vehicles and other embedded systems. MISRA C was originally launched in 1998 by the Motor Industry Software Reliability Association, and has since been adopted across a wide variety of industries. A subsequent update to the guidelines was publishes as MISRA C:2004
You can alter your code to work with the MISRA C:2004 rules. The following options and pragmas enable/disable the rules:
- The --check_misra option enables checking of the specified MISRA C:2004 rules.
- The CHECK_MISRA pragma enables/disables MISRA C:2004 rules at the source level. This pragma is equivalent to using the --check_misra option. See Section 5.10.2.
- RESET_MISRA pragma resets the specified MISRA C:2004 rules to their state before any CHECK_MISRA pragmas were processed. See Section 5.10.21.
The syntax of the option and pragmas is:
--check_misra={all|required|advisory|none|rulespec} |
#pragma CHECK_MISRA ("{all|required|advisory|none|rulespec}") |
#pragma RESET_MISRA ("{all|required|advisory|rulespec}") |
The rulespec parameter is a comma-separated list of rule numbers to enable.
Example: --check_misra=1.1,1.4,1.5,2.1,2.7,7.1,7.2,8.4
- Enables rules 1.1, 1.4, 1.5, 2.1, 2.7, 7.1, 7.2, and 8.4.
Two options control the severity of certain MISRA C:2004 rules:
- The --misra_required option sets the diagnostic severity for required MISRA C:2004 rules.
- The --misra_advisory option sets the diagnostic severity for advisory MISRA C:2004 rules.
The syntax for these options is:
--misra_advisory={error|warning|remark|suppress} |
--misra_required={error|warning|remark|suppress} |
5.4 Using the ULP Advisor
You can get feedback about your code from the ULP (Ultra-Low Power) Advisor. For a list and descriptions of the ULP rules, see www.ti.com/ulpadvisor. You can enable/disable the rules using any of the following. Using multiple --advice options on the command line is permitted.
- The --advice:power option lets you specify which rules to check.
- The --advice:power_severity option lets you specify whether ULP Advisor rule violations are errors, warnings, remarks, or not reported.
- The CHECK_ULP pragma enables/disables ULP Advisor rules at the source level. This pragma is equivalent to using the --advice:power option. See Section 5.10.3.
- The RESET_ULP pragma resets the specified ULP Advisor rules to their state before any CHECK_ULP pragmas were processed. See Section 5.10.22.
The --advice:power option enables checking specified ULP Advisor rules. The syntax is:
--advice:power={all|none|rulespec} |
The rulespec parameter is a comma-separated list of rule numbers to enable. For example, --advice:power=1.1,7.2,7.3,7.4 enables rules 1.1, 7.2, 7.3, and 7.4.
The --advice:power_severity option sets the diagnostic severity for ULP Advisor rules. The syntax is:
--advice:power_severity={error|warning|remark|suppress} |
The syntax of the pragmas is:
#pragma CHECK_ULP ("{all|none|rulespec}") |
#pragma RESET_ULP ("{all|rulespec}") |
5.5 Data Types
Table 5-1 lists the size, representation, and range of each scalar data type for the ARM compiler. Many of the range values are available as standard macros in the header file limits.h.
Table 5-1 ARM C/C++ Data Types
Range | ||||
---|---|---|---|---|
Type | Size | Representation | Minimum | Maximum |
signed char | 8 bits | ASCII | -128 | 127 |
char (1) | 8 bits | ASCII | 0 (1) | 255 (1) |
unsigned char, bool, _Bool | 8 bits | ASCII | 0 | 255 |
short, signed short | 16 bits | 2s complement | -32 768 | 32 767 |
unsigned short, wchar_t (2) | 16 bits | Binary | 0 | 65 535 |
int, signed int | 32 bits | 2s complement | -2 147 483 648 | 2 147 483 647 |
unsigned int | 32 bits | Binary | 0 | 4 294 967 295 |
long, signed long | 32 bits | 2s complement | -2 147 483 648 | 2 147 483 647 |
unsigned long | 32 bits | Binary | 0 | 4 294 967 295 |
long long, signed long long | 64 bits(3) | 2s complement | -9 223 372 036 854 775 808 | 9 223 372 036 854 775 807 |
unsigned long long | 64 bits(3) | Binary | 0 | 18 446 744 073 709 551 615 |
enum (TI_ARM9_ABI and TIABI only) (4) | 32 bits | 2s complement | -2 147 483 648 | 2 147 483 647 |
float | 32 bits | IEEE 32-bit | 1.175 494e-38(5) | 3.40 282 346e+38 |
double | 64 bits(3) | IEEE 64-bit | 2.22 507 385e-308(5) | 1.79 769 313e+308 |
long double | 64 bits(3) | IEEE 64-bit | 2.22 507 385e-308(5) | 1.79 769 313e+308 |
pointers, references, pointer to data members | 32 bits | Binary | 0 | 0xFFFFFFFF |
The type of the storage container for an enumerated type is the smallest integer type that contains all the enumerated values. The container types for enumerators are shown in Table 5-2.
Table 5-2 Enumerator Types
Lower Bound Range | Upper Bound Range | Enumerator Type |
---|---|---|
0 to 255 | 0 to 255 | unsigned char |
-128 to 1 | -128 to 127 | signed char |
0 to 65 535 | 256 to 65 535 | unsigned short |
-128 to 1 | 128 to 32 767 | short, signed short |
-32 768 to -129 | -32 768 to 32 767 | |
0 to 4 294 967 295 | 2 147 483 648 to 4 294 967 295 | unsigned int |
-32 768 to -1 | 32 767 to 2 147 483 647 | int, signed int |
-2 147 483 648 to -32 769 | -2 147 483 648 to 2 147 483 647 | |
0 to 2 147 483 647 | 65 536 to 2 147 483 647 |
The compiler determines the type based on the range of the lowest and highest elements of the enumerator.
For example, the following code results in an enumerator type of int:
enum COLORS
{ green = -200,
blue = 1,
yellow = 2,
red = 60000
};
For example, the following code results in an enumerator type of short:
enum COLORS
{ green = -200,
blue = 1,
yellow = 2,
red = 3
};
5.5.1 Size of Enum Types
An enum type is represented by an underlying integer type. The size of the integer type and whether it is signed is based on the range of values of the enumerated constants.
In strict C89 or C99 mode, the compiler allows only enumeration constants with values that will fit in "int" or "unsigned int".
For C++ and relaxed C89/C99, the compiler allows enumeration constants up to the largest integral type (64 bits). The default, which is recommended, is for the underlying type to be the first type in the following list in which all the enumerated constant values can be represented: int, unsigned int, long, unsigned long long long, unsigned long long.
If you use the --small_enum option, the smallest possible byte size for the enumeration type is used. The underlying type is the first type in the following list in which all the enumerated constant values can be represented: signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long.
The following enum uses 8 bits instead of 32 bits when the --small_enum option is used.
enum example_enum {
first = -128,
second = 0,
third = 127
};
The following enum fits into 16 bits instead of 32 when the --small_enum option is used.
enum a_short_enum {
bottom = -32768,
middle = 0,
top = 32767
};
NOTE
Do not link object files compiled with the --small_enum option with object files that were compiled without it. If you use the --small_enum option, you must use it with all of your C/C++ files; otherwise, you will encounter errors that cannot be detected until run time.
5.6 Keywords
The ARM C/C++ compiler supports all of the standard C89 keywords, including const, volatile, and register. It also supports all of the standard C99 keywords, including inline and restrict. It also supports TI extension keywords __interrupt, and __asm. Some keywords are not available in strict ANSI mode.
The following keywords may appear in other target documentation and require the same treatment as the interrupt and restrict keywords:
- trap
- reentrant
- cregister
5.6.1 The const Keyword
The C/C++ compiler supports the ANSI/ISO standard keyword const in all modes.
This keyword gives you greater optimization and control over allocation of storage for certain data objects. You can apply the const qualifier to the definition of any variable or array to ensure that its value is not altered.
Global objects qualified as const are placed in the .const section. The linker allocates the .const section from ROM or FLASH, which are typically more plentiful than RAM. The const data storage allocation rule has two exceptions:
- If the keyword volatile is also specified in the definition of an object (for example, volatile const int x). Volatile keywords are assumed to be allocated to RAM. (The program is not allowed to modify a const volatile object, but something external to the program might.)
- If the object has automatic storage (function scope).
In both cases, the storage for the object is the same as if the const keyword were not used.
The placement of the const keyword within a definition is important. For example, the first statement below defines a constant pointer p to a modifiable int. The second statement defines a modifiable pointer q to a constant int:
int * const p = &x;
const int * q = &x;
Using the const keyword, you can define large constant tables and allocate them into system ROM. For example, to allocate a ROM table, you could use the following definition:
const int digits[] = {0,1,2,3,4,5,6,7,8,9};
5.6.2 The __interrupt Keyword
The compiler extends the C/C++ language by adding the __interrupt keyword, which specifies that a function is treated as an interrupt function. This keyword is an IRQ interrupt. The alternate keyword, "interrupt", may also be used except in strict ANSI C or C++ modes.
Note that the interrupt function attribute described in Section 5.10.15 is the recommended syntax for declaring interrupt functions.
Functions that handle interrupts follow special register-saving rules and a special return sequence. The implementation stresses safety. The interrupt routine does not assume that the C run-time conventions for the various CPU register and status bits are in effect; instead, it re-establishes any values assumed by the run-time environment. When C/C++ code is interrupted, the interrupt routine must preserve the contents of all machine registers that are used by the routine or by any function called by the routine. When you use the __interrupt keyword with the definition of the function, the compiler generates register saves based on the rules for interrupt functions and the special return sequence for interrupts.
You can only use the __interrupt keyword with a function that is defined to return void and that has no parameters. The body of the interrupt function can have local variables and is free to use the stack or global variables. For example:
__interrupt void int_handler()
{
unsigned int flags;
...
}
The name c_int00 is the C/C++ entry point. This name is reserved for the system reset interrupt. This special interrupt routine initializes the system and calls the main() function. Because it has no caller, c_int00 does not save any registers.
NOTE
Hwi Objects and the __interrupt KeywordThe __interrupt keyword must not be used when SYS/BIOS Hwi objects are used in conjunction with C functions. The Hwi_enter/Hwi_exit macros and the Hwi dispatcher already contain this functionality, and the use of the C modifier can cause unwanted conflicts.
5.6.3 The volatile Keyword
The C/C++ compiler supports the volatile keyword in all modes. In addition, the __volatile keyword is supported in relaxed ANSI mode for C89, C99, and C++.
The volatile keyword indicates to the compiler that there is something about how the variable is accessed that requires that the compiler not use overly-clever optimization on expressions involving that variable. For example, the variable may also be accessed by an external program, an interrupt, another thread, or a peripheral device.
The compiler eliminates redundant memory accesses whenever possible, using data flow analysis to figure out when it is legal. However, some memory accesses may be special in some way that the compiler cannot see, and in such cases you should use the volatile keyword to prevent the compiler from optimizing away something important. The compiler does not optimize out any accesses to variables declared volatile. The number of volatile reads and writes will be exactly as they appear in the C/C++ code, no more and no less and in the same order.
Any variable which might be modified by something external to the obvious control flow of the program (such as an interrupt service routine) must be declared volatile. This tells the compiler that an interrupt function might modify the value at any time, so the compiler should not perform optimizations which will change the number or order of accesses of that variable. This is the primary purpose of the volatile keyword. In the following example, the loop intends to wait for a location to be read as 0xFF:
unsigned int *ctrl;
while (*ctrl !=0xFF);
However, in this example, *ctrl is a loop-invariant expression, so the loop is optimized down to a single-memory read. To get the desired result, define ctrl as:
volatile unsigned int *ctrl;
Here the *ctrl pointer is intended to reference a hardware location, such as an interrupt flag.
The volatile keyword must also be used when accessing memory locations that represent memory-mapped peripheral devices. Such memory locations might change value in ways that the compiler cannot predict. These locations might change if accessed, or when some other memory location is accessed, or when some signal occurs.
Volatile must also be used for local variables in a function which calls setjmp, if the value of the local variables needs to remain valid if a longjmp occurs.
Example 5-1 Volatile for Local Variables With setjmp
#include <stdlib.h>jmp_buf context;
void function()
{
volatile int x = 3;
switch(setjmp(context))
{
case 0: setup(); break;
default:
{
printf("x == %d\n", x); /* We can only reach here if longjmp has occurred; because x's
lifetime begins before the setjmp and lasts through the longjmp,
the C standard requires x be declared "volatile" */
break;
}
}
}
5.7 C++ Exception Handling
The compiler supports all the C++ exception handling features as defined by the ANSI/ISO 14882 C++ Standard. More details are discussed in The C++ Programming Language, Third Edition by Bjarne Stroustrup.
The compiler --exceptions option enables exception handling. The compiler’s default is no exception handling support.
For exceptions to work correctly, all C++ files in the application must be compiled with the --exceptions option, regardless of whether exceptions occur in a particular file. Mixing exception-enabled object files and libraries with object files and libraries that do not have exceptions enabled can lead to undefined behavior.
Exception handling requires support in the run-time-support library, which come in exception-enabled and exception-disabled forms; you must link with the correct form. When using automatic library selection (the default), the linker automatically selects the correct library Section 4.3.1.1. If you select the library manually, you must use run-time-support libraries whose name contains _eh if you enable exceptions.
Using the --exceptions option causes the compiler to insert exception handling code. This code will increase the size of the program, but EABI does not increase the code size much, and has a minimal execution time cost if exceptions are never thrown. It slightly increases the data size for the exception-handling tables.
See Section 7.1 for details on the run-time libraries.
5.8 Register Variables and Parameters
The C/C++ compiler allows the use of the keyword register on global and local register variables and parameters. This section describes the compiler implementation for this qualifier.
5.8.1 Local Register Variables and Parameters
The C/C++ compiler treats register variables (variables defined with the register keyword) differently, depending on whether you use the --opt_level (-O) option.
- Compiling with optimization
- Compiling without optimization
The compiler ignores any register definitions and allocates registers to variables and temporary values by using an algorithm that makes the most efficient use of registers.
If you use the register keyword, you can suggest variables as candidates for allocation into registers. The compiler uses the same set of registers for allocating temporary expression results as it uses for allocating register variables.
The compiler attempts to honor all register definitions. If the compiler runs out of appropriate registers, it frees a register by moving its contents to memory. If you define too many objects as register variables, you limit the number of registers the compiler has for temporary expression results. This limit causes excessive movement of register contents to memory.
Any object with a scalar type (integral, floating point, or pointer) can be defined as a register variable. The register designator is ignored for objects of other types, such as arrays.
The register storage class is meaningful for parameters as well as local variables. Normally, in a function, some of the parameters are copied to a location on the stack where they are referenced during the function body. The compiler copies a register parameter to a register instead of the stack, which speeds access to the parameter within the function.
For more information about register conventions, see Section 6.3.
5.8.2 Global Register Variables
The C/C++ compiler extends the C language by adding a special convention to the register storage class specifier to allow the allocation of global registers. This special global declaration has the form:
registertype regid |
The regid parameter can be __R5, __R6, or __R9. The identifiers _ _R5, _ _R6, and _ _R9 are each bound to their corresponding register R5, R6 and R9, respectively.
When you use this declaration at the file level, the register is permanently reserved from any other use by the optimizer and code generator for that file. You cannot assign an initial value to the register. You can use a #define directive to assign a meaningful name to the register; for example:
register struct data_struct *__R5
#define data_pointer __R5
data_pointer->element;
data_pointer++;
There are two reasons that you would be likely to use a global register variable:
- You are using a global variable throughout your program, and it would significantly reduce code size and execution speed to assign this variable to a register permanently.
- You are using an interrupt service routine that is called so frequently that it would significantly reduce execution speed if the routine did not have to save and restore the register(s) it uses every time it is called.
You need to consider very carefully the implications of reserving a global register variable. Registers are a precious resource to the compiler, and using this feature indiscriminately may result in poorer code.
You also need to consider carefully how code with a globally declared register variable interacts with other code, including library functions, that does not recognize the restriction placed on the register.
Because the registers that can be global register variables are save-on-entry registers, a normal function call and return does not affect the value in the register and neither does a normal interrupt. However, when you mix code that has a globally declared register variable with code that does not have the register reserved, it is still possible for the value in the register to become corrupted. To avoid the possibility of corruption, you must follow these rules:
- Functions that alter global register variables cannot be called by functions that are not aware of the global register. Use the -r shell option to reserve the register in code that is not aware of the global register declaration. You must be careful if you pass a pointer to a function as an argument. If the passed function alters the global register variable and the called function saves the register, the value in the register will be corrupted.
- You cannot access a global register variable in an interrupt service routine unless you recompile all code, including all libraries, to reserve the register. This is because the interrupt routine can be called from any point in the program.
- The longjmp ( ) function restores global register variables to the values they had at the setjmp ( ) location. If this presents a problem in your code, you must alter the code for the function and recompile rts.src.
The -r register compiler command-line option allows you to prevent the compiler from using the named register. This lets you reserve the named register in modules that do not have the global register variable declaration, such as the run-time-support libraries, if you need to compile the modules to prevent some of the above occurrences.
5.9 The __asm Statement
The C/C++ compiler can embed assembly language instructions or directives directly into the assembly language output of the compiler. This capability is an extension to the C/C++ language implemented through the __asm keyword. The __asm keyword provides access to hardware features that C/C++ cannot provide.
The alternate keyword, "asm", may also be used except in strict ANSI C mode. It is available in relaxed C and C++ modes.
Using __asm is syntactically performed as a call to a function named __asm, with one string constant argument:
__asm("assembler text"); |
The compiler copies the argument string directly into your output file. The assembler text must be enclosed in double quotes. All the usual character string escape codes retain their definitions. For example, you can insert a .byte directive that contains quotes as follows:
__asm("STR: .byte \"abc\"");
The inserted code must be a legal assembly language statement. Like all assembly language statements, the line of code inside the quotes must begin with a label, a blank, a tab, or a comment (asterisk or semicolon). The compiler performs no checking on the string; if there is an error, the assembler detects it. For more information about the assembly language statements, see the ARM Assembly Language Tools User's Guide.
The __asm statements do not follow the syntactic restrictions of normal C/C++ statements. Each can appear as a statement or a declaration, even outside of blocks. This is useful for inserting directives at the very beginning of a compiled module.
The __asm statement does not provide any way to refer to local variables. If your assembly code needs to refer to local variables, you will need to write the entire function in assembly code.
For more information, refer to Section 6.6.5.
NOTE
Avoid Disrupting the C/C++ Environment With asm Statements
Be careful not to disrupt the C/C++ environment with __asm statements. The compiler does not check the inserted instructions. Inserting jumps and labels into C/C++ code can cause unpredictable results in variables manipulated in or around the inserted code. Directives that change sections or otherwise affect the assembly environment can also be troublesome.
Be especially careful when you use optimization with __asm statements. Although the compiler cannot remove __asm statements, it can significantly rearrange the code order near them and cause undesired results.
5.10 Pragma Directives
Pragma directives tell the compiler how to treat a certain function, object, or section of code. The ARM C/C++ compiler supports the following pragmas:
- CALLS (See Section 5.10.1)
- CHECK_MISRA (See Section 5.10.2)
- CHECK_ULP (See Section 5.10.3)
- CLINK (See Section 5.10.4)
- CODE_SECTION (See Section 5.10.5)
- CODE_STATE (See Section 5.10.6)
- DATA_ALIGN (See Section 5.10.7)
- DATA_SECTION (See Section 5.10.8)
- diag_suppress, diag_remark, diag_warning, diag_error, diag_default, diag_push, diag_pop (See Section 5.10.9)
- DUAL_STATE (See Section 5.10.10)
- FUNC_ALWAYS_INLINE (See Section 5.10.11)
- FUNC_CANNOT_INLINE (See Section 5.10.12)
- FUNC_EXT_CALLED (See Section 5.10.13)
- FUNCTION_OPTIONS (See Section 5.10.14)
- INTERRUPT (See Section 5.10.15)
- LOCATION (See Section 5.10.16)
- MUST_ITERATE (See Section 5.10.17)
- NOINIT (See Section 5.10.18)
- NO_HOOKS (See Section 5.10.19)
- pack (See Section 5.10.20)
- PERSISTENT (See Section 5.10.18)
- RESET_MISRA (See Section 5.10.21)
- RESET_ULP (See Section 5.10.22)
- RETAIN (See Section 5.10.23)
- SET_CODE_SECTION (See Section 5.10.24)
- SET_DATA_SECTION (See Section 5.10.24)
- SWI_ALIAS (See Section 5.10.25)
- TASK (See Section 5.10.26)
- UNROLL (See Section 5.10.27)
- WEAK (See Section 5.10.28)
The arguments func and symbol cannot be defined or declared inside the body of a function. You must specify the pragma outside the body of a function; and the pragma specification must occur before any declaration, definition, or reference to the func or symbol argument. If you do not follow these rules, the compiler issues a warning and may ignore the pragma.
For pragmas that apply to functions or symbols, the syntax differs between C and C++.
- In C, you must supply the name of the object or function to which you are applying the pragma as the first argument. Because the entity operated on is specified, a pragma in C can appear some distance way from the definition of that entity.
- In C++, pragmas are positional. They do not name the entity on which they operate as an argument. Instead, they always operate on the next entity defined after the pragma.
5.10.1 The CALLS Pragma
The CALLS pragma specifies a set of functions that can be called indirectly from a specified calling function.
The CALLS pragma is used by the compiler to embed debug information about indirect calls in object files. Using the CALLS pragma on functions that make indirect calls enables such indirect calls to be included in calculations for such functions' inclusive stack sizes. For more information on generating function stack usage information, see the -cg option of the Object File Display Utility in the "Invoking the Object File Display Utility" section of the ARM Assembly Language Tools User's Guide.
The CALLS pragma can precede either the calling function's definition or its declaration. In C, the pragma must have at least 2 arguments—the first argument is the calling function, followed by at least one function that will be indirectly called from the calling function. In C++, the pragma applies to the next function declared or defined, and the pragma must have at least one argument.
The syntax for the CALLS pragma in C is as follows. This indicates that calling_function can indirectly call function_1 through function_n.
#pragma CALLS ( calling_function, function_1, function_2, ..., function_n ) |
The syntax for the CALLS pragma in C++ is:
#pragma CALLS ( function_1_mangled_name, ..., function_n_mangled_name) |
Note that in C++, the arguments to the CALLS pragma must be the full mangled names for the functions that can be indirectly called from the calling function.
The GCC-style "calls" attribute syntax, which has the same effect as the CALLS pragma, is as follows:
__attribute__((calls("function_1","function_2",..., "function_n")))
5.10.2 The CHECK_MISRA Pragma
The CHECK_MISRA pragma enables/disables MISRA C:2004 rules at the source level. This pragma is equivalent to using the --check_misra option.
The syntax of the pragma in C is:
#pragma CHECK_MISRA (" {all|required|advisory|none|rulespec} ") |
The rulespec parameter is a comma-separated list of rule numbers. See Section 5.3 for details.
The RESET_MISRA pragma can be used to reset any CHECK_MISRA pragmas; see Section 5.10.21.
5.10.3 The CHECK_ULP Pragma
The CHECK_ULP pragma enables/disables ULP Advisor rules at the source level. This pragma is equivalent to using the --advice:power option.
The syntax of the pragma in C is:
#pragma CHECK_ULP (" {all|none|rulespec} ") |
The rulespec parameter is a comma-separated list of rule numbers. See Section 5.4 for the syntax. See www.ti.com/ulpadvisor for a list of rules.
The RESET_ULP pragma can be used to reset any CHECK_ULP pragmas; see Section 5.10.22.
5.10.4 The CLINK Pragma
The CLINK pragma can be applied to a code or data symbol. It causes a .clink directive to be generated into the section that contains the definition of the symbol. The .clink directive tells the linker that a section is eligible for removal during conditional linking. Thus, if the section is not referenced by any other section in the application being compiled and linked, it will not be included in the resulting output file.
The syntax of the pragma in C is:
#pragma CLINK (symbol ) |
The syntax of the pragma in C++ is:
#pragma CLINK |
The RETAIN pragma has the opposite effect of the CLINK pragma. See Section 5.10.23 for more details.
5.10.5 The CODE_SECTION Pragma
The CODE_SECTION pragma allocates space for the symbol in C, or the next symbol declared in C++, in a section named section name.
The syntax of the pragma in C is:
#pragma CODE_SECTION (symbol, "section name") |
The syntax of the pragma in C++ is:
#pragma CODE_SECTION ("section name") |
The CODE_SECTION pragma is useful if you have code objects that you want to link into an area separate from the .text section.
The following example demonstrates the use of the CODE_SECTION pragma.
Example 5-2 Using the CODE_SECTION Pragma C Source File
#pragma CODE_SECTION(fn, "my_sect")
int fn(int x)
{
return x;
}
Example 5-3 Generated Assembly Code From Example 5-2
.sect "my_sect" .align 4
.clink
.state32
.global fn
;*****************************************************************************
;* FUNCTION NAME: fn *
;* *
;* Regs Modified : SP *
;* Regs Used : A1,SP *
;* Local Frame Size : 0 Args + 4 Auto + 0 Save = 4 byte *
;*****************************************************************************
fn:
;* --------------------------------------------------------------------------*
SUB SP, SP, #8
STR A1, [SP, #0] ; |4|
ADD SP, SP, #8
BX LR
5.10.6 The CODE_STATE Pragma
The CODE_STATE pragma overrides the compilation state of a file, at the function level. For example, if a file is compiled in thumb mode, but you want a function in that file to be compiled in 32-bit mode, you would add this pragma in the file. The compilation state for the function is changed to 16-bit mode (thumb) or 32-bit mode.
The syntax of the pragma is C is:
#pragma CODE_STATE ( function, {16|32} ) |
The syntax of the pragma in C++ is:
#pragma CODE_STATE ( code state) |
5.10.7 The DATA_ALIGN Pragma
The DATA_ALIGN pragma aligns the symbol in C, or the next symbol declared in C++, to an alignment boundary. The alignment boundary is the maximum of the symbol's default alignment value or the value of the constant in bytes. The constant must be a power of 2. The maximum alignment is 32768.
The DATA_ALIGN pragma cannot be used to reduce an object's natural alignment.
The syntax of the pragma in C is:
#pragma DATA_ALIGN (symbol, constant) |
The syntax of the pragma in C++ is:
#pragma DATA_ALIGN (constant) |
5.10.8 The DATA_SECTION Pragma
The DATA_SECTION pragma allocates space for the symbol in C, or the next symbol declared in C++, in a section named section name.
The syntax of the pragma in C is:
#pragma DATA_SECTION (symbol, "section name") |
The syntax of the pragma in C++ is:
#pragma DATA_SECTION ("section name") |
The DATA_SECTION pragma is useful if you have data objects that you want to link into an area separate from the .bss section.
Example 5-4 through Example 5-6 demonstrate the use of the DATA_SECTION pragma.
Example 5-4 Using the DATA_SECTION Pragma C Source File
#pragma DATA_SECTION(bufferB, "my_sect")
char bufferA[512];
char bufferB[512];
5.10.9 The Diagnostic Message Pragmas
The following pragmas can be used to control diagnostic messages in the same ways as the corresponding command line options:
Pragma | Option | Description |
---|---|---|
diag_suppress num | -pds=num[, num2, num3...] | Suppress diagnostic num |
diag_remark num | -pdsr=num[, num2, num3...] | Treat diagnostic num as a remark |
diag_warning num | -pdsw=num[, num2, num3...] | Treat diagnostic num as a warning |
diag_error num | -pdse=num[, num2, num3...] | Treat diagnostic num as an error |
diag_default num | n/a | Use default severity of the diagnostic |
diag_push | n/a | Push the current diagnostics severity state to store it for later use. |
diag_pop | n/a | Pop the most recent diagnostic severity state stored with #pragma diag_push to be the current setting. |
The syntax of the diag_suppress, diag_remark, diag_warning, and diag_error pragmas in C is:
#pragma diag_xxx [=]num[, num2, num3...] |
Notice that the names of these pragmas are in lowercase.
The diagnostic affected (num) is specified using either an error number or an error tag name. The equal sign (=) is optional. Any diagnostic can be overridden to be an error, but only diagnostic messages with a severity of discretionary error or below can have their severity reduced to a warning or below, or be suppressed. The diag_default pragma is used to return the severity of a diagnostic to the one that was in effect before any pragmas were issued (i.e., the normal severity of the message as modified by any command-line options).
The diagnostic identifier number is output with the message when you use the -pden command line option. The following example suppresses a diagnostic message and then restores the previous diagnostics severity state:
#pragma diag_push
#pragma diag_suppress 551
#pragma CHECK_MISRA("-9.1")
#pragma diag_pop
5.10.10 The DUAL_STATE Pragma
By default (that is, without the compiler -md option), all functions with external linkage support dual-state interworking. This support assumes that most calls do not require a state change and are therefore optimized (in terms of code size and execution speed) for calls not requiring a state change. Using the DUAL_STATE pragma does not change the functionality of the dual-state support, but it does assert that calls to the applied function often require a state change. Therefore, such support is optimized for state changes.
The pragma must appear before any declaration or reference to the function that you want to keep. In C, the argument func is the name of the function. In C++, the pragma applies to the next function declared.
The syntax of the pragma in C is:
#pragma DUAL_STATE (func) |
The syntax of the pragma in C++ is:
#pragma DUAL_STATE |
For more information on dual-state interworking, see Section 6.11.
5.10.11 The FUNC_ALWAYS_INLINE Pragma
The FUNC_ALWAYS_INLINE pragma instructs the compiler to always inline the named function. The compiler only inlines the function if it is legal to inline the function and the compiler is invoked with any level of optimization (--opt_level=0). See Section 2.11 for details about interaction between various types of inlining.
This pragma must appear before any declaration or reference to the function that you want to inline. In C, the argument func is the name of the function that will be inlined. In C++, the pragma applies to the next function declared.
The syntax of the pragma in C is:
#pragma FUNC_ALWAYS_INLINE (func) |
The syntax of the pragma in C++ is:
#pragma FUNC_ALWAYS_INLINE |
The following example uses this pragma:
#pragma FUNC_ALWAYS_INLINE(functionThatMustGetInlined)
static inline void functionThatMustGetInlined(void) {
P1OUT |= 0x01;
P1OUT &= ~0x01;
}
NOTE
Use Caution with the FUNC_ALWAYS_INLINE PragmaThe FUNC_ALWAYS_INLINE pragma overrides the compiler's inlining decisions. Overuse of this pragma could result in increased compilation times or memory usage, potentially enough to consume all available memory and result in compilation tool failures.
5.10.12 The FUNC_CANNOT_INLINE Pragma
The FUNC_CANNOT_INLINE pragma instructs the compiler that the named function cannot be expanded inline. Any function named with this pragma overrides any inlining you designate in any other way, such as using the inline keyword. Automatic inlining is also overridden with this pragma; see Section 2.11.
The pragma must appear before any declaration or reference to the function that you want to keep. In C, the argument func is the name of the function that cannot be inlined. In C++, the pragma applies to the next function declared.
The syntax of the pragma in C is:
#pragma FUNC_CANNOT_INLINE (func) |
The syntax of the pragma in C++ is:
#pragma FUNC_CANNOT_INLINE |
5.10.13 The FUNC_EXT_CALLED Pragma
When you use the --program_level_compile option, the compiler uses program-level optimization. When you use this type of optimization, the compiler removes any function that is not called, directly or indirectly, by main(). You might have C/C++ functions that are called by hand-coded assembly instead of main().
The FUNC_EXT_CALLED pragma specifies that the optimizer should keep these C functions or any functions these C/C++ functions call. These functions act as entry points into C/C++. The pragma must appear before any declaration or reference to the function to keep. In C, the argument func is the name of the function to keep. In C++, the pragma applies to the next function declared.
The syntax of the pragma in C is:
#pragma FUNC_EXT_CALLED (func) |
The syntax of the pragma in C++ is:
#pragma FUNC_EXT_CALLED |
Except for _c_int00, which is the name reserved for the system reset interrupt for C/C++programs, the name of the interrupt (the func argument) does not need to conform to a naming convention.
When you use program-level optimization, you may need to use the FUNC_EXT_CALLED pragma with certain options. See Section 3.3.2.
5.10.14 The FUNCTION_OPTIONS Pragma
The FUNCTION_OPTIONS pragma allows you to compile a specific function in a C or C++ file with additional command-line compiler options. The affected function will be compiled as if the specified list of options appeared on the command line after all other compiler options. In C, the pragma is applied to the function specified. In C++, the pragma is applied to the next function.
The syntax of the pragma in C is:
#pragma FUNCTION_OPTIONS ( func, "additional options" ) |
The syntax of the pragma in C++ is:
#pragma FUNCTION_OPTIONS( "additional options" ) |
Supported options for this pragma are --opt_level, --auto_inline, --code_state, and --opt_for_speed. In order to use --opt_level and --auto_inline with the FUNCTION_OPTIONS pragma, the compiler must be invoked with some optimization level (that is, at least --opt_level=0).
5.10.15 The INTERRUPT Pragma
The INTERRUPT pragma enables you to handle interrupts directly with C code. The pragma specifies that the function is an interrupt. The type of interrupt is specified by the pragma; the IRQ (interrupt request) interrupt type is assumed if none is given.
The syntax of the pragma in C is:
#pragma INTERRUPT (func[,interrupt_type]) |
The syntax of the pragma in C++ is:
#pragma INTERRUPT[( interrupt_type)] void func( void ) |
The GCC interrupt attribute syntax, which has the same effects as the INTERRUPT pragma, is as follows. Note that the interrupt attribute can precede either the function's definition or its declaration.
__attribute__((interrupt[( "interrupt_type" )] )) void func( void ) |
In C, the argument func is the name of a function. In C++, the pragma applies to the next function declared. The optional argument interrupt_type specifies an interrupt type. The registers that are saved and the return sequence depend upon the interrupt type. If the interrupt type is omitted from the interrupt pragma, the interrupt type IRQ is assumed. These are the valid interrupt types:
Interrupt Type | Description |
---|---|
DABT | Data abort |
FIQ | Fast interrupt request |
IRQ | Interrupt request |
PABT | Prefetch abort |
RESET | System reset |
SWI | Software interrupt |
UDEF | Undefined instruction |
Except for _c_int00, which is the name reserved for the system reset interrupt for C programs, the name of the interrupt (the func argument) does not need to conform to a naming convention.
For the Cortex-M architectures, the interrupt_type can be nothing (default) or SWI. The hardware performs the necessary saving and restoring of context for interrupts. Therefore, the compiler does not distinguish between the different interrupt types. The only exception is for software interrupts (SWIs) which are allowed to have arguments (for Cortex-M architectures, C SWI handlers cannot return values).
NOTE
Hwi Objects and the INTERRUPT PragmaThe INTERRUPT pragma must not be used when SYS/BIOS Hwi objects are used in conjunction with C functions. The Hwi_enter/Hwi_exit macros and the Hwi dispatcher contain this functionality, and the use of the C modifier can cause negative results.
5.10.16 The LOCATION Pragma
The compiler supports the ability to specify the run-time address of a variable at the source level. This can be accomplished with the LOCATION pragma or attribute.
The syntax of the pragma in C is:
#pragma LOCATION(x,address) |
intx |
The syntax of the pragmas in C++ is:
#pragma LOCATION( address ) |
int x |
The syntax of the GCC attribute is:
int x __attribute__((location( address ))) |
The NOINIT pragma may be used in conjunction with the LOCATION pragma to map variables to special memory locations; see Section 5.10.18.
5.10.17 The MUST_ITERATE Pragma
The MUST_ITERATE pragma specifies to the compiler certain properties of a loop. When you use this pragma, you are guaranteeing to the compiler that a loop executes a specific number of times or a number of times within a specified range.
Any time the UNROLL pragma is applied to a loop, MUST_ITERATE should be applied to the same loop. For loops the MUST_ITERATE pragma's third argument, multiple, is the most important and should always be specified.
Furthermore, the MUST_ITERATE pragma should be applied to any other loops as often as possible. This is because the information provided via the pragma (especially the minimum number of iterations) aids the compiler in choosing the best loops and loop transformations (that is, nested loop transformations). It also helps the compiler reduce code size.
No statements are allowed between the MUST_ITERATE pragma and the for, while, or do-while loop to which it applies. However, other pragmas, such as UNROLL, can appear between the MUST_ITERATE pragma and the loop.
5.10.17.1 The MUST_ITERATE Pragma Syntax
The syntax of the pragma for C and C++ is:
#pragma MUST_ITERATE (min, max, multiple) |
The arguments min and max are programmer-guaranteed minimum and maximum trip counts. The trip count is the number of times a loop iterates. The trip count of the loop must be evenly divisible by multiple. All arguments are optional. For example, if the trip count could be 5 or greater, you can specify the argument list as follows:
#pragma MUST_ITERATE(5)
However, if the trip count could be any nonzero multiple of 5, the pragma would look like this:
#pragma MUST_ITERATE(5, , 5) /* Note the blank field for max */
It is sometimes necessary for you to provide min and multiple in order for the compiler to perform unrolling. This is especially the case when the compiler cannot easily determine how many iterations the loop will perform (that is, the loop has a complex exit condition).
When specifying a multiple via the MUST_ITERATE pragma, results of the program are undefined if the trip count is not evenly divisible by multiple. Also, results of the program are undefined if the trip count is less than the minimum or greater than the maximum specified.
If no min is specified, zero is used. If no max is specified, the largest possible number is used. If multiple MUST_ITERATE pragmas are specified for the same loop, the smallest max and largest min are used.
5.10.17.2 Using MUST_ITERATE to Expand Compiler Knowledge of Loops
Through the use of the MUST_ITERATE pragma, you can guarantee that a loop executes a certain number of times. The example below tells the compiler that the loop is guaranteed to run exactly 10 times:
#pragma MUST_ITERATE(10,10)
for(i = 0; i < trip_count; i++) { ...
In this example, the compiler attempts to generate a loop even without the pragma. However, if MUST_ITERATE is not specified for a loop such as this, the compiler generates code to bypass the loop, to account for the possibility of 0 iterations. With the pragma specification, the compiler knows that the loop iterates at least once and can eliminate the loop-bypassing code.
MUST_ITERATE can specify a range for the trip count as well as a factor of the trip count. For example:
#pragma MUST_ITERATE(8, 48, 8)
for(i = 0; i < trip_count; i++) { ...
This example tells the compiler that the loop executes between 8 and 48 times and that the trip_count variable is a multiple of 8 (8, 16, 24, 32, 40, 48). The multiple argument allows the compiler to unroll the loop.
You should also consider using MUST_ITERATE for loops with complicated bounds. In the following example:
for(i2 = ipos[2]; i2 < 40; i2 += 5) { ...
The compiler would have to generate a divide function call to determine, at run time, the exact number of iterations performed. The compiler will not do this. In this case, using MUST_ITERATE to specify that the loop always executes eight times allows the compiler to attempt to generate a loop:
#pragma MUST_ITERATE(8, 8)
for(i2 = ipos[2]; i2 < 40; i2 += 5) { ...
5.10.18 The NOINIT and PERSISTENT Pragmas
Global and static variables are zero-initialized. However, in applications that use non-volatile memory, it may be desirable to have variables that are not initialized. Noinit variables are global or static variables that are not zero-initialized at startup or reset.
Persistent and noinit variables behave identically with the exception of whether or not they are initialized at load time.
The NOINIT pragma may be used in conjunction with the LOCATION pragma to map variables to special memory locations, like memory-mapped registers, without generating unwanted writes. The NOINIT pragma may only be used with uninitialized variables.
The PERSISTENT pragma is similar to the NOINIT pragma, except that it may only be used with statically-initialized variables. Persistent variables disable startup initialization; they are given an initial value when the code is loaded, but are never again initialized.
NOTE
When using these pragmas in non-volatile FRAM memory, the memory region could be protected against unintended writes through the device's Memory Protection Unit. Some devices have memory protection enabled by default. Please see the information about memory protection in the datasheet for your device. If the Memory Protection Unit is enabled, it first needs to be disabled before modifying the variables.
If you are using non-volatile RAM, you can define a persistent variable with an initial value of zero loaded into RAM. The program can increment that variable over time as a counter, and that count will not disappear if the device loses power and restarts, because the memory is non-volatile and the boot routines do not initialize it back to zero. For example:
#pragma PERSISTENT(x)
#pragma location = 0xC200 // memory address in RAM
int x = 0;
void main() {
run_init();
while (1) {
run_actions(x);
__delay_cycles(1000000);
x++;
}
}
The syntax of the pragmas in C is:
#pragma NOINIT (x) |
int x ; |
#pragma PERSISTENT (x) |
int x =10; |
The syntax of the pragmas in C++ is:
#pragma NOINIT |
int x ; |
#pragma PERSISTENT |
int x =10; |
The syntax of the GCC attributes is:
int x __attribute__((noinit)); |
int x __attribute__((persistent)) = 0; |
5.10.19 The NO_HOOKS Pragma
The NO_HOOKS pragma prevents entry and exit hook calls from being generated for a function.
The syntax of the pragma in C is:
#pragma NO_HOOKS (func) |
The syntax of the pragma in C++ is:
#pragma NO_HOOKS |
See Section 2.15 for details on entry and exit hooks.
5.10.20 The pack Pragma
The pack pragma can be used to control the alignment of fields within a class, struct, or union type. The syntax of the pragma in C/C++ can be any of the following.
#pragma pack (n) |
The above form of the pack pragma affects all class, struct, or union type declarations that follow this pragma in a file. It forces the maximum alignment of each field to be the value specified by n. Valid values for n are 1, 2, 4, 8, and 16 bytes.
#pragma pack ( push, n) |
#pragma pack ( pop ) |
The above form of the pack pragma affects only class, struct, and union type declarations between push and pop directives. (A pop directive with no prior push results in a warning diagnostic from the compiler.) The maximum alignment of all fields declared is n. Valid values for n are 1, 2, 4, 8, and 16 bytes.
#pragma pack ( show ) |
The above form of the pack pragma sends a warning diagnostic to stderr to record the current state of the pack pragma stack. You can use this form while debugging.
For more about packed fields, see Section 5.16.4.
5.10.21 The RESET_MISRA Pragma
The RESET_MISRA pragma resets the specified MISRA C:2004 rules to the state they were before any CHECK_MISRA pragmas (see Section 5.10.2) were processed. For instance, if a rule was enabled on the command line but disabled in the source, the RESET_MISRA pragma resets it to enabled. This pragma accepts the same format as the --check_misra option, except for the "none" keyword.
The syntax of the pragma in C is:
#pragma RESET_MISRA (" {all|required|advisory|rulespec} ") |
The rulespec parameter is a comma-separated list of rule numbers. See Section 5.3 for details.
5.10.22 The RESET_ULP Pragma
The RESET_ULP pragma resets the specified ULP Advisor rules to the state they were before any CHECK_ULP pragmas (see Section 5.10.3) were processed. For instance, if a rule was enabled on the command line but disabled in the source, the RESET_ULP pragma resets it to enabled. This pragma accepts the same format as the --advice:power option, except for the "none" keyword.
The syntax of the pragma in C is:
#pragma RESET_ULP (" {all|rulespec} ") |
The rulespec parameter is a comma-separated list of rule numbers. See Section 5.4 for details. See www.ti.com/ulpadvisor for a list of rules.
5.10.23 The RETAIN Pragma
The RETAIN pragma can be applied to a code or data symbol. It causes a .retain directive to be generated into the section that contains the definition of the symbol. The .retain directive indicates to the linker that the section is ineligible for removal during conditional linking. Therefore, regardless whether or not the section is referenced by another section in the application that is being compiled and linked, it will be included in the output file result of the link.
The syntax of the pragma in C is:
#pragma RETAIN ( symbol ) |
The syntax of the pragma in C++ is:
#pragma RETAIN |
The CLINK pragma has the opposite effect of the RETAIN pragma. See Section 5.10.4 for more details.
5.10.24 The SET_CODE_SECTION and SET_DATA_SECTION Pragmas
These pragmas can be used to set the section for all declarations below the pragma.
The syntax of the pragmas in C/C++ is:
#pragma SET_CODE_SECTION ("section name") |
#pragma SET_DATA_SECTION ("section name") |
In Example 5-7 x and y are put in the section mydata. To reset the current section to the default used by the compiler, a blank parameter should be passed to the pragma. An easy way to think of the pragma is that it is like applying the CODE_SECTION or DATA_SECTION pragma to all symbols below it.
Example 5-7 Setting Section With SET_DATA_SECTION Pragma
#pragma SET_DATA_SECTION("mydata")
int x;
int y;
#pragma SET_DATA_SECTION()
The pragmas apply to both declarations and definitions. If applied to a declaration and not the definition, the pragma that is active at the declaration is used to set the section for that symbol. Here is an example:
Example 5-8 Setting a Section With SET_CODE_SECTION Pragma
#pragma SET_CODE_SECTION("func1")
extern void func1();
#pragma SET_CODE_SECTION()
...
void func1() { ... }
In Example 5-8 func1 is placed in section func1. If conflicting sections are specified at the declaration and definition, a diagnostic is issued.
The current CODE_SECTION and DATA_SECTION pragmas and GCC attributes can be used to override the SET_CODE_SECTION and SET_DATA_SECTION pragmas. For example:
Example 5-9 Overriding SET_DATA_SECTION Setting
#pragma DATA_SECTION(x, "x_data")
#pragma SET_DATA_SECTION("mydata")
int x;
int y;
#pragma SET_DATA_SECTION()
In Example 5-9 x is placed in x_data and y is placed in mydata. No diagnostic is issued for this case.
The pragmas work for both C and C++. In C++, the pragmas are ignored for templates and for implicitly created objects, such as implicit constructors and virtual function tables.
5.10.25 The SWI_ALIAS Pragma
The SWI_ALIAS pragma allows you to refer to a particular software interrupt as a function name and to invocations of the software interrupt as function calls. Since the function name is simply an alias for the software interrupt, no function definition exists for the function name.
The syntax of the pragma in C is:
#pragma SWI_ALIAS(func,swi_number) |
The syntax of the pragma in C++ is:
#pragma SWI_ALIAS(swi_number) |
Calls to the applied function are compiled as software interrupts whose number is swi_number. The swi_number variable must be an integer constant.
A function prototype must exist for the alias and it must occur after the pragma and before the alias is used. Software interrupts whose number is not known until run time are not supported.
For information about using the GCC function attribute syntax to declare function aliases, see Section 5.16.2
For more information about using software interrupts, including restrictions on passing arguments and register usage, see Section 6.7.5.
Example 5-10 Using the SWI_ALIAS Pragma C Source File
#pragma SWI_ALIAS(put, 48) /* #pragma SWI_ALIAS(48) for C++ */
int put (char *key, int value);
void error();
main()
{
if (!put("one", 1)) /* calling "put" invokes SWI #48 with 2 arguments */
error(); /* and returns a result. */
}
Example 5-11 Generated Assembly File
;***************************************************************
;* FUNCTION DEF: _main *
;***************************************************************
_main:
STMFD SP!, {LR}
ADR A1, SL1
MOV A2, #1
SWI #48 ; SWI #48 is generated for the function call
CMP A1, #0
BLEQ _error
MOV A1, #0
LDMFD SP!, {PC}
SL1: .string "one",0
5.10.26 The TASK Pragma
The TASK pragma specifies that the function to which it is applied is a task. Tasks are functions that are called but never return. Typically, they consist of an infinite loop that simply dispatches other activities. Because they never return, there is no need to save (and therefore restore) registers that would otherwise be saved and restored. This can save RAM space, as well as some code space.
The syntax of the pragma in C is:
#pragma TASK(func) |
The syntax of the pragma in C++ is:
#pragma TASK |
5.10.27 The UNROLL Pragma
The UNROLL pragma specifies to the compiler how many times a loop should be unrolled. The optimizer must be invoked (use --opt_level=[1|2|3] or -O1, -O2, or -O3) in order for pragma-specified loop unrolling to take place. The compiler has the option of ignoring this pragma.
No statements are allowed between the UNROLL pragma and the for, while, or do-while loop to which it applies. However, other pragmas, such as MUST_ITERATE, can appear between the UNROLL pragma and the loop.
The syntax of the pragma for C and C++ is:
#pragma UNROLL(n) |
If possible, the compiler unrolls the loop so there are n copies of the original loop. The compiler only unrolls if it can determine that unrolling by a factor of n is safe. In order to increase the chances the loop is unrolled, the compiler needs to know certain properties:
- The loop iterates a multiple of n times. This information can be specified to the compiler via the multiple argument in the MUST_ITERATE pragma.
- The smallest possible number of iterations of the loop
- The largest possible number of iterations of the loop
The compiler can sometimes obtain this information itself by analyzing the code. However, sometimes the compiler can be overly conservative in its assumptions and therefore generates more code than is necessary when unrolling. This can also lead to not unrolling at all. Furthermore, if the mechanism that determines when the loop should exit is complex, the compiler may not be able to determine these properties of the loop. In these cases, you must tell the compiler the properties of the loop by using the MUST_ITERATE pragma.
Specifying #pragma UNROLL(1) asks that the loop not be unrolled. Automatic loop unrolling also is not performed in this case.
If multiple UNROLL pragmas are specified for the same loop, it is undefined which pragma is used, if any.
5.10.28 The WEAK Pragma
The WEAK pragma gives weak binding to a symbol.
The syntax of the pragma in C is:
#pragma WEAK (symbol) |
The syntax of the pragma in C++ is:
#pragma WEAK |
The WEAK pragma makes symbol a weak reference if it is a reference, or a weak definition, if it is a definition. The symbol can be a data or function variable. In effect, unresolved weak references do not cause linker errors and do not have any effect at run time. The following apply for weak references:
- Libraries are not searched to resolve weak references. It is not an error for a weak reference to remain unresolved.
- During linking, the value of an undefined weak reference is:
- Zero if the relocation type is absolute
- The address of the place if the relocation type is PC-relative
- The address of the nominal base address if the relocation type is base-relative.
A weak definition does not change the rules by which object files are selected from libraries. However, if a link set contains both a weak definition and a non-weak definition, the non-weak definition is always used.
5.11 The _Pragma Operator
The ARM C/C++ compiler supports the C99 preprocessor _Pragma() operator. This preprocessor operator is similar to #pragma directives. However, _Pragma can be used in preprocessing macros (#defines).
The syntax of the operator is:
_Pragma ("string_literal"); |
The argument string_literal is interpreted in the same way the tokens following a #pragma directive are processed. The string_literal must be enclosed in quotes. A quotation mark that is part of the string_literal must be preceded by a backward slash.
You can use the _Pragma operator to express #pragma directives in macros. For example, the DATA_SECTION syntax:
#pragma DATA_SECTION( func ," section ")
Is represented by the _Pragma() operator syntax:
_Pragma ("DATA_SECTION( func ,\" section \")")
The following code illustrates using _Pragma to specify the DATA_SECTION pragma in a macro:
...
#define EMIT_PRAGMA(x) _Pragma(#x)
#define COLLECT_DATA(var) EMIT_PRAGMA(DATA_SECTION(var,"mysection"))
COLLECT_DATA(x)
int x;
...
The EMIT_PRAGMA macro is needed to properly expand the quotes that are required to surround the section argument to the DATA_SECTION pragma.
5.12 Application Binary Interface
An Application Binary Interface (ABI) defines how functions that are written separately and compiled or assembled separately can work together. This involves standardizing data type storage, register conventions, and function structure and calling conventions. It should define linkname generation from C symbols. It defines the object file format and the debug format. It should document how the system is initialized. In the case of C++ it defines C++ name mangling and exception handling support.
The COFF ABI is not supported in v15.6.0.STS and later versions of the TI Code Generation Tools. If you want to produce COFF output files, please use v5.2 of the ARM tools and see SPRU151J.
The ARM ABIv2 has become an industry standard for the ARM architecture. It has these advantages:
- It enables interlinking of objects built with different tool chains. For example, this enables a library built with RVCT to be linked in with an application built with the ARM 4.6 toolset.
- It is well documented. The complete ARM ABI specifications are in the ARM Information Center.
- It is modern. EABI requires ELF object file format which enables supporting modern language features like early template instantiation and export inline functions support.
ARM ABIv2 allows a vendor to define the system initialization in the bare-metal mode. TI-specific information on EABI mode is described in Section 6.10.3. The __TI_EABI_ASSEMBLER predefined symbol is set to 1 if compiling for EABI.
5.13 ARM Instruction Intrinsics
Assembly instructions can be generated using the intrinsics in the following tables. Table 5-3 shows which intrinsics are available on the different ARM targets. Table 5-4 shows the calling syntax for each intrinsic, along with the corresponding assembly instruction and a description. Additional intrinsices for getting and setting the CPSR register and to enable/disable interrupts are provided in Section 6.8.1.
Table 5-3 ARM Intrinsic Support by Target
C/C++ Compiler Intrinsic | ARM V5e (ARM9E) | ARM V6 (ARM11) | ARM V6M0 (Cortex-M0) | ARM V7M3 (Cortex-M3) | ARM V7M4 (Cortex-M4) | ARM V7R (Cortex-R4) | ARM V7A8 (Cortex-A8) |
---|---|---|---|---|---|---|---|
_ _clz | yes | yes | yes | yes | yes | yes | |
_ _delay_cycles | yes | yes | yes | yes | |||
_ _get_MSP | yes | yes | yes | ||||
_ _get_PRIMASK | yes | yes | yes | ||||
_ _ldrex | yes | yes | yes | yes | yes | ||
_ _ldrexb | yes | yes | yes | yes | yes | ||
_ _ldrexd | yes | yes | yes | ||||
_ _ldrexh | yes | yes | yes | yes | yes | ||
_ _MCR | yes | yes | yes | yes | yes | yes | |
_ _MRC | yes | yes | yes | yes | yes | yes | |
_ _ nop | yes | yes | yes | yes | yes | yes | yes |
_norm | yes | yes | yes | yes | yes | yes | |
_ _rev | yes | yes | yes | yes | yes | ||
_ _rev16 | yes | yes | yes | yes | yes | ||
_ _revsh | yes | yes | yes | yes | yes | ||
_ _rbit | yes | yes | yes | yes | |||
_ _ror | yes | yes | yes | yes | yes | yes | yes |
_pkhbt | yes | yes | yes | yes | |||
_pkhtb | yes | yes | yes | yes | |||
_qadd16 | yes | yes | yes | yes | |||
_qadd8 | yes | yes | yes | yes | |||
_qaddsubx | yes | yes | yes | yes | |||
_qsub16 | yes | yes | yes | yes | |||
_qsub8 | yes | yes | yes | yes | |||
_qsubaddx | yes | yes | yes | yes | |||
_sadd | yes | yes | yes | yes | yes | ||
_sadd16 | yes | yes | yes | yes | |||
_sadd8 | yes | yes | yes | yes | |||
_saddsubx | yes | yes | yes | yes | |||
_sdadd | yes | yes | yes | yes | yes | ||
_sdsub | yes | yes | yes | yes | yes | ||
_sel | yes | yes | yes | yes | |||
_ _set_MSP | yes | yes | yes | ||||
_ _set_PRIMASK | yes | yes | yes | ||||
_shadd16 | yes | yes | yes | yes | |||
_shadd8 | yes | yes | yes | yes | |||
_shsub16 | yes | yes | yes | yes | |||
_shsub8 | yes | yes | yes | yes | |||
_smac | yes | yes | yes | yes | yes | ||
_smlabb | yes | yes | yes | yes | yes | ||
_smlabt | yes | yes | yes | yes | yes | ||
_smlad | yes | yes | yes | yes | |||
_smladx | yes | yes | yes | yes | |||
_smlalbb | yes | yes | yes | yes | yes | ||
_smlalbt | yes | yes | yes | yes | yes | ||
_smlald | yes | yes | yes | yes | |||
_smlaldx | yes | yes | yes | yes | |||
_smlaltb | yes | yes | yes | yes | yes | ||
_smlaltt | yes | yes | yes | yes | yes | ||
_smlatb | yes | yes | yes | yes | yes | ||
_smlatt | yes | yes | yes | yes | yes | ||
_smlawb | yes | yes | yes | yes | yes | ||
_smlawt | yes | yes | yes | yes | yes | ||
_smlsd | yes | yes | yes | yes | |||
_smlsdx | yes | yes | yes | yes | |||
_smlsld | yes | yes | yes | yes | |||
_smlsldx | yes | yes | yes | yes | |||
_smmla | yes | yes | yes | yes | |||
_smmlar | yes | yes | yes | yes | |||
_smmls | yes | yes | yes | yes | |||
_smmlsr | yes | yes | yes | yes | |||
_smmul | yes | yes | yes | yes | |||
_smmulr | yes | yes | yes | yes | |||
_smuad | yes | yes | yes | yes | |||
_smuadx | yes | yes | yes | yes | |||
_smusd | yes | yes | yes | yes | |||
_smusdx | yes | yes | yes | yes | |||
_smpy | yes | yes | yes | yes | yes | ||
_smsub | yes | yes | yes | yes | yes | ||
_smulbb | yes | yes | yes | yes | yes | ||
_smulbt | yes | yes | yes | yes | yes | ||
_smultb | yes | yes | yes | yes | yes | ||
_smultt | yes | yes | yes | yes | yes | ||
_smulwb | yes | yes | yes | yes | yes | ||
_smulwt | yes | yes | yes | yes | yes | ||
_ _sqrt | yes | yes | yes | yes | |||
_ _sqrtf | yes | yes | yes | yes | yes | ||
_ssat16 | yes | yes | yes | yes | |||
_ssata | yes | yes | yes | yes | yes | yes | |
_ssatl | yes | yes | yes | yes | yes | yes | |
_ssub | yes | yes | yes | yes | yes | ||
_ssub16 | yes | yes | yes | yes | |||
_ssub8 | yes | yes | yes | yes | |||
_ssubaddx | yes | yes | yes | yes | |||
_ _strex | yes | yes | yes | yes | yes | ||
_ _strexb | yes | yes | yes | yes | yes | ||
_ _strexd | yes | yes | yes | ||||
_ _strexh | yes | yes | yes | yes | yes | ||
_subc | yes | yes | yes | yes | yes | ||
_sxtab | yes | yes | yes | yes | |||
_sxtab16 | yes | yes | yes | yes | |||
_sxtah | yes | yes | yes | yes | |||
_sxtb | yes | yes | yes | yes | yes | yes | |
_sxtb16 | yes | yes | yes | yes | |||
_sxth | yes | yes | yes | yes | yes | yes | |
_uadd16 | yes | yes | yes | yes | |||
_uadd8 | yes | yes | yes | yes | |||
_uaddsubx | yes | yes | yes | yes | |||
_uhadd16 | yes | yes | yes | yes | |||
_uhadd8 | yes | yes | yes | yes | |||
_uhsub16 | yes | yes | yes | yes | |||
_uhsub8 | yes | yes | yes | yes | |||
_umaal | yes | yes | yes | yes | |||
_uqadd16 | yes | yes | yes | yes | |||
_uqadd8 | yes | yes | yes | yes | |||
_uqaddsubx | yes | yes | yes | yes | |||
_uqsub16 | yes | yes | yes | yes | |||
_uqsub8 | yes | yes | yes | yes | |||
_uqsubaddx | yes | yes | yes | yes | |||
_usad8 | yes | yes | yes | yes | |||
_usat16 | yes | yes | yes | yes | |||
_usata | yes | yes | yes | yes | yes | yes | |
_usatl | yes | yes | yes | yes | yes | yes | |
_usub16 | yes | yes | yes | yes | |||
_usub8 | yes | yes | yes | yes | |||
_usubaddx | yes | yes | yes | yes | |||
_uxtab | yes | yes | yes | yes | |||
_uxtab16 | yes | yes | yes | yes | |||
_uxtah | yes | yes | yes | yes | |||
_uxtb | yes | yes | yes | yes | yes | yes | |
_uxtb16 | yes | yes | yes | yes | |||
_uxth | yes | yes | yes | yes | yes | yes | |
_ _wfe | yes | yes | yes | yes | yes | ||
_ _wfi | yes | yes | yes | yes | yes |
Table 5-4 shows the calling syntax for each intrinsic, along with the corresponding assembly instruction and a description. See Table 5-3 for a list of which intrinsics are available on the different ARM targets. Additional intrinsices for getting and setting the CPSR register and to enable/disable interrupts are provided in Section 6.8.1.
Table 5-4 ARM Compiler Intrinsics
C/C++ Compiler Intrinsic | Assembly Instruction |
Description |
---|---|---|
int count = _ _clz(int src); | CLZ count , src | Returns the count of leading zeros |
void _ _delay_cycles( unsigned int cycles); | varies | Delays execution for the specified number of cycles. The number of cycles must be a constant. The __delay_cycles intrinsic inserts code to consume precisely the number of specified cycles with no side effects. The number of cycles delayed must be a compile-time constant. Note: Cycle timing is based on 0 wait states. Results vary with additional wait states. The implementation does not account for dynamic prediction. Lower delay cycle counts may be less accurate given pipeline flush behaviors. |
unsigned int dst = _ _get_MSP(void ); | MRS dst , MSP | Returns the current value of the Main Stack Pointer. |
unsigned int dst = _ _get_PRIMASK(void ); | MRS dst , PRIMASK | Returns the current value of the Priority Mask Register. If this value is 1, activation of all exceptions with configurable priority is prevented. |
unsigned int dest = _ _ldrex(void* src); | LDREX dst , src | Loads data from memory address containing word (32-bit) data |
unsigned int dest= _ _ldrexb(void* src); | LDREXB dst , src | Loads data from memory address containing byte data |
unsigned long long dest = _ _ldrexd(void* src); | LDREXD dst , src | Loads data from memory address with long long support |
unsigned int dest = _ _ldrexh(void* src); | LDREXH dst , src | Loads data from memory address containing halfword (16-bit) data |
void __MCR (unsigned int coproc, unsigned int opc1, unsigned int src, unsigned int coproc_reg1, unsigned int coproc_reg2, unsigned int opc2); | MCR coproc, opc1, src, CR<coproc_reg1>, CR<coproc_reg2>, opc2 | Access the coprocessor registers |
unsigned int __MRC(unsigned int coproc, unsigned int opc1, unsigned int coproc_reg1, unsigned int coproc_reg2, unsigned int opc2); | MRC coproc, opc1, src, CR<coproc_reg1>, CR<coproc_reg2>, opc2 | Access the coprocessor registers |
void _ _nop( void ); | NOP | Perform an instruction that does nothing. |
int dst = _norm(int src); | CLZdst, src | Normalize floating point |
int dst = _pkhbt(int src1, int src2, int shift); | PKHBT dst , src1 , src2 , # shift | Combine bottom halfword of src1 with shifted top halfword of src2 |
nt dst = _pkhtb(int src1, int src2, int shift); | PKHTB dst , src1 , src2 , # shift | Combine top halfword of src1 with shifted bottom halfword of src2 |
int dst = _qadd16(int src1, int src2 ); | QADD16 dst , src1 , src2 | Performs two signed halfword saturated additions |
int dst = _qadd8(int src1, int src2 ); | QADD8 dst , src1 , src2 | Performs four signed saturated 8-bit additions |
int dst = _qaddsubx(int src1, int src2); | QASX dst , src1 , src2 | Exchange halfwords of src2, perform signed saturated addition on the top halfwords and signed saturated subtraction on the bottom halfwords. |
int dst = _qsub16(int src1, int src2 ); | QSUB16 dst , src1 , src2 | Performs two signed saturated halfword subtractions |
int dst = _qsub8(int src1, int src2 ); | QSUB8 dst , src1 , src2 | Performs four signed saturated 8-bit subtractions |
int dst = _qsubaddx(int src1, int src2); | QSAX dst , src1 , src2 | Exchange halfwords of src2, perform signed saturated subtraction on top halfwords and signed saturated addition on bottom halfwords |
int dst = _ _rbit(int src); | RBIT dst , src | Reverses the bit order in a word. |
int dst = _ _rev(int src); | REV dst , src | Reverses byte order in a word. That is, converts 32-bit data between big-endian and little-endian or vice versa. |
int dst = _ _rev16(int src); | REV16 dst , src | Reverses byte order in each byte in a word independently. That is, converts 16-bit data between big-endian and little-endian or vice versa. |
int dst = _ _revsh(int src); | REVSH dst , src | Reverses byte order in the lower byte of a word, and extends the sign to 32 bits. That is, converts 16-bit signed data to 32-bit signed data, while also converting between big-endian and little-endian or vice versa. |
int dst = _ _ror(int src , int shift); | ROR dst , src , shift | Rotates the value to the right by the number of bits specified. Bits rotated off the right end are placed into empty bits on the left. |
int dst =_sadd(int src1, int src2); | QADDdst, src1, src2 | Saturated add |
int dst = _sadd16(int src1, int src2); | SADD16dst , src1 , src2 | Performs two signed halfword additions |
int dst = _sadd8(int src1, int src2); | SADD8 dst , src1 , src2 | Performs four signed 8-bit additions |
int dst = _saddsubx(int src1, int src2); | SASX dst , src1 , src2 | Exchange halfwords of src2, add the top halfwords and subtract the bottom halfwords |
int dst =_sdadd(int src1, int src2); | QDADDdst, src1, src2 | Saturated double-add |
int dst =_sdsub(int src1, int src2); | QDSUBdst, src1, src2 | Saturated double-subtract |
int dst = _sel(int src1, int src2); | SEL dst , src1 , src2 | Selects byte n from src1 if GE bit n is set or from src2 if GE bit n is not set, where n ranges from 0 to 3. |
void _ _set_MSP(unsigned int src); | MSR MSP, src | Sets the value of the Main Stack Pointer to src. |
unsigned int dst = _ _set_PRIMASK(unsigned int src); |
MRS
dst
, PRIMASK (optional) MSR PRIMASK,src |
Sets the Priority Mask Register to the src value and returns the value as it was prior to being set as dst. Setting this register to 1 prevents the activation of all exceptions with configurable priority. |
int dst = _shadd16(int src1, int src2); | SHADD16 dst , src1 , src2 | Performs two signed halfword additions and halves the results |
int dst = _shadd8(int src1, int src2); | SHADD8 dst , src1 , src2 | Performs four signed 8-bit additions and halves the results |
int dst = _shsub16(int src1, int src2); | SHSUB16 dst , src1 , src2 | Performs two signed halfword subtractions and halves the results |
int dst = _shsub8int src1, int src2); | SHSUB8 dst , src1 , src2 | Performs four signed 8-bit subtractions and halves the results |
int dst =_smac(int src1, int src2); | SMULBBtmp, src1, src2 QDADDdst, dst, tmp |
Saturated multiply-accumulate |
int dst =_smlabb(int dst, short src1, short src2); | SMLABBdst, src1, src2 | Signed multiply-accumulate bottom halfwords |
int dst =_smlabt(int dst, short src1, int src2); | SMLABTdst, src1, src2 | Signed multiply-accumulate bottom and top halfwords |
int dst_smlad(int src1, int src2, int acc); | SMLAD dst , src1 , src2 , acc | Performs two signed 16-bit multiplications on the top and bottom halfwords of src1 and src2 and adds the results to acc. |
int dst_smladx(int src1, int src2, int acc); | SMLADX dst , src1 , src2 , acc | Same as _smlad except the halfwords in src2 are exchange before the multiplication. |
long long dst =_smlalbb(long long dst, short src1, short src2); | SMLALBBdstlo, dsthi, src1, src2 | Signed multiply-long and accumulate bottom halfwords |
long long dst =_smlalbt(long long dst, short src1, int src2); | SMLALBTdstlo, dsthi, src1, src2 | Signed multiply-long and accumulate bottom and top halfwords |
long long dst_smlald(long long acc , int src1, int src2); | SMLALD dst , src1 , src2 | Performs two 16-bit multiplication on the top and bottom halfwords of src1 and src2 and adds the results to the 64-bit acc operand |
long long dst_smlaldx(long long acc , int src1, int src2); | SMLALDX dst , src1 , src2 | Same as _smlald except the halfwords in src2 are exchanged. |
long long dst =_smlaltb(long long dst, int src1, short src2); | SMLALTBdstlo, dsthi, src1, src2 | Signed multiply-long and accumulate top and bottom halfwords |
long long dst =_smlaltt(long long dst, int src1, int src2); | SMLALTTdstlo, dsthi, src1, src2 | Signed multiply-long and accumulate top halfwords |
int dst =_smlatb(int dst, int src1, short src2); | SMLATBdst, src1, src2 | Signed multiply-accumulate top and bottom halfwords |
int dst =_smlatt(int dst, int src1, int src2); | SMLATTdst, src1, src2 | Signed multiply-accumulate top halfwords |
int dst_smlawb(int src1, short src2, int acc); | SMLAWBdst, src1, src2 | Signed multiply-accumulate word and bottom halfword |
int dst_smlawt(int src1, short src2, int acc); | SMLAWTdst, src1, src2 | Signed multiply-accumulate word and top halfword |
int dst_smlsd(int src1, int src2, int acc); | SMLSD dst , src1 , src2 , acc | Performs two signed 16-bit multiplications on the top and bottom halfwords of src1 and src2 and adds the difference of the results to acc. |
int dst_smlsdx(int src1, int src2, int acc); | SMLSDX dst , src1 , src2 , acc | Same as _smlsd except the halfwords in src2 are exchange before the multiplication. |
long long dst_smlsld(long long acc , int src1, int src2); | SMLSLD dst , src1 , src2 | Performs two 16-bit multiplication on the top and bottom halfwords of src1 and src2 and adds the difference of the results to the 64-bit acc operand. |
long long dst_smlsldx(long long acc , int src1, int src2); | SMLSLDX dst , src1 , src2 | Same as _smlsld except the halfwords in src2 are exchanged. |
int dst_smmla(int src1, int src2, int acc); | SMMLA dst , src1 , src2 , acc | Performs a signed multiplication on src1 and src2, extracts the most significant 32 bits of the result, and adds an accumulate value. |
int dst_smmlar(int src1, int src2, int acc); | SMMLAR dst , src1 , src2 , acc | Same as _smmla execpt the result is rounded instead of being truncated. |
int dst_smmls(int src1, int src2, int acc); | SMMLS dst , src1 , src2 , acc | Performs a signed multiplication on src1 and src2, subtracts the result from an accumulate value that is shifted left by 32 bits, and extracts the most significant 32 bits of the result of the subtraction. |
int dst_smmlsr(int src1, int src2, int acc); | SMMLSR dst , src1 , src2 , acc | Same as _smmls except the result is rounded instead of being truncated. |
int dst_smmul(int src1, int src2, int acc); | SMMUL dst , src1 , src2 , acc | Performs a signed 32-bit multiplication on src1 and src2 and extracts the most significant 32-bits of the result. |
int dst_smmulr(int src1, int src2, int acc); | SMMULR dst , src1 , src2 , acc | Same as _smmul except the result is rounded instead of being truncated. |
int dst =_smpy(int src1, int src2); | SMULBBdst, src1, src2 QADDdst, dst, dst |
Saturated multiply |
int dst =_smsub(int src1, int src2); | SMULBBtmp, src1, src2 QDSUBdst, dst, tmp |
Saturated multiply-subtract |
int dst_smuad(int src1, int src2, int acc); | SMUAD dst , src1 , src2 , acc | Performs two signed 16-bit multiplications on the top and bottom halfwords and adds the products. |
int dst_smuadx(int src1, int src2, int acc); | SMUADX dst , src1 , src2 , acc | Same as _smuad except the halfwords in src2 are exchange before the multiplication. |
int dst =_smulbb(int src1, int src2); | SMULBBdst, src1, src2 | Signed multiply bottom halfwords |
int dst =_smulbt(int src1, int src2); | SMULBTdst, src1, src2 | Signed multiply bottom and top halfwords |
int dst =_smultb(int src1, int src2); | SMULTBdst, src1, src2 | Signed multiply top and bottom halfwords |
int dst =_smultt(int src1, int src2); | SMULTTdst, src1, src2 | Signed multiply top halfwords |
int dst_smulwb(int src1, short src2, int acc); | SMULWBdst, src1, src2 | Signed multiply word and bottom halfword |
int dst_smulwt(int src1, short src2, int acc); | SMULWTdst, src1, src2 | Signed multiply word and top halfword |
int dst_smusd(int src1, int src2, int acc); | SMUSD dst , src1 , src2 , acc | Performs two signed 16-bit multiplications on the top and bottom halfwords and subtracts the products. |
int dst_smusdx(int src1, int src2, int acc); | SMUSDX dst , src1 , src2 , acc | Same as _smusd except the halfwords in src2 are exchanged before the multiplication. |
double __sqrt( double ); | VSQRT dst , src1 | Return the square root of the specified double. This intrinsic is directly replaced with the VSQRT instruction if --fp_mode=relaxed. If strict floating point mode is used, the function must also set an errno if a domain error occurs. |
float __sqrtf( float ); | VSQRT dst , src1 | Return the square root of the specified float. This intrinsic is directly replaced with the VSQRT instruction if --fp_mode=relaxed. If strict floating point mode is used, the function must also set an errno if a domain error occurs. |
int dst =_ssat16(int src, int bitpos); | SSAT16 dst , # bitpos | Performs two halfword saturations to a selectable signed range specified by bitpos |
int dst =_ssata(int src, int shift , int bitpos); | SSATdst, #bitpos,src, ASR #shift | Right shifts src and saturates to a selectable signed range specified by bitpos |
int dst =_ssatl(int src , int shift , int bitpos); | SSATdst, #bitpos,src, LSL #shift | Left shifts src and saturates to a selectable signed range specified by bitpos |
int dst =_ssub(int src1, int src2); | QSUBdst, src1, src2 | Saturated subtract |
int dst = _ssub16(int src1, int src2); | SSUB16dst , src1 , src2 | Performs two signed halfword subtractions |
int dst = _ssub8(int src1, int src2); | SSUB8 dst , src1 , src2 | Performs four signed 8-bit subtractions |
int dst = _ssubaddx(int src1, int src2); | SSAX dst , src1 , src2 | Exchange halfwords of src2, subtract the top halfwords and add the bottom halfwords |
int status = _ _strex(unsigned int src, void* dst); | STREX status , src , dest | Stores word (32-bit) data in memory address |
int status = _ _strexb(unsigned char src, void* dst); | STREXB status , src , dest | Stores byte data in memory address |
int status = _ _strexd(unsigned long long src, void* dst); | STREXD status , src , dest | Stores long long data in memory address |
int status = _ _strexh(unsigned short src, void* dst); | STREXH status , src , dest | Stores halfword (16-bit) data in memory address |
int dst = _subc(int src1, int src2); | SUBCdst, src1, src2 | Subtract with carry |
int dst_sxtab(int src1, int src2, int rotamt); | SXTAB dst , src1 , src2 , ROR # rotamt | Extracts an optionally rotated 8-bit value from src2 and sign extends it to 32 bits, then adds the value to src1. The rotation amount can be 0, 8, 16, or 24. |
int dst_sxtab16(int src1, int src2, int rotamt); | SXTAB16 dst , src1 , src2 , ROR # rotamt | Extracts two optionally rotated 8-bit values from src2 and sign extends them to 16 bits each, then adds the values to the two 16-bit values in src1. The rotation amount should be 0, 8, 16, or 24. |
int dst_sxtah(int src1, int src2, int rotamt); | SXTAH dst , src1 , src2 , ROR # rotamt | Extracts an optionally rotated 16-bit value from src2 and sign extends it to 32 bits, then adds the result to src1. The rotation amount can be 0, 8, 16, or 32. |
int dst_sxtb(int src1, int rotamt); | SXTBdst, src1, ROR #rotamt | Extracts an optionally rotated 8-bit value from src1 and sign extends it to 32 bits. The rotation amount can be 0, 8, 16, or 24. |
int dst_sxtb16(int src1, int rotamt); | SXTAB16 dst , src1 , ROR # rotamt | Extracts two optionally rotated 8-bit values from src1 and sign extends them to 16-bits. The rotation amount can be 0, 8, 16, or 24. |
int dst_sxth(int src1, int rotamt); | SXTHdst, src1, ROR #rotamt | Extracts an optionally rotated 16-bit value from src2 and sign extends it to 32 bits. The rotation amount can be 0, 8, 16, or 24. |
int dst = _uadd16(int src1, int src2); | UADD16 dst , src1 , src2 | Performs two unsigned halfword additions |
int dst = _uadd8(int src1, int src2); | UADD8 dst , src1 , src2 | Performs four unsigned 8-bit additions |
int dst = _uaddsubx(int src1, int src2); | UASX dst , src1 , src2 | Exchange halfwords of src2, add the top halfwords and subtract the bottom halfwords |
int dst = _uhadd16(int src1, int src2); | UHADD16 dst , src1 , src2 | Performs two unsigned halfword additions and halves the results |
int dst = _uhadd8(int src1, int src2); | UHADD8 dst , src1 , src2 | Performs four unsigned 8-bit additions and halves the results |
int dst = _uhsub16(int src1, int src2); | UHSUB16 dst , src1 , src2 | Performs two unsigned halfword subtractions and halves the results |
int dst = _uhsub8(int src1, int src2); | UHSUB8 dst , src1 , src2 | Performs four unsigned 8-bit subtractions and halves the results |
int dst = _umaal(long long acc , int src1 , int src2 ); | UMAAL dst1 , dst2 , src1 , src2 | Performs an unsigned 32-bit multiplication on src1 and src2, then adds two unsigned 32-bit values in acc. |
int dst = _uqadd16(int src1, int src2); | UQADD16 dst , src1 , src2 | Performs two unsigned halfword saturated additions |
int dst = _uqadd8(int src1, int src2); | UQADD8 dst , src1 , src2 | Performs four unsigned saturated 8-bit additions |
int dst = _uqaddsubx(int src1, int src2); | UQASX dst , src1 , src2 | Exchange halfwords of src2, perform unsigned saturated addition on the top halfwords and unsigned saturated subtraction on the bottom halfwords. |
int dst = _uqsub16(int src1, int src2); | UQSUB16 dst , src1 , src2 | Performs two unsigned saturated halfword subtractions |
int dst = _uqsub8(int src1, int src2); | UQSUB8 dst , src1 , src2 | Performs four unsigned saturated 8-bit subtractions |
int dst = _uqsubaddx(int src1, int src2); | UQSAX dst , src1 , src2 | Exchange halfwords of src2, perform unsigned saturated subtraction on top halfwords and unsigned saturated addition on bottom halfwords |
int dst = _usad8(int src1, int src2); | USAD8 dst , src1 , src2 | Performs four unsigned 8-bit subtractions, and adds the absolute value of the differences together. |
int dst =_usat16(int src, int bitpos); | USAT16dst, #bitpos | Performs two halfword saturations to a selectable unsigned range specified by bitpos |
int dst =_usata(int src, int shift, int bitpos); | USATdst, #bitpos,src, ASR #shift | Right shifts src and saturates to a selectable unsigned range specified by bitpos |
int dst =_usatl(int src, int shift, int bitpos); | USATdst, #bitpos,src, LSL #shift | Left shifts src and saturates to a selectable unsigned range specified by bitpos |
int dst = _usub16(int src1, int src2); | USUB16 dst , src1 , src2 | Performs two unsigned halfword subtractions |
int dst = _usub8(int src1, int src2); | USUB8 dst , src1 , src2 | Performs four unsigned 8-bit subtractions |
int dst = _usubaddx(int src1, int src2); | USAX dst , src1 , src2 | Exchange halfwords of src2, subtract the top halfwords and add the bottom halfwords |
int dst_uxtab(int src1, int src2, int rotamt); | UXTAB dst , src1 , src2 , ROR # rotamt | Extracts an optionally rotated 8-bit value from src2 and zero extends it to 32 bits, then adds the value to src1. The rotation amount can be 0, 8, 16, or 24. |
int dst_uxtab16(int src1, int src2, int rotamt); | UXTAB16 dst , src1 , src2 , ROR # rotamt | Extracts two optionally rotated 8-bit values from src2 and zero extends them to 16 bits each, then adds the values to the two 16-bit values in src1. The rotation amount should be 0, 8, 16, or 24. |
int dst_uxtah(int src1, int src2, int rotamt); | UXTAH dst , src1 , src2 , ROR # rotamt | Extracts an optionally rotated 16-bit value from src2 and zero extends it to 32 bits, then adds the result to src1. The rotation amount can be 0, 8, 16, or 32. |
int dst_uxtb(int src1, int rotamt); | UXTB dst , src1 , ROR # rotamt | Extracts an optionally rotated 8-bit value from src2 and zero extends it to 32 bits. The rotation amount can be 0, 8, 16, or 24. |
int dst_uxtb16(int src1, int rotamt); | UXTB16 dst , src1 , ROR # rotamt | Extracts two optionally rotated 8-bit values from src1 and zero extends them to 16-bits. The rotation amount can be 0, 8, 16, or 24. |
int dst_uxth(int src1, int rotamt); | UXTH dst , src1 , ROR # rotamt | Extracts an optionally rotated 16-bit value from src2 and zero extends it to 32 bits. The rotation amount can be 0, 8, 16, or 24. |
void _ _wfe( void ); | WFE | Wait for event. Save power by waiting for an exception or event.. |
void _ _wfi( void ); | WFI | Wait for interrupt. Enter standby, dormant or shutdown mode, where an interrupt is required to wake-up the processor. |
5.14 Object File Symbol Naming Conventions (Linknames)
Each externally visible identifier is assigned a unique symbol name to be used in the object file, a so-called linkname. This name is assigned by the compiler according to an algorithm which depends on the name, type, and source language of the symbol. This algorithm may add a prefix to the identifier (typically an underscore), and it may mangle the name.
User-defined symbols in C code and in assembly code are in the same namespace, which means you are responsible for making sure that your C identifiers do not collide with your assembly code identifiers. You may have identifiers that collide with assembly keywords (for instance, register names); in this case, the compiler automatically uses an escape sequence to prevent the collision. The compiler escapes the identifier with double parallel bars, which instructs the assembler not to treat the identifier as a keyword. You are responsible for making sure that C identifiers do not collide with user-defined assembly code identifiers.
Name mangling encodes the types of the parameters of a function in the linkname for a function. Name mangling only occurs for C++ functions which are not declared 'extern "C"'. Mangling allows function overloading, operator overloading, and type-safe linking. Be aware that the return value of the function is not encoded in the mangled name, as C++ functions cannot be overloaded based on the return value.
For example, the general form of a C++ linkname for a 32-bit function named func is:
__func__F parmcodes
Where parmcodes is a sequence of letters that encodes the parameter types of func.
For this simple C++ source file:
int foo(int I){ } //global C++ function compiled in 16-bit mode
This is the resulting assembly code:
$__foo__Fi
The linkname of foo is $__foo__Fi, indicating that foo is a 16-bit function that takes a single argument of type int. To aid inspection and debugging, a name demangling utility is provided that demangles names into those found in the original C++ source. See Section 8 for more information.
The mangling algorithm follows that described in the Itanium C++ ABI (http://www.codesourcery.com/cxx-abi/abi.html).
int foo(int i) { } would be mangled "_Z3fooi"
NOTE
EABI Mode C++ DemanglingThe EABI mode has a different C++ demangling scheme. For instance, there is no prefix (either _ or $). Please refer to the ARM Information Center for details.
5.15 Changing the ANSI/ISO C/C++ Language Mode
The language mode command-line options determine how the compiler interprets your source code. You specify one option to identify which language standard your code follows. You can also specify a separate option to specify how strictly the compiler should expect your code to conform to the standard.
Specify one of the following language options to control the language standard that the compiler expects the source to follow. The options are:
- ANSI/ISO C89 (--c89, default for C files)
- ANSI/ISO C99 (--c99, see Section 5.15.1.)
- ISO C++03 (--c++03, default for C++ files)
Use one of the following options to specify how strictly the code conforms to the standard:
- Relaxed ANSI/ISO (--relaxed_ansi or -pr) This is the default.
- Strict ANSI/ISO (--strict_ansi or -ps)
The default is relaxed ANSI/ISO mode. Under relaxed ANSI/ISO mode, the compiler accepts language extensions that could potentially conflict with ANSI/ISO C/C++. Under strict ANSI mode, these language extensions are suppressed so that the compiler will accept all strictly conforming programs. (See Section 5.15.2.)
5.15.1 Enabling C99 Mode (--c99)
The compiler supports the 1999 standard of C as standardized by the ISO. However, the following list of run-time functions and features are not implemented or fully supported:
- complex.h
- ctype.h
- isblank()
- inttypes.h
- wcstoimax() / wcstoumax()
- stdarg.h
- va_copy macro
- stdio.h
- %a and %A format specifiers for hexadecimal float
- The %e specifier may produce "-0" when "0" is expected by the standard
- snprintf() does not properly pad with spaces when writing to a wide character array
- stdlib.h
- strtof() atof() / strtod() / strtold() do not support hexadecimal float strings
- vfscanf() / vscanf() / vsscanf() return value on floating point matching failure is incorrect
- tgmath.h
- time.h
- strftime()
- wchar.h
- getws() / fputws()
- mbrlen()
- mbsrtowcs()
- wcscat()
- wcschr()
- wcscmp() / wcsncmp()
- wcscpy() / wcsncpy()
- wcsftime()
- wcsrtombs()
- wcsstr()
- wcstok()
- wcsxfrm()
- Wide character print / scan functions
- Wide character conversion functions
5.15.2 Enabling Strict ANSI/ISO Mode and Relaxed ANSI/ISO Mode (--strict_ansi and --relaxed_ansi Options)
Under relaxed ANSI/ISO mode (the default), the compiler accepts language extensions that could potentially conflict with a strictly conforming ANSI/ISO C/C++ program. Under strict ANSI mode, these language extensions are suppressed so that the compiler will accept all strictly conforming programs.
Use the --strict_ansi option when you know your program is a conforming program and it will not compile in relaxed mode. In this mode, language extensions that conflict with ANSI/ISO C/C++ are disabled and the compiler will emit error messages where the standard requires it to do so. Violations that are considered discretionary by the standard may be emitted as warnings instead.
Examples:
The following is strictly conforming C code, but will not be accepted by the compiler in the default relaxed mode. To get the compiler to accept this code, use strict ANSI mode. The compiler will suppress the interrupt keyword language exception, and interrupt may then be used as an identifier in the code.
int main()
{
int interrupt = 0;
return 0;
}
The following is not strictly conforming code. The compiler will not accept this code in strict ANSI mode. To get the compiler to accept it, use relaxed ANSI mode. The compiler will provide the interrupt keyword extension and will accept the code
interrupt void isr(void);
int main()
{
return 0;
}
The following code is accepted in all modes. The __interrupt keyword does not conflict with the ANSI/ISO C standard, so it is always available as a language extension.
__interrupt void isr(void);
int main()
{
return 0;
}
The default mode is relaxed ANSI. This mode can be selected with the --relaxed_ansi (or -pr) option. Relaxed ANSI mode accepts the broadest range of programs. It accepts all TI language extensions, even those which conflict with ANSI/ISO, and ignores some ANSI/ISO violations for which the compiler can do something reasonable. The GCC language extensions described in Section 5.16 are available in relaxed ANSI/ISO mode.
5.16 GNU Language Extensions
The GNU compiler collection (GCC) defines a number of language features not found in the ANSI/ISO C and C++ standards. The definition and examples of these extensions (for GCC version 4.7) can be found at the GNU web site, https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/C-Extensions.html#C-Extensions.
Most of these extensions are also available for C++ source code.
5.16.1 Extensions
Most of the GCC language extensions are available in the TI compiler when compiling in relaxed ANSI mode (--relaxed_ansi).
The extensions that the TI compiler supports are listed in Table 5-5, which is based on the list of extensions found at the GNU web site. The shaded rows describe extensions that are not supported.
Table 5-5 GCC Language Extensions
Extensions | Descriptions |
---|---|
Statement expressions | Putting statements and declarations inside expressions (useful for creating smart 'safe' macros) |
Local labels | Labels local to a statement expression |
Labels as values | Pointers to labels and computed gotos |
Nested functions | As in Algol and Pascal, lexical scoping of functions |
Constructing calls | Dispatching a call to another function |
Naming types(1) | Giving a name to the type of an expression |
typeof operator | typeof referring to the type of an expression |
Generalized lvalues | Using question mark (?) and comma (,) and casts in lvalues |
Conditionals | Omitting the middle operand of a ?: expression |
long long | Double long word integers and long long int type |
Hex floats | Hexadecimal floating-point constants |
Complex | Data types for complex numbers |
Zero length | Zero-length arrays |
Variadic macros | Macros with a variable number of arguments |
Variable length | Arrays whose length is computed at run time |
Empty structures | Structures with no members |
Subscripting | Any array can be subscripted, even if it is not an lvalue. |
Escaped newlines | Slightly looser rules for escaped newlines |
Multi-line strings(1) | String literals with embedded newlines |
Pointer arithmetic | Arithmetic on void pointers and function pointers |
Initializers | Non-constant initializers |
Compound literals | Compound literals give structures, unions, or arrays as values |
Designated initializers | Labeling elements of initializers |
Cast to union | Casting to union type from any member of the union |
Case ranges | 'Case 1 ... 9' and such |
Mixed declarations | Mixing declarations and code |
Function attributes | Declaring that functions have no side effects, or that they can never return |
Attribute syntax | Formal syntax for attributes |
Function prototypes | Prototype declarations and old-style definitions |
C++ comments | C++ comments are recognized. |
Dollar signs | A dollar sign is allowed in identifiers. |
Character escapes | The character ESC is represented as \e |
Variable attributes | Specifying the attributes of variables |
Type attributes | Specifying the attributes of types |
Alignment | Inquiring about the alignment of a type or variable |
Inline | Defining inline functions (as fast as macros) |
Assembly labels | Specifying the assembler name to use for a C symbol |
Extended asm | Assembler instructions with C operands |
Constraints | Constraints for asm operands |
Alternate keywords | Header files can use __const__, __asm__, etc |
Explicit reg vars | Defining variables residing in specified registers |
Incomplete enum types | Define an enum tag without specifying its possible values |
Function names | Printable strings which are the name of the current function |
Return address | Getting the return or frame address of a function (limited support) |
Other built-ins | Other built-in functions (see Section 5.16.5) |
Vector extensions | Using vector instructions through built-in functions |
Target built-ins | Built-in functions specific to particular targets |
Pragmas | Pragmas accepted by GCC |
Unnamed fields | Unnamed struct/union fields within structs/unions |
Thread-local | Per-thread variables |
Binary constants | Binary constants using the '0b' prefix. |
5.16.2 Function Attributes
The following GCC function attributes are supported:
- alias
- always_inline
- const
- constructor
- deprecated
- format
- format_arg
- interrupt
- malloc
- noinline
- noreturn
- pure
- ramfunc
- section
- unused
- used
- visibility
- warn_unused_result
For example, this function declaration uses the alias attribute to make "my_alias" a function alias for the "myFunc" function:
void my_alias() __attribute__((alias("myFunc")));
The format attribute is applied to the declarations of printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf, scanf, fscanf, vfscanf, vscanf, vsscanf, and sscanf in stdio.h. Thus when GCC extensions are enabled, the data arguments of these functions are type checked against the format specifiers in the format string argument and warnings are issued when there is a mismatch. These warnings can be suppressed in the usual ways if they are not desired.
See Section 5.10.15 for more about the interrupt function attribute.
The malloc attribute is applied to the declarations of malloc, calloc, realloc and memalign in stdlib.h.
The ramfunc attribute specifies that a function will be placed in and executed from RAM. The ramfunc attribute allows the compiler to optimize functions for RAM execution, as well as to automatically copy functions to RAM on flash-based devices. For example:
__attribute__((ramfunc))
void f(void) {
...
}
The --ramfunc=on option specifies that all functions compiled with this option are placed in and executed from RAM, even if this function attribute is not used.
Newer TI linker command files support the ramfunc attribute automatically by placing functions with this attribute in the .TI.ramfunc section. If you have a linker command file that does not include a section specification for the .TI.ramfunc section, you can modify the linker command file to place this section in RAM. See the Placing functions in RAM wiki page for more about the ramfunc attribute and option. See the ARM Assembly Language Tools User's Guide for details on section placement.
5.16.3 Variable Attributes
The following variable attributes are supported: aligned, deprecated, mode, noinit, persistent, section, transparent_union, unused, used, and weak.
The used attribute is defined in GCC 4.2 (see https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Variable-Attributes.html#Variable-Attributes).
In addition, the packed attribute may be applied to individual fields within a struct or union. The packed attribute is supported on all ARM targets. See the description of the --unaligned_access option for more information on how the compiler accesses unaligned data.
5.16.4 Type Attributes
The following type attributes are supported: aligned, deprecated, packed, transparent_union, unused, and visibility.
The packed attribute is supported for struct and union types. It is supported on all ARM targets if the --relaxed_ansi option is used. See the description of the --unaligned_access option for more information on how the compiler accesses unaligned data.
Members of a packed structure are stored as closely to each other as possible, omitting additional bytes of padding usually added to preserve word-alignment. For example, assuming a word-size of 4 bytes ordinarily has 3 bytes of padding between members c1 and i, and another 3 bytes of trailing padding after member c2, leading to a total size of 12 bytes:
struct unpacked_struct { char c1; int i; char c2;};
However, the members of a packed struct are byte-aligned. Thus the following does not have any bytes of padding between or after members and totals 6 bytes:
struct __attribute__((__packed__)) packed_struct { char c1; int i; char c2; };
Subsequently, packed structures in an array are packed together without trailing padding between array elements.
Bit fields of a packed structure are bit-aligned. The byte alignment of adjacent struct members that are not bit fields does not change. However, there are no bits of padding between adjacent bit fields.
The packed attribute can only be applied to the original definition of a structure or union type. It cannot be applied with a typedef to a non-packed structure that has already been defined, nor can it be applied to the declaration of a struct or union object. Therefore, any given structure or union type can only be packed or non-packed, and all objects of that type will inherit its packed or non-packed attribute.
The packed attribute is not applied recursively to structure types that are contained within a packed structure. Thus, in the following example the member s retains the same internal layout as in the first example above. There is no padding between c and s, so s falls on an unaligned boundary:
struct __attribute__((__packed__)) outer_packed_struct { char c; struct unpacked_struct s; };
It is illegal to implicitly or explicitly cast the address of a packed struct member as a pointer to any non-packed type except an unsigned char. In the following example, p1, p2, and the call to foo are all illegal.
void foo(int *param);
struct packed_struct ps;
int *p1 = &ps.i;
int *p2 = (int *)&ps.i;
foo(&ps.i);
However, it is legal to explicitly cast the address of a packed struct member as a pointer to an unsigned char:
unsigned char *pc = (unsigned char *)&ps.i;
The TI compiler also supports an unpacked attribute for an enumeration type to allow you to indicate that the representation is to be an integer type that is no smaller than int; in other words, it is not packed.
5.16.5 Built-In Functions
The following built-in functions are supported: __builtin_abs, __builtin_classify_type, __builtin_constant_p, __builtin_expect, __builtin_fabs, __builtin_fabsf, __builtin_frame_address, __builtin_labs, __builtin_llabs, __builtin_sqrt, __builtin_sqrtf, __builtin_memcpy, and __builtin_return_address.
The __builtin_frame_address function returns zero unless the argument is a constant zero.
The __builtin_return_address function always returns zero.
5.17 AUTOSAR
The ARM compiler supports the AUTOSAR 3.1 standard by providing the following header files:
- Compiler.h
- Platform_Types.h
- Std_Types.h
- Compiler_Cfg.h
Compiler_Cfg.h is an empty file, the contents of which should be provided by the end user. The provided file contains information on what the contents of the file should look like. It is included by Compiler.h. If a new Compiler_Cfg.h file is provided by the user, its include path must come before the path to the run-time-support header files.
More information on AUTOSAR can be found at https://www.autosar.org.
5.18 Compiler Limits
Due to the variety of host systems supported by the C/C++ compiler and the limitations of some of these systems, the compiler may not be able to successfully compile source files that are excessively large or complex. In general, exceeding such a system limit prevents continued compilation, so the compiler aborts immediately after printing the error message. Simplify the program to avoid exceeding a system limit.
Some systems do not allow filenames longer than 500 characters. Make sure your filenames are shorter than 500.
The compiler has no arbitrary limits but is limited by the amount of memory available on the host system. On smaller host systems such as PCs, the optimizer may run out of memory. If this occurs, the optimizer terminates and the shell continues compiling the file with the code generator. This results in a file compiled with no optimization. The optimizer compiles one function at a time, so the most likely cause of this is a large or extremely complex function in your source module. To correct the problem, your options are:
- Don't optimize the module in question.
- Identify the function that caused the problem and break it down into smaller functions.
- Extract the function from the module and place it in a separate module that can be compiled without optimization so that the remaining functions can be optimized.
Copyright© 2016, Texas Instruments Incorporated. An IMPORTANT NOTICE for this document addresses availability, warranty, changes, use in safety-critical applications, intellectual property matters and other important disclaimers.