Skip to content

Decisions

So far, we have only covered sequential execution. In other words, the instructions are executed in program order from top to bottom. Unfortunately, this is not enough to perform general computing tasks1. For general computing tasks, we need two additional constructs:

  1. Selection (i.e., making decision): if and switch-case.
  2. Repetition (i.e., iterations): while, do-while and for.

In MIPS, both selection and repetition are combined into a single construct similar to if statement followed by a goto. Note that C has a goto statement but it is highly discouraged2.

What these "decision making" instructions do is to alter the control flow of the program as well as change the next instruction to be executed. For instance, it allows a certain sequence to be executed only if a certain condition occurs (i.e., selection via goto downward) or a certain sequence to be executed multiple times until a certain condition is no longer valid (i.e., repetition via goto upwards).

Label

There are two types of decision making statements in MIPS:

  1. Conditional (a.k.a., branch)
    • bne $t0, $t1, label
    • beq $t0, $t1, label
  2. Unconditional (a.k.a., jump)
    • j label

A label is an "anchor" in the assembly code to indicate a point of interest. This is usually a branch target but can also be used to indicate a logical grouping for the programmer. It is important to note that labels are NOT instructions.

You have seen one instance of label in the previous section:

Swap Elements (in MIPS)
1
2
3
4
5
6
7
swap:
  sll  $2, $5, 2   #  $v0    = k * 4     -- for word alignment
  add  $2, $4, $2  #  $v0    = (k*4)+v   -- computing the actual address
  lw   $15, 0($2)  #  temp   = v[k]
  lw   $16, 4($2)  #  $t8    = v[k+1]
  sw   $16, 0($2)  #  v[k]   = $t8
  sw   $15, 4($2)  #  v[k+1] = temp

Here, the name swap is a label. It indicates that the code below it belongs to the same logical grouping for swapping. The labels can be any name and will be removed from the code during assembly. As such, its use is only for us programmers to understand the code better.

Label Naming

Since the use of label is for programmers, it is highly encouraged to use descriptive names for the labels.

Conditional Branch

Branch indicates that there are at least two possible choices for the path to take. In this case, the processor follows the branch only when the condition is satisfied (i.e., true). There are two conditional branch instructions in MIPS depending on whether the condition should be based on equality or non-equality.

Conditional Branch

MIPS
1
beq $rs, $rt, label
MipC
1
2
3
if($rs == $rt) {
  // label lands here
}

Go to statement labeled label if the value in register $rs equals the value in register $rt.

MIPS
1
bne $rs, $rt, label
MipC
1
2
3
if($rs != $rt) {
  // label lands here
}

Go to statement labeled label if the value in register $rs does not equal the value in register $rt.

Although we show the possible MipC equivalent code, it is not exactly correct. In this case, there is an implicit assumption that label is after the current instruction. Furthermore, there is a common trick to slightly optimise the code for selection. More importantly, the conversion should be the other way around (i.e., MipC to MIPS).

Unconditional Jump

A jump indicates no choice. In this case, the processor always follows the branch.

Unconditional Jump

MIPS
1
j label

Go to statement labeled label.

Technically, this is equivalent to ignoring the assembly and how far we can jump:

MIPS Equivalent
1
beq $reg, $reg, label

Any register $reg can be used as long as it is a valid register.

Inequalities

We have beq and bne, but what about if want to branch on inequalities? For example, what if we want to branch when $rs is less than $rt? There is no real blt (i.e., branch on less than) instruction but there are several pseudo-instructions.

Pseudo-Instruction Code Operation
Branch on Less Than blt $rs, $rt, label if($rs < $rt) then goto label
Branch on Greater Than bgt $rs, $rt, label if($rs > $rt) then goto label
Branch on Less Than or Equal ble $rs, $rt, label if($rs <= $rt) then goto label
Branch on Greater Than or Equal bge $rs, $rt, label if($rs >= $rt) then goto label

In the end, it will still be translated into real instructions. What are the real instructions used in this case? Suprisingly, only one additional real instruction is needed to be able to translate all of the pseudo-instructions.

Set on Less Than

MIPS
1
slt $rd, $rs, $rt

Set the value of $rd to 1 if the value of $rs is less than the value of $rt. Otherwise, set the value of $rd to 0. In C, it looks like the following:

Set on Less Than
1
2
3
4
5
if (rs < rt) {
  rd = 1;
} else {
  rd = 0;
}

Given this additional instruction, we can now build the pseudo-instructions as follows:

Pseudo-Instruction Translation

blt $rs, $rt, label

We do the translation using an intermediate form: if (($rs < $rt) != 0) goto label

blt Translation
1
2
slt $t0, $rs, $rt
bne $t0, $zero, L

bgt $rs, $rt, label

We do the translation using an intermediate form: if (($rt < $rs) != 0) goto label

bgt Translation
1
2
slt $t0, $rt, $rs
bne $t0, $zero, L

ble $rs, $rt, label

We do the translation using an intermediate form: if (($rt < $rs) == 0) goto label

ble Translation
1
2
slt $t0, $rt, $rs
beq $t0, $zero, L

bge $rs, $rt, label

We do the translation using an intermediate form: if (($rs < $rt) == 0) goto label

blt Translation
1
2
slt $t0, $rs, $rt
beq $t0, $zero, L

Take a moment to understand the translation. If you are having problem understanding the translation, do click on the explanation below.

Translation Idea

Here, the comparison $rs < $rt will be 1 if the condition is true. So we simply check that the result is not equal to 0. Then we can evaluate $rs > $rt using slt by swapping the two registers! In other words:

1
2
$rs > $rt
 $rt < $rs

For the ble we simply do the negation.

1
2
3
4
$rs <= $rt
 !($rs > $rt)
 !($rt < $rs)
 ($rt < $rs) == 0

Lastly, for the bge we do the same trick as before again.

1
2
3
4
5
$rs >= $rt
 $rt <= $rs
 !($rt > $rs)
 !($rs < $rt)
 ($rs < $rt) == 0

Examples

Selection Statement

If Statement

If Statement (in C)
1
2
3
if (i == j) {
  f = g + h;
}
Variable Register
f $s0
g $s1
h $s2
i $s3
j $s4
If Statement (in MipC)
1
2
3
if ($s3 == $s4) {
  $s1 = $s1 + $s2;
}

There are two equivalent translations. Click on the "Invert" tab to see the more efficient translation.

If Statement (in MIPS)
1
2
3
4
      beq $s3, $s4, L1
      j   Exit
L1:     add $s0, $s1, $s2
Exit:
If Statement (in MIPS)
1
2
3
      bne $s3, $s4, Exit
      add $s0, $s1, $s2
Exit:

The efficient translation uses the common technique summarised below:

Inversion

Invert the selection condition for shorter code.

If-Else Statement

If-Else Statement (in C)
1
2
3
4
5
if (i == j) {
  f = g + h;
} else {
  f = g - h;
}
Variable Register
f $s0
g $s1
h $s2
i $s3
j $s4
If-Else Statement (in MipC)
1
2
3
4
5
if ($s3 == $s4) {
  $s1 = $s1 + $s2;
} else {
  $s1 = $s1 - $s2;
}

There are two equivalent translations. We will show the inversion translation and leave the direct translation for exercise.

If-Else Statement (in MIPS)
1
2
3
4
5
      bne $s3, $s4, Else # invert then goto else branch
      add $s0, $s1, $s2
      j   Exit
Else: sub $s0, $s1, $s2
Exit:

If-Else

Although inversion does not reduce the number of instructions, it helps make the translation uniform. The flowchart is given on the right.

Exercise

  1. Translate the following C code fragments to MIPS without inversion.

    Question 1
    1
    2
    3
    4
    5
    if (i == j) {
      f = g + h;
    } else {
      f = g - h;
    }
    
  2. What is the corresponding high-level language statement for the following MIPS code?

    Question 2
    1
    2
    3
         beq $s1, $s2, Exit
         add $s0, $zero, $zero    
    Exit:
    
  1. Since there is an else, direct translation can be with the same number of instructions.

    Answer 1
    1
    2
    3
    4
    5
          beq $s3, $s4, Then # simply goto then branch
          sub $s0, $s1, $s2
          j   Exit
    Then: add $s0, $s1, $s2
    Exit:
    

    Alternatively, you can first "rewrite" the code by swapping the then and else branch as shown below. Then you can use the inversion technique to produce the same code as above.

    Rewrite
    1
    2
    3
    4
    5
    if (i != j) {
      f = g - h; // previously +
    } else {
      f = g + h; // previously -
    }
    
  2. Note that the 3 lines code match more of the inversion technique rather than the direct translation technique. So, instead of $s1 == $s2, we should think in terms of $s1 != $s2. What this means is that the add is only executed if the condition $s1 != $s2 evaluates to false. This add also adds 2 zeroes which is equal to 0. A simple translation may be $s0 = 0 + 0; but this is simply $s0 = 0;. An intermediate MipC statement looks like the following:

    Intermediate MipC
    1
    2
    3
    if ($s1 != $s2) {
      $s0 = 0;
    }
    

    Then, the answer after remapping to variable, is simply:

    Answer 2
    1
    2
    3
    if (i != j) {
      f = 0;
    }
    

Repetition Statement

For the repetition statement, the MipC intermediate is not exactly useful as we designed the MipC to be quite close to C for these high-level constructs. As such, in the examples below, we will simply show the MIPS instructions instead with explanation in a C with goto.

While Loop

While-Loop Statement (in C)
1
2
3
while (j == k) {
  i = i + 1;      // ignore for a moment that this is infinite loop
}
Variable Register
i $s3
j $s4
k $s5

If we translate the code into a C statement with goto, we get the following code fragment:

While-Loop Statement (in C with goto)
1
2
3
4
Loop: if (j != k) goto Exit;  // Inversion: exit when false
      i = i + 1;
      goto Loop;              // Jump back to start of loop
Exit:

This produces the MIPS code that follows the similar structure as the C code fragment above using goto and label.

While-Loop Statement (in MIPS)
1
2
3
4
Loop: bne  $s4, $s5, Exit  # Inversion: exit when false
      addi $s3, $s3, 1
      j    Loop            # Jump back to start of loop
Exit:

Exercise

Write the following for-loop in MIPS.

Question
1
2
3
for (i=0; i<10; i++) {
  a = a + 5;
}
Variable Register
i $s0
a $s2

The constant 10 is rather troublesome because we cannot compare easily with a constant. We need to store this value into a register. Let's use $s1 for this.

Now, translating this for-loop into a similar while-loop might be more useful. Additionally, we use our understanding of the code fragment to note that the inequality can be replaced with equality. In this case, the loop ends when variable i is equal to 10.

The while-loop looks like the following:

While-Loop Variant
1
2
3
4
5
6
i = 0;
$s1 = 10;
while (i != $s1) {
  a = a + 5;
  i++;
}

And voila! We can now use the same technique of while-loop translation to translate this to the MIPS code below.

Answer
1
2
3
4
5
6
7
      add  $s0, $zero, $zero #       i   = 0;
      addi $s1, $zero, 10    #       $s1 = 10;
Loop: beq  $s0, $s1, Exit    # Loop: if (i == $s1) goto Exit;
      addi $s2, $s2, 5       #       a   = a + 5;
      addi $s0, $s0, 1       #       i++;
      j    Loop              #       goto Loop;
Exit:                        # Exit:

Array and Loop

A typical example of accessing array elements in a loop can be summarised with the diagram below:

Array and Loop

Count Zeroes

The problem is to count the number of zeroes in an integer array A (i.e., int A[40];). Here, A is an integer array with 40 elements.

Variable Register
&A[0] $t0
result $t8

You should think about the following:

  • How to perform the right comparison.
  • How to perform the right load operation.

In this version, we use the following simple C code:

Count Zeroes V1 (in C)
1
2
3
4
5
6
7
8
result = 0;
i = 0;
while (i < 40) {   // How to compare correctly?
  if (A[i] == 0) { // How to translate A[i] correctly?
    result++;
  }
  i++;
}

Since we use a temporary variable i, we need to map this. Let us map this to $t1. We also need to store the constant 40 for comparison, we will use $t2. Lastly, note that we need to compute the correct address. Since this is an integer array, it will be word aligned. Which means, the actual offset will need to be multiplied by 4. We use both $t3 and $t4 to compute the actual address for load.

Count Zeroes V1 (in MIPS)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
      addi $t8, $zero, 0
      addi $t1, $zero, 0
      addi $t2, $zero, 40    # end point
loop: bge  $t1, $t2, end     # pseudo-instruction, can you use beq?
      sll  $t3, $t1, 2       # $t3 = i*4     (for offset computation)
      add  $t4, $t0, $t3     # $t4 = &A[$t3] (after offset computation)
      lw   $t5, 0($t4)       # $t5 = A[$t3]  (deferencing using *$t4)
      bne  $t5, $zero, skip
      addi $t8, $t8, 1       # result++
skip: addi $t1, $t1, 1       # i++
      j loop
end:

In this version, we use pointer arithmetic version of the C code:

Count Zeroes V2 (in C)
1
2
3
4
5
6
7
8
9
result = 0;
curr = &A[0];
last = &A[40];
while (curr < last) { // How to compare correctly?
  if (*curr == 0) {   // How to translate curr correctly?
    result++;
  }
  curr++;
}

Here we use two additional variables curr and last. curr is address of the current item, which we will be incremented using pointer arithmetic. last is a computed address of the last element. We can compare address as if they are numbers because MIPS register has no data type. However, this omission of data type produce a problem for curr++. This should increment the address by 4 because this is an integer array. So remember to do this on your MIPS code. Now, since curr is already the address, we do not need to do the multiplication by 4 and add the base address. Instead, we can simply load.

Count Zeroes V2 (in MIPS)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
      addi $t8, $zero, 0
      addi $t1, $t0, 0      # curr = &A[0];
      addi $t2, $t0, 160    # last = &A[40];
loop: bge  $t1, $t2, end    # address comparison! can you use beq?
      lw   $t3, 0($t1)      # $t3 = *curr  (simple load)
      bne  $t3, $zero, skip
      addi $t8, $t8, 1      # result++
skip: addi $t1, $t1, 4      # curr++ (move to next item, but add 4 to address)
      j loop
end:

Pointer Arithmetic

Note that the use of "pointers" directly via pointer arithmetic can produce more efficient code.

Simple Loop

Given the following MIPS code:

Question 1
1
2
3
4
5
6
       addi $t1, $zero, 10
       add  $t1, $t1, $t1
       addi $t2, $zero, 10
Loop:  addi $t2, $t2, 10
       addi $t1, $t1, -1
       beq  $t1, $zero, Loop
  1. How many instructions are executed?

    (a) 6
    (b) 30
    (c) 33
    (d) 36
    (e) None of the above

  2. What is the final value in $t2?

    (a) 10
    (b) 20
    (c) 300
    (d) 310
    (e) None of the above

Answer
  1. (a)
  2. (b)

Given the following MIPS code:

Question 2
1
2
3
4
5
6
       add  $t0, $zero, $zero
       add  $t1, $t0, $t0
       addi $t2, $t1, 4
Again: add  $t1, $t1, $t0
       addi $t0, $t0, 1
       bne  $t2, $t0, Again
  1. How many instructions are executed?

    (a) 6
    (b) 12
    (c) 15
    (d) 18
    (e) None of the above

  2. What is the final value in $t1?

    (a) 0
    (b) 4
    (c) 6
    (d) 10
    (e) None of the above

Answer
  1. (c)
  2. (c)

Given the following MIPS code accessing an integer array of elements in memory with the starting address in $t0.

Question 3
1
2
3
4
5
6
       addi $t1, $t0, 10
       add  $t2, $zero, $zero
Loop:  ulw  $t3, 0($t1) # ulw: unaligned lw
       add  $t2, $t2, $t3
       addi $t1, $t1, -1
       bne  $t1, $t0, Loop
  1. How many times in the bne instruction executed?

    (a) 1
    (b) 3
    (c) 9
    (d) 10
    (e) 11

  2. How many times does the bne instruction actually branch to the label Loop?

    (a) 1
    (b) 8
    (c) 9
    (d) 10
    (e) 11

  3. How many instructions are executed?

    (a) 6
    (b) 12
    (c) 41
    (d) 42
    (e) 46

  4. How many unique bytes of data are read from the memory?

    (a) 4
    (b) 10
    (c) 11
    (d) 13
    (e) 40

Answer
  1. (d)
  2. (c)
  3. (d)
  4. (d)

  1. There is a growing field of computing called "Branchless Programming". However, it typically only removes selection statements (e.g., if and switch-case) and we still need repetition statements for general purpose computing. As you will learn later on pipelining, branch prediction helps but only if the prediction is correct. 

  2. One of the opponent is Edsger W. Dijkstra of Dijkstra's algorithm fame. You can read his opposition to understand why. In short, unchecked use of goto leads to unreadable code (called the spaghetti code). However, a certain highly restricted goto may actually be beneficial (e.g., try escaping from nested loop, you will realise that your code will feel weird).