In the previous article I looked at the rich families of instructions to perform arithmetic on integer values in the general-purpose registers. This article completes most of this survey of instructions by considering those which operate with bits and other representations of data.
Move as bits
In addition to the MOV
instruction to move the contents of a register to another register, there are three variants which perform bit operations as part of the move:
MOVK
– move with keep, which inserts the first operand (a 16-bit immediate value) into an X or W register without changing the bits outside it,MOVN
– move with NOT, which performs a one’s complement (bitwise NOT) on the first operand (a 16-bit immediate value) as it’s moved,MOVZ
– move with zero, which inserts the first operand (a 16-bit immediate value) into an X or W register, zeroing the other bits.
Some examples explain these better:
MOVK W0, #0x1234, LSL #16
moves the halfword 0x1234 which has been left-shifted (see below) 16 places to form the most significant bytes in the register W0.
Because of the limitation on size of immediate values, you can load a 64-bit immediate using a sequence of one MOV followed by three MOVKs:
MOV X0, #0xDEF0
// this is assembled as MOVZ to zero the other bits in the register
MOVK X0, #0x9ABC, LSL #16
MOVK X0, #0x5678, LSL #32
MOVK X0, #0x1234, LSL #48
which sets X0 to 0x123456789ABCDEF0.
Shifting bits
There are four ways in which the bits in a register can be shifted and rotated: LSL (logical shift left), LSR (logical shift right), ASR (arithmetic shift right) and ROR (rotate right).
LSL
is an alias for LSLV, which shift bits to the left by moving in zero bits at the right:
LSL W0, W1, #1
shifts the contents of W1 one place to the left and puts the result in W0. The shift can be in a register, and for W registers can be 0-31, for X registers 0-63 in places.
For example, if W1 contained 0x0000 00F0 = 1111 0000, then shifting it left by one place converts it to 1 1110 0000 = 0x0000 01E0. Logical shift right moves the bits in the other direction.
If the integer being shifted is signed and negative, then LSR unfortunately changes its sign. To accommodate that, when shifting signed values to the right, you should use ASR
, which is an alias of ASRV
. This shifts in copies of the sign bit of the number rather than zeros. LSL and ASR are handy quick methods of multiplying and dividing integers by powers of 2.
LSL, LSR and their relatives all move in zeros. The other option is to move in the bits that are shifted out, which is performed by ROR
, and its relative RORV
.
Bitwise operations
The most common operations are:
AND
performs a bitwise AND, and has a siblingANDS
which does the same and sets NZCV flags;BIC
andBICS
perform a bitwise AND with the complement of a register value, which can be shifted;ORR
performs a bitwise (inclusive) OR of a register value;ORN
performs a bitwise (inclusive) OR of a register value and the complement of a register value;EOR
performs a bitwise exclusive OR (XOR) of a register value;EON
performs a bitwise exclusive OR (XOR) of the complement of a register value;MVN
performs a bitwise inverse of a register value.
Miscellaneous operations you should be aware of, which are detailed in the instruction set reference, include:
BFC, BFI, BFM, BFXIL
– these clear, insert and move bitfields within registers;REV
reverses the byte order in a register, and has relatives which work within sub-units:REV16
for each halfword, andREV32
for each word.
As promised, here’s a cheat sheet summary of the main operations using these registers:
and a tear-out PDF is here: armgpinstructions1
The next article will tackle the remaining topic involving the general-purpose registers, that of conditional operations, and their use to avoid branching. After that, I’ll move on to floating point.
Previous articles in this series:
1: Building an app to develop assembly routines, including an explanation of calling assembly language from Swift, with a complete Xcode project
2: Registers explained
3: Working with pointers
4: Controlling flow
5: Conditional loops
6: Flow, pipelines and performance
7: Moving data around
8: Integer arithmetic
Downloads:
ARM register summary
ARM operand architecture
Conditions and conditional branching instructions
Control Flow
ARM instructions for GP registers
AsmAttic 2, a complete Xcode project (version 2)
AsmAttic, a complete Xcode project (version 1)
References
Procedure Call Standard for the Arm 64-bit Architecture (ARM) from Github
Writing ARM64 Code for Apple Platforms (Apple)
Stephen Smith (2020) Programming with 64-Bit ARM Assembly Language, Apress, ISBN 978 1 4842 5880 4.
Daniel Kusswurm (2020) Modern Arm Assembly Language Programming, Apress, ISBN 978 1 4842 6266 5.
ARM64 Instruction Set Reference (ARM).