Overview Why you should care about the ISA Instruction sets in the Arm architecture Instruction set resources Simple sequential execution Registers in AArch64 - general-purpose registers Registers in AArch64 - other registers Registers in AArch64 - system registers Data processing - arithmetic and logic operations Data processing - floating point Data processing - bit manipulation Data processing - extension and saturation Data processing - format conversion Data processing - vector data Loads and stores Loads and stores - size Loads and stores - zero and sign extension Loads and stores - addressing Loads and stores - load pair and store pair Loads and stores - using floating point registers Program flow Program flow - loops and decisions Program flow - generating condition code Program flow - conditional select instructions Function calls Procedure Call Standard System calls Check your knowledge Related information Next steps
Conditional select instructions
So far, we have seen examples that use branches to handle decisions. The A64 instruction set also provides conditional select instructions. In many cases, these instructions can be used as an alternative to branches.
There are many variants, but the basic form is:
CSEL Xd, Xn, Xm, cond
This means that:
if cond then
Xd = Xn
else
Xd = Xm
You can see an example in this code:
CMP W1, #0
CSEL W5, W6, W7, EQ
Which gives the same result as:
if (W1==0) then
W5 = W6
else
W5 = W7
There are variants that combine another operation with the conditional select. For example, CSINC performs a select and addition:
CSINC Xd, Xn, Xm, cond
This means that:
if cond then
Xd = Xn
else
Xd = Xm + 1
To just conditionally increment, you could write:
CSINC X0, X0, X0, cond
Which equates to:
if cond then
X0 = X0
else
X0 = X0 + 1
The architecture provides an alias, CINC
, for this command. Note however that CINC
inverts the logic of CSINC
:
CSINC X0, X0, X0, cond
- leaves
X0
unchanged ifcond
is true - increments
X0
ifcond
is false
- leaves
CINC X0, X0, cond
- increments
X0
ifcond
is true - leaves
X0
unchanged ifcond
is false
- increments
Compilers choose the most efficient method to implement the functionality in your program. Compilers will often use a conditional select for small if ... else statements performing simple operations, because conditional selects can be more efficient than branches.
Here are some simple if ... else examples that compare implementations using branches to equivalent implementations using conditional select instructions:
C | Branching | Conditional select |
if (a != 0) b = b + 1;
|
CMP W0, #0 B.EQ else ADD W1, W1, #1 else: …
|
CMP W0, #0 CINC W1, W1, NE |
if (a == 0) y = y + 1; else y = y - 1;
|
CMP W0, #0 B.NE else ADD W1, W1, #1 B end else: SUB W1, W1, #1 end: …
|
CMP W0, #0 SUB W2, W1, #1 CSINC W1, W2, W1, NE |
In these types of examples, conditional selects have some advantages. The sequences are shorter and take the same number of instructions, regardless of the outcome.
Importantly, conditional selects also remove the need to branch. In modern processors, this kind of branch can be difficult for the branch prediction logic to predict correctly. A mispredicted branch can have a negative effect on performance, it is better that you remove branches where possible.