Codementor Events

Conditional Branching In Instruction Set Architecture

Published Oct 18, 2019

Instruction Sets use an if-goto style for conditional branching.  I've written several posts on how to logically transform structured statements like loops and if-then-else statement into this if-goto style.

In this post, I'm going to speak to the translation of the if-condition-then-goto statement into instruction sets of several different machine architectures.

Let's take a look at a basic if-goto statement:

    if ( i >= n ) goto exitLoop;

This one statement has 4 operands that the hardware has to consider:

Operand Example Usage
source 1 i probably a register, one of 16 or so
condition >= one of 10 relational operators when counting both signed and unsigned
source 2 j probably a register, one of 16 or so
branch target exitLoop a label in assembly (a number in machine code

The issue here is that, generally speaking, there are too many operands, and they would add up to one of the largest instructions in the machine.  The last operand, the branch target, in particular, is fairly large operand typically 8 or more bits.

Rather than implement all the above capabilities within a single instruction with lots of operands and options, most instruction sets break this set of functionality into several instructions.  Common cases may be optimized to one instruction, while others take more.

MIPS

MIPS chooses to provide and if-goto for == and != operators directly in one instruction:
    beq $r1, $r2, target, and,
    bne $r1, $r2, target.

These allow comparing two registers for equality or inequality and branching to a target conditionally.  Note that the special constant 0 can be also used in one of the register positions (by referencing the MIPS-always-zero-valued register $0), which provides a handy way to branch on zero or non-zero of a single register's value in one instruction.

Note that the magnitude checking operators: <, <=, >, >= are left out, as well as all comparisons involving constants, except zero (e.g if ( n >= 100 ) goto stop;).

In order to do the other relational operators, there are four additional instructions, the first two for register-to-register:
    slt $r1, $r2, $r3 — outputs a boolean in $r1 for $r2 < $r3, and,
    sltu $r1, $r2, $r3 — outputs a boolean in $r1 for $r2 < $r3 (unsigned)
And the next two for register-to-immediate:
    slti $r1, $r2, #imm — outputs a boolean in $r1 for $r2 < #imm, and,
    sltiu $r1, $r2, #imm — outputs a boolean in $r1 for $r2 < #imm (unsigned)

If an immediate to compare with cannot be represented a larger immediate is loaded into a scratch register and the register-to-register form is used.  (This is also the approach for equality and inequality testing against (non-zero) constants using beq and bne.)

Sequences of instructions (slt, beq — or — li, beq) accomplish the if-goto; like most code sequences, these instructions in these sequences are interconnected via one or more of the standard registers in the instruction set.

MIPS allows for a 16-bit number for the branch target, giving it a rather larger range.

RISC V

RISC V uses a comare and branch with branch target width of 12 bits wide, as compared with MIPS' 16 bits wide — this reduction in range allows room to express all of the relational operators within a single branch instruction.  Like MIPS, RISC V compare and branch supports only register-to-register.  RISC V also shares the idea of the always-zero register $0, and also requires constants/immediates to be loaded into a register in order to use the register-to-register compare & branch instruction.

Condition Codes

An alternate approach used by many other processors (e.g. x86, 6502, MC68000, etc..) is that of condition codes, which are a set of (usually) 4 1-bit registers known also as "flags".  These special registers hold the state that interconnects instructions: typically, one for specifying the operands to compare (setting the flags), and the next to identify the desired comparison operator (testing the flags) and the branch target.  As an extra efficiency on code size, many instructions also set the condition codes, which means a dedicated comparison operation is sometimes not needed.  The 4 bits capture the notion of equal, not equal, and the signed and unsigned magnitude relations.

Discover and read more posts from Erik Eidt
get started
post commentsBe the first to share your opinion
Show more replies