Description
Overview
You must use C for this homework assignment, and your code must successfully execute on
Submitty to obtain full credit.
Homework Specifications
For this individual homework assignment, we revisit Homework 2 and implement a rudimentary
compiler in C that translates one or more arithmetic expressions as assignment statements into
valid MIPS code. Just as with Homework 2, you can assume that each C variable name is one
lowercase letter (e.g., a, b, c, etc.) and of type int.
Unlike Homework 2, in this assignment, integer constants may be positive, negative, or zero. Further, you will need to support the addition (+), subtraction (-), multiplication (*), division (/),
and mod (%) operators. Treat all of these as 32-bit integer operations with each operation requiring
two operands.
You will also need to support multiple lines of input, i.e., multiple assignment instructions. To avoid
overcomplicating your implementation, you can assume that each assignment statement will consist
of a mix of addition and subtraction operations, a mix of multiplication or division operations, or
a simple assignment (e.g., x = 42).
Therefore, you can always parse each line from left to right.
As with Homework 2, the MIPS code you generate must make proper use of registers $s0,…,$s7
to correspond to C variables and registers $t0,…$t9 to correspond to any temporary variables you
need.
Variables in MIPS should match those in C from left to right. Note that unlike Homework 2,
the final result of the last assignment statement likely will not end up in register $s0.
You can again assume that you will not need more than the specific MIPS registers listed here,
with use of temporary registers cycling from $t9 back to $t0 as necessary.
Required Input and Output
Your code must read the input file specified as the first command-line argument (i.e., argv[1]).
Translate each line of input into corresponding MIPS instructions. And include as a comment each
original line being translated. Note that the use of pseudo-instructions is fine.
Below are a few example runs of your program that you can use to better understand how your
program should work, how you can test your code, and what output formatting to use for Submitty.
In the first example (i.e., with input example1.src), register $s0 corresponds to C variable g,
register $s1 corresponds to h, and register $s2 corresponds to f.
bash$ cat example1.src
g = 100;
h = 200;
f = g + h – 42;
bash$ ./a.out example1.src
# g = 100;
li $s0,100
# h = 200;
li $s1,200
# f = g + h – 42;
add $t0,$s0,$s1
addi $s2,$t0,-42
bash$ cat example2.src
q = 12;
j = q – 2;
x = q * q / j;
bash$ ./a.out example2.src
# q = 12;
li $s0,12
# j = q – 2;
addi $s1,$s0,-2
# x = q * q / j;
mult $s0,$s0
mflo $t0
div $t0,$s1
mflo $s2
Be sure to test your resulting MIPS code, for example by using print $N in spim to verify your
MIPS code properly computes the correct answers and stores it in the appropriate registers.
2
For multiplication and division, you will need to make use of the HI and LO registers, as shown in
the following example.
bash$ cat example3.src
a = 10;
b = 73;
c = a * b / a;
bash$ ./a.out example3.src
# a = 10;
li $s0,10
# b = 73;
li $s1,73
# c = a * b / a;
mult $s0,$s1
mflo $t0
div $t0,$s0
mflo $s2
Assumptions
Given the complexity of this assignment, you can make the following assumptions:
Assume all input files are valid.
Assume the length of argv[1] is at most 128 characters.
Assume that constants will only appear as the second operand to a valid operator (e.g., x = 42 / y
is not possible).
Assume that expressions will never have two constants adjacent to one another (e.g., x = 42 / 13
is not possible).
3
Simplifying Multiplication and Division
There are two “simplifications” that you are required to implement. When you multiply or divide
involving a constant operand, there are cases in which you should not use mult or div instructions.
Instead, for multiplication, break the constant down into its sum of powers of two, then use a series
of sll instructions to perform each multiplication, adding the resulting intermediate products.
As an example, to multiply n by constant 45, start by determining sum 25 + 23 + 22 + 20 =
32 + 8 + 4 + 1 = 45. Next, multiply n × 32, n × 8, and n × 4 using three successive sll instructions.
Note that there is no need to multiply n by 1 for the last term.
Finally, add each term as you calculate it, thereby accumulating a sum. More specifically, the first
intermediate product should be placed in the target register via move, while subsequent intermediate
products should be added via add.
Note that you should use only two temporary registers for this, the first to calculate each required
power of 2, the second to accumulate the sum. For example, the example4.src input shown below
should produce the MIPS code shown.
bash$ cat example4.src
n = 100;
b = n * 45;
bash$ ./a.out example4.src
# n = 100;
li $s0,100
# b = n * 45;
sll $t0,$s0,5
move $t1,$t0
sll $t0,$s0,3
add $t1,$t1,$t0
sll $t0,$s0,2
add $t1,$t1,$t0
add $t1,$t1,$s0
move $s1,$t1
To multiply by a negative constant (e.g., n * -45), replace the last move instruction with a subtraction from $zero, as in:
sub $s1,$zero,$t1
And to multiply by given constant 0, treat this as a special case in which the target variable/register
simply is assigned to 0 (as shown below). Note that this could be a temporary register if it appears
as part of a longer expression.
li $s3,0
4
Another special case is multiplying by constant 1 or -1. These cases are shown via the example
snippets below:
# b = a * 1;
move $t0,$s0
move $s1,$t0
# b = a * -1;
move $t0,$s0
sub $s1,$zero,$t0
Division
The relationship status of division is definitely “it’s complicated.”
For division in this assignment, if the divisor is an exact power of 2 (e.g., 32), we might be able
to use the right-shift simplification in MIPS. More specifically, we can use this simplification if the
first operand is non-negative.
To implement this logic in MIPS, we can use the bltz (Branch if Less Than Zero) instruction to
test whether the first operand is negative. If it is negative, we then branch to the standard div/mflo
approach described earlier. The example below shows generated MIPS code for the above logic
(regardless of variable n):
bash$ cat example5.src
n = 100;
b = n / 32;
bash$ ./a.out example5.src
# n = 100;
li $s0,100
# b = n / 32;
bltz $s0,L0
srl $s1,$s0,5
j L1
L0:
li $t0,32
div $s0,$t0
mflo $s1
L1:
Note that labels should be generated as L0, L1, L2, …, L10, L11, L12, …, and be on lines of their
own (as shown above).
And to divide by a negative constant (e.g., n / -32), after the srl instruction, perform a subtraction
from $zero, i.e., sub $s1,$zero,$s1. Further, for the special case of dividing by constant 1 or -1,
the following examples show the required behavior:
# b = a / 1;
move $s1,$s0
# b = a / -1;
sub $s1,$zero,$s0
5
Submission Instructions
Before you submit your code, be sure that you have clearly commented your code (this should not
be an after-thought). Further, your code should have a clear and logical organization.
To submit your assignment (and also perform final testing of your code), please use Submitty.
Note that the test cases for this assignment will be available on Submitty a minimum of three days
before the due date and will include hidden test cases.
Also as a reminder, your code must successfully execute on Submitty to obtain credit for this
assignment.
6