3.1.2. Function keywords

Several keywords tell the compiler to give a function special treatment. These are all ARM extensions to the ANSI C specification:

Declarations inside functions

Declarations inside a function indicate that the following statements are processed differently. The asm keyword does not modify the surrounding function, but it does indicate that the statements following the keyword are different.

__asm

This instructs the compiler that the following code is written in assembler language (see Inline assembler).

Function qualifiers

Function qualifiers affect the type of a function. The qualifiers are placed after the parameter list in the same position that const and volatile can appear for C++ member function types.

__irq

This enables a C or C++ function to be used as an interrupt routine called by the IRQ or FIQ vectors. All corrupted registers except floating-point registers are preserved, not only those that are normally preserved under the ATPCS. The default ATPCS mode must be used. The function exits by setting the pc to lr–4 and the CPSR to the value in SPSR. It is not available in tcc or tcpp. No arguments or return values can be used with __irq functions.

See the chapter on Handling Processor Exceptions in the ADS Developer Guide for detailed information on using __irq.

__pure

This asserts that a function declaration is pure. Functions that are pure are candidates for common subexpression elimination. By default, functions are assumed to be impure (causing side-effects). A function is properly defined as pure only if:

  • its result depends exclusively on the values of its arguments

  • it has no side effects, for example it cannot call impure functions.

So, a pure function cannot use global variables or dereference pointers, because the compiler assumes that the function does not access memory (except stack memory) at all. When called twice with the same parameters, a pure function must return the same value each time.

The __pure declaration can also be used as a prefix or postfix declaration. In some cases the prefix form can be ambiguous and readability is improved by using the postfix form:

__pure void (*h(void))(void);  /* declares 'h' as a (pure?) function that returns a pointer to a (pure?) function.  It is ambiguous which of the two function types is pure. */
void (*h1(void) __pure)(void);  /* 'h1' is a pure function returning a pointer to a (normal) function */
__softfp

This asserts that a function uses software floating-point linkage. Calls to the function pass floating-point arguments in integer registers. If the result is a floating-point value, the value is returned in integer registers. This duplicates the behavior of compilation targeting software floating-point.

This keyword allows an identical library to be used by sources compiled to use hardware and software floating-point.

__swi

This declares a SWI function taking up to four integer-like arguments and returning up to four results in a value_in_regs structure. This causes function invocations to be compiled inline as an ATPCS compliant SWI that behaves similarly to a normal call to a function.

For a SWI returning no results use:

void __swi(swi_num) swi_name(int arg1,…, int argn);

For example:

void __swi(42) terminate_proc(int procnum);

For a SWI returning one result, use:

int __swi(swi_num) swi_name(int arg1,…, int argn);

For a SWI returning more than 1 result use:

typedef struct res_type { int res1,…,resn;} res_type;
res_type __value_in_regs __swi(swi_num) swi_name(
           int arg1,…,int argn);

The __value_in_regs qualifier is used to specify that a small structure of up to four words (16 bytes) is returned in registers, rather than by the usual structure-passing mechanism defined in the ATPCS.

See the chapter on Handling Processor Exceptions in the ADS Developer Guide for detailed information.

__swi_indirect

This passes an operation code to the SWI handler in r12:

int __swi_indirect(swi_num)	 
            swi_name(int real_num,	 
            int arg1, … argn);

where:

swi_num

Is the SWI number used in the SWI instruction.

real_num

Is the value passed in r12 to the SWI handler. You can use this feature to implement indirect SWIs. The SWI handler can use r12 to determine the function to perform.

For example:

int __swi_indirect(0) ioctl(int swino, int fn, 	
                            void *argp);

This SWI can be called as follows:

ioctl(IOCTL+4, RESET, NULL);

It compiles to a SWI 0 with IOCTL+4 in r12.

To use the indirect SWI mechanism, your system SWI handlers must make use of the r12 value to select the required operation.

__value_in_regs

This instructs the compiler to return a structure of up to four integer words in integer registers or up to four floats or doubles in floating-point registers rather than using memory, for example:

typedef struct int64_struct {	
    unsigned int lo;	
    unsigned int hi;	
} int64_struct;	
__value_in_regs extern 	
    int64_struct mul64(unsigned a, unsigned b);

Declaring a function __value_in_regs can be useful when calling assembler functions that return more than one result. See the AXD and armsd Debuggers Guide for information on the default method of passing and returning structures.

Note

A C++ function cannot return a __value_in_regs structure if the structure requires copy constructing.

Function storage class modifiers

A storage class modifier is a subset of function declaration keywords, however they do not affect the type of the function.

__inline

This instructs the compiler to compile a C function inline if it is sensible to do so. The semantics of __inline are exactly the same as those of the C++ inline keyword:

__inline int f(int x) {return x*5+1;}
int g(int x, int y) {return f(x) + f(y);}

The compiler compiles functions inline when __inline is used and the functions are not too large. Large functions are not compiled inline because they can adversely affect code density and performance. See Defining optimization criteria for information on command-line options that affect inlining.

__weak

This specifies an extern function or object declaration that, if not present, does not cause the linker to fault an unresolved reference. The linker does not load the function or object from a library unless another compilation uses the function or object non-weakly. If the reference remains unresolved, its value is assumed to be NULL. See the ADS Linker and Utilities Guide for details on library searching.

If the reference is made from code that compiles to a Branch or Branch Link instruction, the reference is resolved as branching to the next instruction. This effectively makes the branch a no-op:


__weak void f(void);
...
f(); // call f weakly 

A function or object cannot be used both weakly and non-weakly in the same compilation. For example the following code uses f() weakly from g() and h():


void f(void);
void g() {f();}
__weak void f(void);
void h() {f();}

It is not possible to use a function or object weakly from the same compilation that defines the function or object. The code below uses f() non-weakly from h():


__weak void f(void);
void h() {f();}
void f() {}

Copyright © 1999-2001 ARM Limited. All rights reserved.ARM DUI 0067D
Non-Confidential