Skip to content

Arithmetic

There are two arithmetic operations that we are going to discuss here: addition and subtraction. We will not discuss multiplication and division because they are much more expensive (i.e., takes more time) to execute than addition and subtraction1.

Addition

Addition

MIPS
1
add $rd, $rs, $rt
MipC
1
$rd = $rs + $rt;

Note that in MipC2, we explicitly use the register name like variable to avoid performing an automated mapping. In particular, the mapping is done by the programming explicitly. Consider a simple C statement:

Simple Addition (in C)
1
a = b + c;

Further consider that we have a mapping3:

Variable Register
a $s0
b $s1
c $s2

We can then write the simple addition into the following MIPS assembly code:

Simple Addition (in MIPS)
1
add $s0, $s1, $s2

Add Immediate

We often want to add a constant value into a variable. For instance, in a loop, we have the statement i++ which is typically equivalent to i = i+1;. Of course, we can always change this into i = i+C; where C = 1;. However, due to the ubiquity of such statement, MIPS provides a simple way to do this.

Immediate Addition

MIPS
1
addi $rt, $rs, immediate
MipC
1
$rt = $rs + immediate;

Note that most arithmetic and logical operations will have the immediate variants. We will highlight this at the end as well as provide a simplified reason on why some do not have this immediate variant.

Subtraction

Subtraction

MIPS
1
sub $rd, $rs, $rt
MipC
1
$rd = $rs - $rt;

Note that the ordering of the register is critical for subtraction due to the non-commutativity of subtraction.

a - b ≠ b - a

Using the same mapping as before, we can now translate the simple subtraction below:

Simple Subtraction (in C)
1
a = b + c;

into:

Simple subtraction (in MIPS)
1
sub $s0, $s1, $s2

Sub Immediate

There is NO immediate variant for subtraction. This can be easily explained by the fact that the constant value used for addi can be negative number. In fact, the negative number is written as 16-bits 2s complement. So, the range of values for the constant is between -215 to 215-1.

Remember, one of the design principle is

Design Principle #1

Keep the instruction set small

Complex Operations

The two arithmetic operations above are "simple" in a sense that we have two operands register and one result register (to store the result). Yes, the result register can be the same as either or both of the operands, but we can also imagine that a statement in C can involve more than two operands.

Complex Expression (in C)
1
a = b + c - d

Consider the mapping:

Variable Register
a $s0
b $s1
c $s2
d $s3

How do we perform such complex operation? It will be good if we have a special operation that uses 4 registers like addsub $s0, $s1, $s2, $s3. Unfortunately, this means that we will need to also add the three other variants: addadd, subadd and subsub. To make matter worse, we will then have to add more for operations with 5 registers, 6 registers, etc.

So the solution is to have the compiler be smarter! More jobs for the compiler (or you, if you write your own MIPS) but less job for the assembler and processor. The compiler can break this complex statement into multiple smaller statement. Unfortunately, this requires us to use temporary registers which is not mapped into any variables. Luckily, we have 10 of those.

So, first consider breaking the C statement into the following MipC statements:

Complex Expression (in MipC)
1
2
$t0 = $s1 + $s2     // $t0 = b + c
$s0 = $t0 - $s3     // a = $t0 - d

Now we are ready to translate this into MIPS.

Complex Expression (in MIPS)
1
2
add $t0, $s1, $s2   #  $t0 = b + c
sub $s0, $t0, $s3   #  a = $t0 - d

And that is how we can express complex C expressions in MIPS. Of course, the use of MipC to express the intermediate translation is entirely optional.

Complex Expression

Complex Expression (in C)
1
f = (g + h) - (i + j);
Variable Register
f $s0
g $s1
h $s2
i $s3
j $s4

We use two temporary registers to evaluate this: $t0 and $t1.

Complex Expression (in MipC)
1
2
3
$t0 = $s1 + $s2;   // $t0 = g + h
$t1 = $s3 + $s4;   // $t1 = i + j 
$s0 = $t0 - $t1;   // f = $t0 – $t1

We use two temporary registers to evaluate this: $t0 and $t1.

Complex Expression (in MIPS)
1
2
3
add $t0, $s1, $s2  #  $t0 = g + h
add $t1, $s3, $s4  #  $t1 = i + j 
sub $s0, $t0, $t1  #  f = $t0 – $t1

Complex Expression

  1. z = a + b + c + d

    Variable Register
    a $s0
    b $s1
    c $s2
    d $s3
    z $s4
  2. z = (a - b) + c

    Variable Register
    a $s0
    b $s1
    c $s2
    z $s3
  1. Here, we "abuse" the expression to avoid using intermediate register.

    Question 1
    1
    2
    3
    add $s4, $s0, $s1
    add $s4, $s4, $s2
    add $s4, $s4, $s3
    
  2. Again, we also "abuse" the expression to avoid using intermediate register.

    Question 2
    1
    2
    sub $s3, $s0, $s1
    add $s3, $s3, $s2
    

To know the intermediate MipC representation, please click on the tab "Workings"

  1. z = (((a + b) + c) + d)

    Question 1 (in MipC)
    1
    2
    3
    $s4 = $s0 + $s1;   // z = a + b
    $s4 = $s4 + $s2;   // z = z + c
    $s4 = $s4 + $s3;   // z = z + d
    
  2. z = ((a - b) + c)

    Question 2 (in MipC)
    1
    2
    $s3 = $s0 - $s1;   // z = a - b
    $s3 = $s3 + $s2;   // z = z + c
    

Simple Assignment

Complex expressions have a problem of not having enough registers in the operations. Now we will talk about the "opposite" problem. What happen if we have too many registers in the operations? What value should we use?

Note that this is not the problem of i = i+1; because we already have an immediate variants for that. This is more of a problem like i = 0; at the start of the loop. A similar problem is to have f = g;.

Let's look at the second problem first.

Variable-to-Variable Assignment

One trick to solve this problem is to add with 0. So, instead of translating f = g;, we now translate f = g + 0;. This can be easily solved with the immediate variant of add (i.e., the addi).

Variable-to-Variable Assignment V1

Variable-to-Variable Assignment (in C)
1
f = g;
Variable Register
f $s0
g $s1
Complex Expression (in MipC)
1
$s0 = $s1 + 0;    // f = g + 0
Complex Expression (in MIPS)
1
addi $s0, $s1, 0  #  f = g + 0

This is not the only way to translate the assignment. The other solution is to use the register $zero that is guaranteed to have a value of 0. Since this register cannot be written, its value is always 0.

Variable-to-Variable Assignment V2

Variable-to-Variable Assignment (in C)
1
f = g;
Variable Register
f $s0
g $s1
Complex Expression (in MipC)
1
$s0 = $s1 + $zero;   // f = g + zero
Complex Expression (in MIPS)
1
add $s0, $s1, $zero  #  f = g + zero

Pseudo-Instruction

Since assignment is one of the most common instruction in a program (e.g., pass-by-value on function call), there is an equivalent pseudo-instruction that can be used. This instruction is called move. Note that this instruction is a "fake" instruction which will be translated into the corresponding "real" MIPS instruction(s). These pseudo-instructions are provided for convenience during coding only. As such, the assignment above can be solved rather easily with this as follows:

Pseudo-Instruction Move
1
move $s0, $s1

Constant-to-Variable Assignment

Let's now move to the first problem. How do we translate i = 0;? Now that you know about $zero, we have two ways of translating this:

Constant-to-Variable Assignment (in MIPS)
1
2
addi $s0, $zero, 0
add  $s0, $zero, $zero

Unfortunately, the second solution (at line 2) cannot be used for other constant such as i = 4;. In such cases, we have to use the first solution.

Large Constant

But wait, isn't the constant encoded in 16-bits 2s complement? So we can use the trick for constants in the range of -215 to 215-1. The trick, however, fails for large constant (e.g., between -232 to -215-1 and 215 to 232-1).

Such large values can be written in C code since C uses 32-bits 2s complement. But in MIPS, we cannot write those. So what can we do? We will answer this again after we explain logical operations.


  1. In fact, division is so expensive that we typically combine both division and modulo operation into a single divmod operation. 

  2. MipC is not a real language. It is merely an intermediate language to simplify our discussion. We will introduce certain complex instructions that will make this MipC language more applicable for intermediate form for translation later. You can play around with MipC to MIPS compilation

  3. How to do the mapping will be explained later