aarch64-pg
4.6 · Conditionals with cmp and b.cond

Conditionals with cmp and b.cond

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:

  1. Compare two values using the cmp instruction.
  2. 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 epilogue
Open in playground

The 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.

loading editor...

regfile

N clearZ clearC clearV clear

x0–x30 are the integer registers.

X0arg00x0000000000000000
X1arg10x0000000000000000
X2arg20x0000000000000000
X3arg30x0000000000000000
X4arg40x0000000000000000
X5arg50x0000000000000000
X6arg60x0000000000000000
X7arg70x0000000000000000
X8ind0x0000000000000000
X90x0000000000000000
X100x0000000000000000
X110x0000000000000000
X120x0000000000000000
X130x0000000000000000
X140x0000000000000000
X150x0000000000000000
X16ip00x0000000000000000
X17ip10x0000000000000000
X18pr0x0000000000000000
X190x0000000000000000
X200x0000000000000000
X210x0000000000000000
X220x0000000000000000
X230x0000000000000000
X240x0000000000000000
X250x0000000000000000
X260x0000000000000000
X270x0000000000000000
X280x0000000000000000
X29fp0x0000000000000000
X30lr0x0000000000000000
SP0x0000000080000000
PC0x0000000000400000
console

Output prints here as your program runs.

Step with F10, run with F5, or feed stdin from the box below.

figure 4.6.1runnable: step it and watch the registersOpen in playground