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