Code Generation, Continued 1
How to be a MIPS Master • It’s really easy to get confused with assembly • Some suggestions Create super simple test cases • Main procedure: print the value of some expression – Start simple: main procedure with “print(1);” • Create more and more complicated expressions • Get procedure main to compile and run Regression suite • Rerun all test cases to check whether you introduced a bug – Function prologue and epilog • Trivial case of expressions: evaluating the constant 1, which pushes a 1 on the stack • Printing: print(1); – Then grow your compiler incrementally • Expressions • Control constructes • Call/return 2
How to be a MIPS Master • More suggestions – Try writing the desired assembly code by hand before having the compiler generate it – Draw pictures of program flow – Have your compiler put in detailed comments in the assembly code it emits! • Get help – Post on piazza • It’s really easy to get confused with assembly (did I say that already?) 3
Roadmap • Last time: Scanner Scanner – Talked about compiler Tokens Parser Parser backend design points Parse Tree – Decided to go directly from AST AST to machine code for Semantic our language Analysis • This time: Annotated AST Symbol Table – Discuss what the actual MC Codegen codegen pass should look like 4
Review: Global Variables • Showed you one way to do declaration last time: .data .align 2 _name: .space 4 • Simpler form for primitives: .data _name: .word <value> 5
Review: Functions – Preamble • Sort of like the function signature – Prologue • Set up the AR – Body • Do the thing – Epilogue • Tear down the AR 6
Function Preambles int f(int a, int b){ .text int c = a + b; _f: int d = c – 7; #... Function body ... return c; } This label gives us something to jump to jal _f 7
Function Prologue sp space for local 2 • Recall our view of the static space for local 1 sp Activation Record size ctrl link (caller $fp) sp 1. save the return address ret address (caller $ra) 2. save the frame pointer sp fp 3. make space for locals param 1 4. update the frame ptr param 2 low mem caller’s AR fp high mem 8
*sp = ra; Function Prologue: MIPS sp -= 4; *sp = fp; sp -= 4; .text • Recall our view of the _f: sp -= 8; sw $ra 0($sp) #call lnk Activation Record fp = sp + 16; subu $sp $sp 4 # (push) 1. save the return address sw $fp 0($sp) #ctrl lnk subu $sp $sp 4 # (push) 2. save the frame pointer subu $sp $sp 8 #locals 3. make space for locals addu $fp $sp 16 #update fp 4. update the frame ptr 9
Function Epilogue $sp space for local 2 • Restore Caller AR space for local 1 1. restore return address II ctrl link (caller $fp) 2. restore frame pointer ret address (caller $ra) $fp $sp 3. restore stack pointer I 4. return control param 1 param 2 $t0: (old fp) $ra: (old $ra) caller’s AR $fp 10
Function Epilogue: MIPS .text • Restore Caller AR _f: sw $ra 0($sp) 1. restore return address ra = *fp; subu $sp $sp 4 t0 = fp; 2. restore frame pointer sw $fp 0($sp) subu $sp $sp 4 fp = *(fp-4); 3. restore stack pointer subu $sp $sp 8 sp = t0; addu $fp $sp 16 4. return control #... Function body ... lw $ra, 0($fp) move $t0, $fp lw $fp, -4($fp) move $sp, $t0 jr $ra 11
Function Body • Obviously, quite different based on content – Higher-level data constructs • Loading parameters, setting return • Evaluating expressions – Higher-level control constructs • Performing a call • While loops • If-then and if-then-else statements 12
Function Locals sp space for local 2 .text _f: space for local 1 # … prologue … # lw $t0, -8($fp) ctrl link (caller $fp) lw $t1, -12($fp) fp ret address (caller $ra) param 1 # … epilogue … # param 2 caller’s AR 13
Function Returns sp space for local 2 .text _f: space for local 1 # … prologue … # lw $t0, -8($fp) ctrl link (caller $fp) lw $t1, -12($fp) lw $v0, -8($fp) fp ret address (caller $ra) j _f_exit _f_exit: param 1 # … epilogue … # param 2 caller’s AR 14
Function Body: Expressions • Goal – Linearize (“flatten”) an expression tree • Use the same insight as SDT during parsing – Use a work stack and a post-order traversal Visit 1 Visit 2 + Visit id Visit * Visit + 1 * 2 id 15
Linearized Pseudocode • Key insights – Use the stack-pointer location as “scratch space” Push the value of id! – At operands: push value onto the stack – At operators: pop source values from stack, push result $t1 = id push 2 $t0 = 2 2 * id I IV push id pop id into t1 * pop 2 into t0 id mult t0 * t1 into t0 II III 2 push t0 2 id result (2 * id) 16
Linearized MIPS L1: li $t0 2 .data sw $t0 0($sp) _id: .word <value> subu $sp $sp 4 L2: lw $t0 _id .text sw $t0 0($sp) L1: push 2 subu $sp $sp 4 L2: push id L3: lw $t1 4($sp) L3: pop id into t1 addu $sp $sp 4 L4: pop 2 into t0 L4: lw $t0 4($sp) L5: mult t0 * t1 into t0 addu $sp $sp 4 L6: push t0 L5: mult $t0 $t0 $t1 L6: sw $t0 0($sp) subu $sp $sp 4 17
Function Body: Expressions • Goal – Linearize (“flatten”) an expression tree • Use the same insight as SDT during parsing – Use a work stack and a post-order traversal Visit 1 push 1 Visit 2 push 2 Visit id push value of id + Visit * pop id into t1 pop 2 into t0 mult t0 * t1 into t0 push t0 1 * Visit + pop into t1 pop 1 into t0 add t0 + t1 into t0 2 id push t0 18
Assignment Statements • By the end of the expression, the stack isn’t exactly as we found it – Contains the value of the expression – This organization is intentional 1) Compute address of LHS location ; leave result on stack assign 2) Compute value of RHS expr; leave result on stack 3) Pop RHS into $t1 4) Pop LHS into $t0 5) Store value $t1 at the address held in $t0 loc (exp) 19
Simple Assignment, You Try sp • Generate stack-machine id2 style MIPS code for (space for id) id = 1 + 2; ctrl link (caller $fp) fp ret address (caller $ra) param 1 Algorithm 1) Compute address of LHS location ; leave result on stack 2) Compute value of RHS expr; leave result on stack param 2 3) Pop RHS into $t1 4) Pop LHS into $t0 5) Store value $t1 at the address held in $t0 caller’s AR 20
Dot Access • Fortunately, we know the offset from the base of a struct to a certain field statically – The compiler can do the math for the slot address – This isn’t true for languages with pointers! struct Inner{ bool hi; int there; struct Demo inst; int c; struct Demo inst2; }; inst.b.c = inst2.b.c + 1; struct Demo{ load this value struct Inner b; load this address int val; }; 21
Dot Access Example void v(){ sp struct Inner{ inst is based at $fp-8 bool hi; inst.val field b.c is -8 off the base int there; int c; inst.b.c }; struct Demo{ inst.b.there struct Inner b; int val; inst.b.hi }; struct Demo inst; ctrl link (caller $fp) … = inst.b.c; inst.b.c = …; } fp ret address (caller $ra) LHS RHS subu $t0 $fp 16 lw $t0 -16($fp) caller’s AR sw $t0 0($sp) sw $t0 0($sp) subu $sp $sp 4 subu $sp $sp 4 22
Control-Flow Constructs • Function Calls • Loops • Ifs 23
Function Call • Two tasks: – Put argument values on the stack (pass-by-value semantics) – Jump to the callee preamble label – Bonus 3 rd task: save live registers • (We don’t have any in a stack machine) • On return – Tear down the actual parameters – Retrieve and push the result value 24
Function-Call Example int f(int arg1, int arg2){ return 2; } int main(){ int a; a = f( a, 4) ; } li $t0 4 # push arg 2 sw $t0 0($sp) # subu $sp $sp 4 # lw $t0 -8($fp) # push arg 1 sw $t0 0($sp) # subu $sp $sp 4 # jal _f # call f (via jump and link) addu $sp $sp 8 # tear down actual parameters sw $v0 0($sp) # retrieve and push the result subu $sp $sp 4 # 25
Generating If-Then[-Else] Statements • First, obtain names to use for the labels of the – [false branch] – successor • Generate code for the branch condition – Can emit a jump to the (not-yet placed!) false-branch label • Generate code for the true branch – Emit the code for the body of the true branch – [Emit a jump to the (not-yet placed!) successor label] • [Generate code for the false branch (similar to the true branch) – Emit the false-branch label – Emit the code for the body of the false branch] • Emit the successor label 26
If-Then Statement Example … lw $t0 _val # evaluate condition LHS sw $t0 0($sp) # push onto stack if (val == 1){ subu $sp $sp 4 # val = 2; li $t0 1 # evaluate condition RHS } sw $t0 0($sp) # push onto stack … subu $sp $sp 4 # lw $t1 4($sp) # pop RHS into $t1 addu $sp $sp 4 # lw $t0 4($sp) # pop LHS into $t0 addu $sp $sp 4 # bne $t0 $t1 L_0 # branch if condition false li $t0 2 # true branch sw $t0 _val j L_0 # end true branch L_0: # successor label … 27
Recommend
More recommend