The AArch64 processor (aka arm64), part 9: Sign and zero extension

Raymond Chen

AArch64 does not have dedicated sign and zero-extension instructions because they can be synthesized as pseudo-instructions from the bitfield extraction instructions.

    ; unsigned extend byte
    ; Rd = (uint8_t)Rn
    uxtb    Rd/zr, Rn/zr        ; ubfx Rd, Rn, #0, #8

    ; unsigned extend halfword
    ; Rd = (uint16_t)Rn
    uxth    Rd/zr, Rn/zr        ; ubfx Rd, Rn, #0, #16

    ; signed extend byte
    ; Rd = (int8_t)Rn
    sxtb    Rd/zr, Rn/zr        ; sbfx Rd, Rn, #0, #8

    ; signed extend halfword
    ; Rd = (int16_t)Rn
    sxth    Rd/zr, Rn/zr        ; sbfx Rd, Rn, #0, #16

    ; unsigned extend word
    mov     Wd, Wn

    ; signed extend word
    sxtw    Xd/zr, Xn/zr        ; sbfx Xd, Xn, #0, #32

The odd man out here is the lack of an unsigned extend word pseudo-instruction, but a MOV works just as well, because the rule for 32-bit destinations is that they are zero-extended to a 64-bit value. So just moving a 32-bit register secretly zero-extends it. In practice, you can usually get the zero-extension for free by using a 32-bit register as the destination for the original calculation.

You can avoid having using these instructions if you can merge it into a subsequent extended register operation:

    ; as two instructions, using r3 as scratch register
    uxtb    r3, r2              ; r3 = (uint8_t)r2
    add     r0, r1, r3          ; r0 = r1 + r3

    ; merged into one instruction, avoids scratch register
    add     r0, r1, r2, uxtb    ; r0 = r1 + (uint8_t)r2

For extending a word to a doubleword, you can synthesize that easily enough:

    ; unsigned extend word in Xd to doubleword in Xd/X(d+1)
    mov     X(d+1), #0

    ; signed extend word in Xd to doubleword in Xd/X(d+1)
    asr     X(d+1), Xd, #63 ; copy sign bits to all bits

Next time, we’ll look at ways of loading constants.