42.5. Directives

The Xtensa assember supports a region-based directive syntax:

    .begin directive [options]
    …
    .end directive

All the Xtensa-specific directives that apply to a region of code use this syntax.

The directive applies to code between the .begin and the .end. The state of the option after the .end reverts to what it was before the .begin. A nested .begin/.end region can further change the state of the directive without having to be aware of its outer state. For example, consider:

    .begin no-density
L:  add a0, a1, a2
    .begin density
M:  add a0, a1, a2
    .end density
N:  add a0, a1, a2
    .end no-density

The generic ADD opcodes at L and N in the outer no-density region both result in ADD machine instructions, but the assembler selects an ADD.N instruction for the generic ADD at M in the inner density region.

The advantage of this style is that it works well inside macros which can preserve the context of their callers.

When command-line options and assembler directives are used at the same time and conflict, the one that overrides a default behavior takes precedence over one that is the same as the default. For example, if the code density option is available, the default is to select density instructions whenever possible. So, if the above is assembled with the -no-density flag, which overrides the default, all the generic ADD instructions result in ADD machine instructions. If assembled with the -density flag, which is already the default, the no-density directive takes precedence and only one of the generic ADD instructions is optimized to be a ADD.N machine instruction. An underscore prefix identifying a specific opcode always takes precedence over directives and command-line flags.

The following directives are available:

42.5.1. density

The density and no-density directives enable or disable optimization of generic instructions into density instructions within the region. Section 42.3.1 Using Density Instructions.

    .begin [no-]density
    .end [no-]density

This optimization is enabled by default unless the Xtensa configuration does not support the code density option or the -no-density command-line option was specified.

42.5.2. relax

The relax directive enables or disables relaxation within the region. Section 42.4 Xtensa Relaxation. Note: In the current implementation, these directives also control whether assembler optimizations are performed, making them equivalent to the generics and no-generics directives.

    .begin [no-]relax
    .end [no-]relax

Relaxation is enabled by default unless the -no-relax command-line option was specified.

42.5.3. longcalls

The longcalls directive enables or disables function call relaxation. Section 42.4.2 Function Call Relaxation.

    .begin [no-]longcalls
    .end [no-]longcalls

Call relaxation is disabled by default unless the -longcalls command-line option is specified.

42.5.4. generics

This directive enables or disables all assembler transformation, including relaxation (Section 42.4 Xtensa Relaxation) and optimization (Section 42.3 Xtensa Optimizations).

    .begin [no-]generics
    .end [no-]generics

Disabling generics is roughly equivalent to adding an underscore prefix to every opcode within the region, so that every opcode is treated as a specific opcode. Section 42.2.1 Opcode Names. In the current implementation of as, built-in macros are also disabled within a no-generics region.

42.5.5. literal

The .literal directive is used to define literal pool data, i.e., read-only 32-bit data accessed via L32R instructions.

    .literal label, value[, value…]

This directive is similar to the standard .word directive, except that the actual location of the literal data is determined by the assembler and linker, not by the position of the .literal directive. Using this directive gives the assembler freedom to locate the literal data in the most appropriate place and possibly to combine identical literals. For example, the code:

    entry sp, 40
    .literal .L1, sym
    l32r    a4, .L1

can be used to load a pointer to the symbol sym into register a4. The value of sym will not be placed between the ENTRY and L32R instructions; instead, the assembler puts the data in a literal pool.

By default literal pools are placed in a separate section; however, when using the -text-section-literals option (Section 42.1 Command Line Options), the literal pools are placed in the current section. These text section literal pools are created automatically before ENTRY instructions and manually after .literal_position directives (Section 42.5.6 literal_position). If there are no preceding ENTRY instructions or .literal_position directives, the assembler will print a warning and place the literal pool at the beginning of the current section. In such cases, explicit .literal_position directives should be used to place the literal pools.

42.5.6. literal_position

When using -text-section-literals to place literals inline in the section being assembled, the .literal_position directive can be used to mark a potential location for a literal pool.

    .literal_position

The .literal_position directive is ignored when the -text-section-literals option is not used.

The assembler will automatically place text section literal pools before ENTRY instructions, so the .literal_position directive is only needed to specify some other location for a literal pool. You may need to add an explicit jump instruction to skip over an inline literal pool.

For example, an interrupt vector does not begin with an ENTRY instruction so the assembler will be unable to automatically find a good place to put a literal pool. Moreover, the code for the interrupt vector must be at a specific starting address, so the literal pool cannot come before the start of the code. The literal pool for the vector must be explicitly positioned in the middle of the vector (before any uses of the literals, of course). The .literal_position directive can be used to do this. In the following code, the literal for M will automatically be aligned correctly and is placed after the unconditional jump.

    .global M
code_start:
    j continue
    .literal_position
    .align 4
continue:
    movi    a4, M

42.5.7. literal_prefix

The literal_prefix directive allows you to specify different sections to hold literals from different portions of an assembly file. With this directive, a single assembly file can be used to generate code into multiple sections, including literals generated by the assembler.

    .begin literal_prefix [name]
    .end literal_prefix

For the code inside the delimited region, the assembler puts literals in the section name.literal. If this section does not yet exist, the assembler creates it. The name parameter is optional. If name is not specified, the literal prefix is set to the "default" for the file. This default is usually .literal but can be changed with the -rename-section command-line argument.

42.5.8. freeregs

This directive tells the assembler that the given registers are unused in the region.

    .begin freeregs ri[,ri…]
    .end freeregs

This allows the assembler to use these registers for relaxations or optimizations. (They are actually only for relaxations at present, but the possibility of optimizations exists in the future.)

Nested freeregs directives can be used to add additional registers to the list of those available to the assembler. For example:

    .begin freeregs a3, a4
    .begin freeregs a5

has the effect of declaring a3, a4, and a5 all free.

42.5.9. frame

This directive tells the assembler to emit information to allow the debugger to locate a function's stack frame. The syntax is:

    .frame reg, size

where reg is the register used to hold the frame pointer (usually the same as the stack pointer) and size is the size in bytes of the stack frame. The .frame directive is typically placed immediately after the ENTRY instruction for a function.

In almost all circumstances, this information just duplicates the information given in the function's ENTRY instruction; however, there are two cases where this is not true:

  1. The size of the stack frame is too big to fit in the immediate field of the ENTRY instruction.

  2. The frame pointer is different than the stack pointer, as with functions that call alloca.