| 1 | = INTRODUCTION =
|
---|
| 2 |
|
---|
| 3 | Welcome reader,
|
---|
| 4 |
|
---|
| 5 | You will find our solution on assignment 4 of Compiler Constructions 2008
|
---|
| 6 | given at LIACS University. First we will give you a grand overview of the files
|
---|
| 7 | altered, next we will bullet point the most important design decisions. After that
|
---|
| 8 | an example is shown.
|
---|
| 9 |
|
---|
| 10 | And the grand finale will show the usage of the program.
|
---|
| 11 |
|
---|
| 12 | Enjoy!
|
---|
| 13 | Johan and Rick <hvdzwet@liacs.nl>
|
---|
| 14 |
|
---|
| 15 | = FILES EDITED/ADDED =
|
---|
| 16 | A globals.h = Some global definitions
|
---|
| 17 | A MOperand.cc = Represents a operand for a MIPS statement
|
---|
| 18 | A MOperator.cc = Represents a MIPS operator/opcode
|
---|
| 19 | A MStatement.cc = Represents MIPS statements
|
---|
| 20 | E StackFrameManager.cc = Manages the stack frame
|
---|
| 21 | A RegisterManager.cc
|
---|
| 22 | E CodeGenerator.cc
|
---|
| 23 | E main.cc = Main program function, argument parsing
|
---|
| 24 |
|
---|
| 25 | = DESIGN DECISIONS =
|
---|
| 26 | * Added a register manager to keep track of what symbols are associated with what
|
---|
| 27 | registers. The register manager also loads the register if it's new and writes
|
---|
| 28 | it back to memory.
|
---|
| 29 |
|
---|
| 30 | * The current implementation for spilling a register is to select a random one. Also
|
---|
| 31 | all registers are written back before a function call, before the end of a
|
---|
| 32 | function and before jumps and branches. This can be optimized in the next assignment.
|
---|
| 33 |
|
---|
| 34 | * We prefix all the symbol names with "__" to prevent name clashes with MIPS
|
---|
| 35 | assembly instructions.
|
---|
| 36 |
|
---|
| 37 | * Register $V0 is used for integer function return values and $f0 for real
|
---|
| 38 | return values.
|
---|
| 39 |
|
---|
| 40 | * Register $V1 is used for expressions
|
---|
| 41 |
|
---|
| 42 | * Registers $A0, $A1, $A2 and $A3 do not have to be gotten through the RegisterManager
|
---|
| 43 | and can thus be used as temporaries inside a known code block while generating code.
|
---|
| 44 |
|
---|
| 45 | * The stack pointer $sp points to the last used word on the stack. We generate code
|
---|
| 46 | that assumes it's pointing to the first free word. Therefore the stack is increased
|
---|
| 47 | by one word in main before calling the program body.
|
---|
| 48 |
|
---|
| 49 | * The stack frame layout is as follows:
|
---|
| 50 | ^ ^
|
---|
| 51 | | |
|
---|
| 52 | $fp + 8 second parameter
|
---|
| 53 | $fp + 4 first parameter
|
---|
| 54 | $fp + 0 return address
|
---|
| 55 | $fp - 4 previous frame pointer
|
---|
| 56 | $fp - 8 return value
|
---|
| 57 | $fp - 12 first local variable
|
---|
| 58 | $fp - 16 second local variable
|
---|
| 59 | | |
|
---|
| 60 | v v
|
---|
| 61 |
|
---|
| 62 | * We created a framework for Assembly code, model-ed after the intermediate code
|
---|
| 63 | framework. This was done to separate the generation of the output file from
|
---|
| 64 | generation of the code. It can also later be used to implement further
|
---|
| 65 | optimizations on the MIPS assembly code.
|
---|
| 66 |
|
---|
| 67 | = SAMPLE GENERATED CODE =
|
---|
| 68 | C01) program example;
|
---|
| 69 | C02)
|
---|
| 70 | C03) var x, y, z: integer;
|
---|
| 71 | C04) function foo(a,b: integer): integer;
|
---|
| 72 | C05) begin
|
---|
| 73 | C06) foo := 1
|
---|
| 74 | C07) end;
|
---|
| 75 | C08)
|
---|
| 76 | C09) begin
|
---|
| 77 | C10) x := readinteger;
|
---|
| 78 | C11) y := 20;
|
---|
| 79 | C12) z := x + 20;
|
---|
| 80 | C13) z := z + foo(0,0)
|
---|
| 81 | C14) end.
|
---|
| 82 |
|
---|
| 83 | 1 ## Output generated by ./comp @ kubuntu-desktop
|
---|
| 84 | 2 ## Thu Nov 20 14:30:48 2008
|
---|
| 85 | 3
|
---|
| 86 | 4 ## Compiler Construction Course - Leiden University - LIACS
|
---|
| 87 | 5 ## Johan IJsveld - Rick van der Zwet
|
---|
| 88 | 6 ## BSD Licenced
|
---|
| 89 | 7
|
---|
| 90 | 8 .data # Global data section
|
---|
| 91 | 9 .align 4
|
---|
| 92 | 10 __x:
|
---|
| 93 | 11 .word 0
|
---|
| 94 | 12 __y:
|
---|
| 95 | 13 .word 0
|
---|
| 96 | 14 __z:
|
---|
| 97 | 15 .word 0
|
---|
| 98 | 16
|
---|
| 99 | 17 .text # Code section
|
---|
| 100 | 18 .align 4
|
---|
| 101 | 19 .globl main
|
---|
| 102 | 20
|
---|
| 103 | 21 .ent main
|
---|
| 104 | 22 main:
|
---|
| 105 | 23 addi $sp, $sp, -4
|
---|
| 106 | 24 jal __example # Jump to program body
|
---|
| 107 | 25 addi $sp, $sp, 4
|
---|
| 108 | 26 addi $v0, $0, 10 # Exit system call
|
---|
| 109 | 27 syscall
|
---|
| 110 | 28 .end main
|
---|
| 111 | 29
|
---|
| 112 | 30 .ent __example
|
---|
| 113 | 31 __example:
|
---|
| 114 | 32 sw $ra, 0($sp) # Set up stack frame
|
---|
| 115 | 33 sw $fp, -4($sp)
|
---|
| 116 | 34 move $fp, $sp
|
---|
| 117 | 35 addi $sp, $sp, -28
|
---|
| 118 | 36 jal __readinteger
|
---|
| 119 | 37 lw $t0, -12($fp) # Load integer Register
|
---|
| 120 | 38 move $t0, $v0 # Store integer function result
|
---|
| 121 | 39 lw $t1, __x # Load integer Register
|
---|
| 122 | 40 move $t1, $t0 # Assign integer
|
---|
| 123 | 41 lw $t2, __y # Load integer Register
|
---|
| 124 | 42 addi $t2, $0, 20 # Assign constant integer
|
---|
| 125 | 43 lw $t3, -16($fp) # Load integer Register
|
---|
| 126 | 44 addi $a0, $0, 20
|
---|
| 127 | 45 add $t3, $t1, $a0 # Add integers
|
---|
| 128 | 46 lw $t4, __z # Load integer Register
|
---|
| 129 | 47 move $t4, $t3 # Assign integer
|
---|
| 130 | 48 addi $v1, $0, 0 # Push constant integer parameter
|
---|
| 131 | 49 sw $v1, 0($sp)
|
---|
| 132 | 50 addi $sp, $sp, -4
|
---|
| 133 | 51 addi $v1, $0, 0 # Push constant integer parameter
|
---|
| 134 | 52 sw $v1, 0($sp)
|
---|
| 135 | 53 addi $sp, $sp, -4
|
---|
| 136 | 54 sw $t0, -12($fp) # Write back integer register
|
---|
| 137 | 55 sw $t1, __x # Write back integer register
|
---|
| 138 | 56 sw $t2, __y # Write back integer register
|
---|
| 139 | 57 sw $t3, -16($fp) # Write back integer register
|
---|
| 140 | 58 sw $t4, __z # Write back integer register
|
---|
| 141 | 59 jal __foo
|
---|
| 142 | 60 lw $t0, -20($fp) # Load integer Register
|
---|
| 143 | 61 move $t0, $v0 # Store integer function result
|
---|
| 144 | 62 lw $t1, -24($fp) # Load integer Register
|
---|
| 145 | 63 lw $t2, __z # Load integer Register
|
---|
| 146 | 64 add $t1, $t2, $t0 # Add integers
|
---|
| 147 | 65 move $t2, $t1 # Assign integer
|
---|
| 148 | 66 sw $t0, -20($fp) # Write back integer register
|
---|
| 149 | 67 sw $t1, -24($fp) # Write back integer register
|
---|
| 150 | 68 sw $t2, __z # Write back integer register
|
---|
| 151 | 69 lw $ra, 0($fp) # Return from call
|
---|
| 152 | 70 lw $fp, -4($fp)
|
---|
| 153 | 71 addi $sp, $sp, 28
|
---|
| 154 | 72 jr $ra
|
---|
| 155 | 73 .end __example
|
---|
| 156 | 74
|
---|
| 157 | 75 .ent __foo
|
---|
| 158 | 76 __foo:
|
---|
| 159 | 77 sw $ra, 0($sp) # Set up stack frame
|
---|
| 160 | 78 sw $fp, -4($sp)
|
---|
| 161 | 79 move $fp, $sp
|
---|
| 162 | 80 addi $sp, $sp, -12
|
---|
| 163 | 81 lw $t0, -8($fp) # Load integer Register
|
---|
| 164 | 82 addi $t0, $0, 1 # Assign constant integer
|
---|
| 165 | 83 sw $t0, -8($fp) # Write back integer register
|
---|
| 166 | 84 lw $t0, -8($fp) # Load integer Register
|
---|
| 167 | 85 move $v0, $t0 # Store integer return value
|
---|
| 168 | 86 lw $ra, 0($fp) # Return from call
|
---|
| 169 | 87 lw $fp, -4($fp)
|
---|
| 170 | 88 addi $sp, $sp, 20
|
---|
| 171 | 89 jr $ra
|
---|
| 172 | 90 .end __foo
|
---|
| 173 | 91
|
---|
| 174 | 92 .ent __readinteger # Start of builtin functions and procedures
|
---|
| 175 | 93 __readinteger:
|
---|
| 176 | 94 addi $v0, $0, 5
|
---|
| 177 | 95 syscall
|
---|
| 178 | 96 jr $ra
|
---|
| 179 | 97 .end __readinteger
|
---|
| 180 | 98
|
---|
| 181 | 99 .ent __writeinteger
|
---|
| 182 | 100 __writeinteger:
|
---|
| 183 | 101 lw $a0, 4($sp)
|
---|
| 184 | 102 addi $v0, $0, 1
|
---|
| 185 | 103 syscall
|
---|
| 186 | 104 addi $sp, $sp, 4
|
---|
| 187 | 105 jr $ra
|
---|
| 188 | 106 .end __writeinteger
|
---|
| 189 | 107
|
---|
| 190 | 108 .ent __readreal
|
---|
| 191 | 109 __readreal:
|
---|
| 192 | 110 addi $v0, $0, 6
|
---|
| 193 | 111 syscall
|
---|
| 194 | 112 jr $ra
|
---|
| 195 | 113 .end __readreal
|
---|
| 196 | 114
|
---|
| 197 | 115 .ent __writereal
|
---|
| 198 | 116 __writereal:
|
---|
| 199 | 117 l.s $f12, 4($sp)
|
---|
| 200 | 118 addi $v0, $0, 2
|
---|
| 201 | 119 syscall
|
---|
| 202 | 120 addi $sp, $sp, 4
|
---|
| 203 | 121 jr $ra
|
---|
| 204 | 122 .end __writereal
|
---|
| 205 | 123
|
---|
| 206 |
|
---|
| 207 | Lines 8 through 16 shows the space for globals being reserved.
|
---|
| 208 | Lines 21 through 28 is the main function calling the program body and doing a syscall to exit.
|
---|
| 209 | Lines 30 through 73 is the program body code.
|
---|
| 210 | Lines 75 through 90 is the function foo, where on lines 77 through 80 the stack
|
---|
| 211 | frame is set up. In lines 81 through 85 the return value 1 is stored on the stack
|
---|
| 212 | and then put in the return register $v0.
|
---|
| 213 | On line 86 and line 87, $ra and the old $fp are restored. The stack is shrunk back again,
|
---|
| 214 | including parameters, on line 88 and on line 89 is the jump back from where the call was made.
|
---|
| 215 | After line 92 are the builtin functions.
|
---|
| 216 |
|
---|
| 217 | = USAGE =
|
---|
| 218 | # Compile
|
---|
| 219 | $ make first
|
---|
| 220 | $ make
|
---|
| 221 | # Call without optimalisation
|
---|
| 222 | $ ./comp -w -00 <testfile
|
---|
| 223 | # Call with optimalisation
|
---|
| 224 | $ ./comp -w -01 <testfile
|
---|
| 225 | The resultant MIPS assembly is stored in the file "out.s".
|
---|