Conditionals with cmp and b.cond
prerequisite
Read these first:
Every program has to make decisions. In high-level languages a decision is written with if and else. ARMv8 AArch64 Assembly has no such construct.
In high-level programming languages, such as C, conditional logic can be implemented using built-in language constructs (if constructs). For example:
#include <stdio.h>int main() { int a = 6; int b = 7; if (a > b) { printf("XX\n"); } else { printf("XY\n"); } return 0;}The code above compares the values stored in the variables a and b. "XX" will be printed if the value of a is greater than b; otherwise, "XY" is printed.
At the Assembly level, the processor does not understand high-level abstractions such as if and else. Instead, conditional behaviour is created by directly controlling the flow of execution through comparisons, condition codes, and branch instructions.
The big picture
Conditional constructs in Assembly can be achieved by comparing values and changing the program's execution flow based on the resulting condition flags. The process can be summarised as follows:
- Compare two values using the
cmpinstruction. - Use a branch instruction (
b.cond) to jump to a specific label when the condition is satisfied.
note
b.cond is not an actual Assembly instruction. The cond part represents a placeholder for a condition code. Replacing cond with a specific condition code creates the actual branch instruction, such as b.eq, b.ne, or b.gt. See the b.cond entry in the Reference for an interactive breakdown of every condition code.
More about cmp and b.cond
The cmp instruction is the compare instruction. It compares the contents of two registers, or the contents of a register with an immediate value,
cmp performs the comparison and takes no action on the result.
Instead it updates the condition flags, which record whether the result was zero, negative, carried, or overflowed.
Instructions that use a condition code, such as b.cond, examine these condition flags. If the specified condition code (cond) is met, b.cond branches to the specified label. Otherwise, execution continues with the instruction immediately following b.cond.
Implementing a conditional
The above C code can be translated into Assembly as follows:
// Pseudo-ops and directives ..main: // Program prologue .. mov x19, 6 // int a = 6; mov x20, 7 // int b = 7; cmp x19, x20 // Compare a and b: if (a > b) b.gt greaterThan // Jump to greaterThan if the condition code is met // else block // If the condition code is not met, execution continues with the instruction // immediately following the conditional branch. ldr x0, =fmt2 // Load the address of the "XY" string bl printf b end // without this branch, execution falls into the if block belowgreaterThan: ldr x0, =fmt1 // Load the address of the "XX" string bl printfend: // Code block after the if-else construct .. // Program epilogueThe assembly order does not have to match the order of the original if-else statement. In this example, the else block is placed first because b.gt only jumps when the condition is true. If the condition is false, execution naturally continues to the next instruction, which is the else block. After completing the else block, an unconditional branch (b end) to the label end is used to skip over the if block and prevent both blocks from executing.
The b.gt instruction checks whether the first value being compared is greater than the second value. In this case, it checks the condition flags updated by cmp x19, x20 to determine whether the value in x19 is greater than the value in x20.
The whole program
The code below demonstrates the complete process of implementing conditionals in Assembly, including the pseudo-ops, function prologue, and function epilogue.