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
Generating condition code
In Program flow - loops and decisions, we learned that the <cond>
is tested against the ALU flags stored in PSTATE.
The ALU flags are set as a side effect of data-processing instructions. To recap, an S
at the end operation causes the ALU flags to be updated. This is an example of an instruction in which the ALU flags are not updated:
ADD X0, X1, X2
This is an example of an instruction in which the ALU flags are updated with the use of S
:
ADDS X0, X1, X2
This method allows software to control when the flags are updated or not updated. The flags can be used by subsequent condition instructions. Let's take the following code as an example:
SUBS X0, X5, #1
AND X1, X7, X9
B.EQ label
The SUBS
instruction performs a subtract and updates the ALU flags. Then the AND
instruction performs an and operation, and does not update the ALU flags. Finally, the B.EQ
instruction performs a conditional branch, using flags set as result of the subtract.
The flags are:
- N - Negative
- C - Carry
- V - Overflow
- Z - Zero
Let’s take the Z flag as an example. If the result of the operation was zero, then the Z flag is set to 1. For example, here the Z
flag will be set if X5
is 1, otherwise it will be cleared:
SUBS X0, X5, #1
The condition codes map on to these flags and come in pairs. Let's take EQ (equal) and NE (not equal) as an example, and see how they map to the Z flag:
The EQ code checks for Z==1
. The NE code checks for Z==0
.
Taking the following code as an example:
SUBS W0, W7, W9 // W0 = W7 - W9
B.EQ label
In the first line, we have a subtract operation. Because we used the S
suffix, this subtract operation sets the Z flag if the result is zero. In the final line, there is a branch to label if Z==1
.
If w7==w9
, the result of the subtraction will be zero, and the Z
flag would have been set. Therefore, the branch to label will be taken if w7
and w9
are equal.
In addition to the regular data-processing instructions, other instructions are available that only update the ALU flags:
CMP
- Compare
TST
- Test
These instructions are aliases of other instructions. For example:
CMP X0, X7 //an alias of SUBS XZR, X0, X7
TST W5, #1 //an alias of ANDS WZR, W5, #1
By using the Zero register as a destination, we are discarding the result of the operation and only updating the ALU flags.
-
Test yourself: The examples we seen so far have used the EQ and NE conditions. Write a sequence that will set X0 to 5 if the result of (X5 - X6) is negative. To do this, you will need to look up the full list of condition codes in the Arm ARM.
There are several sequences you could write. Here is one example:
SUBS XZR, X5, X6
B.PL 1a //Branch is positive or zero
MOV X0, #5 //Only executed if result was negative
1:
…A conditional select instruction might be a better choice here.