# The Alpha AXP, part 3: Integer constants

Raymond

The Alpha AXP does not have a “load immediate 32-bit integer” instruction. If you need to load an immediate 32-bit integer, you need to use some tricks.

We saw last time that loading 8-bit constants can be done by using the `ADD`

and `SUB`

instructions. But there are also instructions that can be repurposed to generate signed 16-bit constants.

Effective address instructions are basically arithmetic operations disguised as memory operations. (Yes, I know we haven’t learned about memory operations yet.)

LDA Ra, disp16(Rb) ; Ra = Rb + (int16_t)disp16 LDAH Ra, disp16(Rb) ; Ra = Rb + (int16_t)disp16 * 65536

The first instruction applies a signed 16-bit displacement to a value in a register and puts the result in the `Ra` register.

The second one is a little trickier. It takes the signed 16-bit displacement and shifts it left 16 positions before adding it to the `Rb` register.

Both of these operations operate on the full 64-bit register, so they can produce non-canonical results.

The basic idea behind loading a 32-bit constant (in canonical form) is as follows:

- Use the
`LDAH`

relative to the`zero`register to load the high-order 48 bits of the 32-bit constant. - Use the
`LDA`

instruction relative to the destination register of the previous instruction to load the low-order 16 bits.

However, the fact that the 16-bit values are sign-extended makes things a bit more complicated.

Let’s say that the 32-bit constant we want to load into the `t0` register is `0xXXXXYYYY`

.

Let `xxxx`

be the result you get when you treat `XXXX`

as a signed 16-bit value. Similarly, `yyyy`

and `YYYY`

.

Let `S`

be the sign bit of `XXXX`

. The canonical form of the constant we want to load is `0xSSSSSSSS`XXXXYYYY`

.

If `yyyy`

is nonnegative, then we can just load up the two halves of our constant and they won’t interact with each other.

LDAH t0, XXXX(zero) ; t0 = 0xSSSSSSSS`XXXX0000 LDA t0, YYYY(t0) ; t0 = 0xSSSSSSSS`XXXXYYYY

(Throughout, I will leave out the obvious simplifications if `XXXX`

or `YYYY`

is zero.)

If `yyyy`

is negative, then the `LDA`

is going to undershoot by `0x10000`

, so we compensate by adding one more to `xxxx`

.

LDAH t0, xxxx+1(zero) ; t0 = 0xSSSSSSSS`XXXX0000 + 0x10000 LDA t0, yyyy(t0) ; t0 = 0xSSSSSSSS`XXXXYYYY

Aha, but this trick doesn’t work if `xxxx`

is exactly `0x7FFF`

, because `0x7FFF`

+ 1 = `0x8000`

, which has the wrong sign bit. In that case, we need a final adjustment step to put the result into canonical form.

LDAH t0, -32768(zero) ; t0 = 0xFFFFFFFF`80000000 LDA t0, yyyy(t0) ; t0 = 0xFFFFFFFF`7FFFYYYY ADDL zero, t0, t0 ; t0 = 0x00000000`7FFFYYYY

Constants that are in the range `0x7FFF8000`

to `0x7FFFFFFF`

suffer from this problem.¹

All of this hassle about creating 32-bit constants has consequences for the Windows NT memory manager, as I discussed a few years ago.

Okay, so that’s it for loading constants. Next time, we’ll start looking at memory access.

¹ There is a special shortcut for the value `0x7FFFFFFF`

:

LDA t0, -1(zero) ; t0 = 0xFFFFFFFF`FFFFFFFF SRL t0, #33, t0 ; t0 = 0x00000000`7FFFFFFF