9.28.2 High-level assembly macros

MIPS assemblers have traditionally provided a wider range of instructions than the MIPS architecture itself. These extra instructions are usually referred to as “macro” instructions 2.

Some MIPS macro instructions extend an underlying architectural instruction while others are entirely new. An example of the former type is and, which allows the third operand to be either a register or an arbitrary immediate value. Examples of the latter type include bgt, which branches to the third operand when the first operand is greater than the second operand, and ulh, which implements an unaligned 2-byte load.

One of the most common extensions provided by macros is to expand memory offsets to the full address range (32 or 64 bits) and to allow symbolic offsets such as ‘my_data + 4’ to be used in place of integer constants. For example, the architectural instruction lbu allows only a signed 16-bit offset, whereas the macro lbu allows code such as ‘lbu $4,array+32769($5)’. The implementation of these symbolic offsets depends on several factors, such as whether the assembler is generating SVR4-style PIC (selected by -KPIC, see Assembler options), the size of symbols (see Directives to override the size of symbols), and the small data limit (see Controlling the use of small data accesses).

Sometimes it is undesirable to have one assembly instruction expand to several machine instructions. The directive .set nomacro tells the assembler to warn when this happens. .set macro restores the default behavior.

Some macro instructions need a temporary register to store intermediate results. This register is usually $1, also known as $at, but it can be changed to any core register reg using .set at=reg. Note that $at always refers to $1 regardless of which register is being used as the temporary register.

Implicit uses of the temporary register in macros could interfere with explicit uses in the assembly code. The assembler therefore warns whenever it sees an explicit use of the temporary register. The directive .set noat silences this warning while .set at restores the default behavior. It is safe to use .set noat while .set nomacro is in effect since single-instruction macros never need a temporary register.

Note that while the GNU assembler provides these macros for compatibility, it does not make any attempt to optimize them with the surrounding code.


Footnotes

(2)

The term “macro” is somewhat overloaded here, since these macros have no relation to those defined by .macro, see .macro.