Hard Register Constraints (Using the GNU Compiler Collection (GCC))

#### 6.11.6.3 Hard Register Constraints ¶

Similar to register `asm` but still distinct, hard register constraints are another way to force operands of inline `asm` into specific machine registers. In contrast to register `asm` where a variable is bound to a machine register, a hard register constraint binds an `asm` operand to a machine register. Assume in the following that `r4` is a general-purpose register, `f5` a floating-point register, and `v6` a vector register for some target.

    int x;
    int y __attribute__ ((vector_size (16)));
    ...
    asm ("some instructions"
         : "={r4}" (x)
         : "{f5}" (42.0), "{v6}" (y));

For the inline `asm`, variable `x` is bound to register `r4`, and `y` is loaded to `v6`. Furthermore, constant `42.0` is loaded into floating-point register `f5`.

A key difference between register `asm` and hard register constraints is that the latter are specified at the point where they are supposed to materialize, namely at inline `asm`, which may lead to more readable code.

#### Usage ¶

Each input operand is loaded into the register specified by its corresponding hard register constraint. Furthermore, each hard register must be used at most once among an alternative for inputs. This renders hard register constraints more strict compared to register `asm` where multiple inputs may share a register as for example in

    int x;
    register int y asm ("0") = ...;
    asm ("" : "=r" (x) : "r" (y), "r" (y));

or even

    register int x asm ("0") = 42;
    register int y asm ("0") = 24;
    asm ("" : "=r" (x) : "r" (x), "r" (y));

The analogue for hard register constraints is invalid in order to prevent subtle bugs.

Likewise, two outputs must not share a register among an alternative. That means, the following example is invalid

    int x, y;
    asm ("" : "={r4}" (x), "={r4}" (y));  // invalid

which also aligns with register `asm`. Despite that, each output must refer to a distinct object if a hard register constraint is involved. For example, in the following, object `x` is assigned two registers.

    int x;
    asm ("" : "=r" (x), "=r" (x));

This is not allowed for hard register constraints in order to prevent subtle bugs. Even if only one output operand has a hard register constraint, the code is rejected since the allocation for the object is still ambiguous.

    int x;
    asm ("" : "=r" (x), "={1}" (x));  // invalid

The type of an operand must be supported by the corresponding machine register.

A hard register constraint may refer to any general, floating-point, or vector register except a fixed register as e.g. the stack-pointer register. The set of allowed registers is target dependent analogue to register `asm`. Furthermore, the referenced register must be a valid register name of the target. Note, on some targets, a single register may be referred to by different names where each name specifies the length of the register. For example, on x86_64 the register names `rcx`, `ecx`, and `cx` all refer to the same register but in different sizes. If any of those names is used for a hard register constraint, the actual size of a register is determined by its corresponding operand. For example

    long x;
    asm ("mov\t$42, %0" : "={ecx}" (x));

Although the hard register constraint refers to register `ecx`, the actual register will be `rcx` since on x86_64 a `long` is 8 byte in total. This aligns with register `asm` where you could have

    register long x asm ("ecx");

#### Interaction with Register `asm` ¶

A mixture of both constructs as for example

    register int x asm ("r4") = 42;
    int y;
    asm ("" : "={r5}" (y) : "r" (x));

is valid.

If an operand is a register `asm` and the corresponding constraint a hard register, then both must refer to the same register. That means

    register int x asm ("r4");
    asm ("" : "={r4}" (x));

is valid and

    register int x asm ("r4");
    asm ("" : "={r5}" (x));  // invalid

is invalid.

Note, register `asm` may not only be clobbered by function calls but also by inline `asm` in conjunction with hard register constraints. For example, in the following

    register int x asm ("r5") = 42;
    int y;
    asm ("" : "={r5}" (y));
    asm ("" : "+r" (x));

variable `x` materializes before the very first inline `asm` which writes to register `r5` and therefore clobbers `x` which in turn is read by the subsequent inline `asm`.

#### Limitations ¶

At the moment fixed registers are not supported for hard register constraints. Thus, idioms like

    register void *x asm ("rsp");
    asm ("" : "=r" (x));

are not supported for hard register constraints. This might be lifted.

Multiple hard register constraints in one alternative are also not supported. Furthermore, combinations of hard register constraints and regular register constraints in one alternative are not supported, too.