# The Alpha AXP, part 3: Integer constants

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:

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

2. 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
```
Tags

1. Joshua says:

If it were up to me, the no-man’s-land 64kb wouldn’t have existed, but the loader wouldn’t load any DLLs there unless their base address was high enough to load there. Oh well.

I’m disappointed the alpha didn’t have load32 or load64 instructions. Since you’re going to end up double-sized anyway the easiest way to implement such a thing is provide LODx instructions that load 16 bit chunks (this takes weight off the machinery). But behold they only did it with signed numbers. Oops.

1. Antonio Rodríguez says:

Take into account that the Alpha uses fixed-sized 32 bit instructions. You only have 32 bits to encode the opcode and any operands, and having 32 registers means the register number itself spans 5 bits. Fitting a 24 bit immediate constant would be really difficult (assuming you could spare a three bit opcode, of which there are only eight possible). And fitting a 32 bit one is physically impossible (no space left for the register number or the opcode!).

1. Matteo Italia says:

On this topic, ARM is way more fun; most instruction that take an immediate have an implicit “rotate field”, so while you have just 8 bits for the immediate value (+4 for rotation), many 32 bit “interesting” values can still be expressed in the immediate (think in particular about bit fiddling).

2. Matteo Italia says:

https://alisdair.mcdiarmid.org/arm-immediate-value-encoding/

3. Joshua says:

With my scheme, 2 instructions would suffice to load any 32 bit value, 4 instructions to load any 64 bit value. There’s plenty of space as the constant is only half the instruction width.

1. At a cost of consuming 28 bits just for the parameters. (16 bits for the constant, 5 bits for the source register, 5 bits for the destination register, 2 bits to select the position of the 16 bits = 28 bits.) This leaves only 4 bits for the opcode. I think there are more than 16 instructions in the Alpha AXP instruction set.

1. Jonathan Wilson says:

They could have introduced special versions of ldah and lda that dont do the sign extending that are just for loading a 32 bit constant.
That way you can just have ldah t0, XXXX(zero) followed by lda, t0, YYYY(t0) and not need to have to worry about sign extentions.