| |||
| Home > ARM Compiler Reference > Compiler-specific features > Intrinsic functions | |||
The following intrinsic functions are ARM language extensions to the ISO C and C++ specifications:
These extensions are always available.
The __breakpoint() intrinsic enables you
to include an ARM or Thumb BKPT instruction in your
C or C++ code. You cannot use this intrinsic in inline assembly.
The syntax for this intrinsic is:
__breakpoint(value);
is a compile-time
constant integer, and must be included. The value must be an integer
in the range:value
if compiled as ARM code.
if compiled as Thumb code.
For example:
func() {
...
__breakpoint(0xF02C);
...
}
If __breakpoint() is used on architectures
that do not support the BKPT instruction, a warning
is generated. If a BKPT instruction is executed on
an architecture that does not support it, the undefined instruction
trap is taken.
The exact location of the BKPT instruction is
not guaranteed unless you specify the minimum optimization level -O0.
At all other optimization levels the compiler might move, but not
remove, the BKPT instruction.
For more details of the BKPT instruction, see RealView
Developer Kit v2.2 Assembler Guide.
Returns the value of the program counter (PC) at the point
where __current_pc() is used. The implicit prototype
for this intrinsic is:
int __current_pc(void)
If you have legacy source that accesses the pc register from inline assembly, see Legacy inline assembler that accesses sp, lr or pc.
Returns the value of the stack pointer (sp) at the point where __current_sp() is
used. The implicit prototype for this intrinsic is:
int __current_sp(void)
If you have legacy source that accesses the sp register
from inline assembly, see Legacy inline assembler that accesses
sp, lr or pc.
Returns the value of the link register (lr)
that is used to return from the current function. The implicit prototype
for this intrinsic is:
int __return_address(void)
If you have legacy source that accesses the lr register
from inline assembly, see Legacy inline assembler that accesses
sp, lr or pc.
The __return_address() intrinsic does not
affect the ability of the compiler to perform optimizations, such
as inlining, tail calling, and code sharing. However, the returned value
reflects the optimizations performed. For more details on the optimization options,
see Defining optimization criteria.
Different optimizations are applied as follows:
If a function call is inlined then the value returned by __return_address() is
the return address for the function that calls the inlined function.
If inlining and tail calling are disabled, the value
returned by __return_address() is the return
address of the next instruction in the calling function.
If a function call is inlined and
tail calling is enabled, then the value returned by __return_address() within
the called function is the return address for the caller function.
The __nop() intrinsic is used to insert
a single NOP instruction into the instruction stream generated
by the compiler. This enables you to, for example, insert a small
delay between reading and writing to a memory-mapped peripheral.
The implicit prototype for this intrinsic is:
void __nop(void)
One NOP instruction is generated for each __nop() in
the source. The compiler does not optimize-away the NOP instructions,
except for normal unreachable-code elimination. __nop() also
acts as a barrier for instruction scheduling in the compiler, that
is instructions are not moved from one side of the NOP to
the other as a result of optimization.
You can use the __schedule_barrier() intrinsic
to insert a scheduling barrier without generating a NOP instruction.
See Optimization barrier intrinsics for more information.
For example:
volatile int *hw_reg1;
volatile int *hw_reg2;
int update(int input)
{
/* update the peripheral */
*hw_reg1 = input;
/* allow peripheral time to update its status */
__nop();
/* read new status */
return *hw_reg2;
}
These functions enable you to control IRQ and FIQ interrupts (see Enabling and disabling interrupts).
The prototypes for these intrinsics are:
void __disable_irq(void); void __enable_irq(void); void __disable_fiq(void); void __enable_fiq(void);
__{dis,en}able_{ir,fi}q can only be executed
in privileged modes, that is, in non-user modes. In User mode these
instructions do not change the interrupt flags in the CPSR.
These intrinsics are available for all processor architectures in both ARM and Thumb state:
If you are compiling for processors
that support ARMv6 (or later), a CPS instruction is
generated inline for these functions, for example:
CPSID i
If you are compiling for processors that support
ARMv4 or ARMv5 in ARM state, the compiler inlines a sequence of MRS and MSR instructions,
for example:
MRS r0, CPSR
ORR r0, r0, #0x80
MSR CPSR_c, r0
If you are compiling for processors that support ARMv4 or ARMv5 in Thumb state, the compiler calls a helper function, for example:
BL __ARM_disable_irq
For more information on these instructions, see RealView Developer Kit v2.2 Assembler Guide.
You cannot use these functions to change any other CPSR bits including the mode, state, and imprecise data abort setting. This means that the intrinsics can be used only if the processor is already in a privileged mode, because the control bits of the CPSR and SPSR cannot be changed in User mode.
The ARM compiler can perform a range of optimizations, including re-ordering instructions and merging some operations. In some cases, such as system level programming where memory is being accessed concurrently by multiple processes, it might be necessary to disable instruction re-ordering and force memory to be updated.
The following optimization barrier intrinsics do not generate code, however they can result in slightly increased code size and additional memory accesses:
void __schedule_barrier(void); void __force_stored(void); void __memory_changed(void):
On some systems the memory barrier intriniscs might not be
sufficient to ensure memory consistency. For example, the __memory_changed() intrinsic
forces values held in registers to be written out to memory. However,
if the destination for the data is held in a bufferable region it
might wait in a write buffer. In this case you might also have to write
to CP15 to drain the write buffer. Refer to the Technical Reference
Manual for your ARM core for more information.
void
__schedule_barrier(void)A scheduling
barrier creates a sequence point where operations before and operations
after the sequence point are not merged by the compiler. A scheduling
barrier does not cause memory to be updated. If variables are held
in registers they are updated in place, and not written out. This intrinsic
is similar to the __nop() intrinsic, except
that no NOP instruction is generated.
void __force_stores(void)A force stores barrier causes all variables that
are visible outside the current function, such as variables that
have pointers to them passed into or out of the function, to be
written back to memory if they have been changed. The __force_stores() intrinsic
also acts as a scheduling barrier.
void __memory_changed(void)A memory changed barrier causes all variables that
are visible outside the current function, such as variables that
have pointers to them passed into or out of the function, to be
written back to memory if they have been changed, and then to be
read back from memory. The __memory_changed() intrinsic
also acts as a scheduling barrier.