370 likes | 402 Views
This lecture covers the process of generating target code by walking the AST from top to bottom and applying rules for each node, including basic operations like emitting instructions and handling binary operations. Specific examples and code snippets are provided for better understanding.
E N D
Lecture 8 AST Visiting and Code Generation Xiaoyin Wang CS 5363 Programming Languages and Compilers
Code Generation • Tree Walking • Code Generation Rules • Control Flow Graph
Code Generation • After we constructed the AST and decorated it • We finally start working on generating target code • Here we output 3-address code • Still an intermediate representation • Assuming unlimited registers • No machine specifications • Format: op src1 src2 => dest
Code Generation • It is surprisingly simple: • You just need to walk the tree from top to bottom • Apply rules for each AST Node • Then, we are done!
Code Generation • Basic Operations • Emit: write an instruction or a label to the instruction stream • Register.Next(): get the next available register • Label.Next(): get the next available label • For expression AST Nodes, add a register field to save the register that stores its value
Tree walking • Depth-first tree walking • Always visit children left to right
Applying Rules: Binary Operation • Decide what should the code do (semantics) for each AST Node • For example: Consider Add (left, right) • What you want to do is:eval <left> eval <right> add left, right => result
Applying Rules: Binary Operation • So in your code: public void visit (Add add){ add.left.accept(this); Register r1 = add.left.reg; add.right.accept(this); Register r2 = add.right.reg; Register r3 = Register.next(); emit(new instruction(‘add’, r3, r1, r2)); add.reg = r3; }
Applying Rules: Binary Operation • Another example: • expr1 > expr2 eval <expr1> eval <expr2> set1g expr1, expr2 => result
Applying Rules: Binary Operation • Code Example public void visit (Compare comp){ comp.left.accept(this); Register r1 = comp.left.reg; comp.right.accept(this); Register r2 = comp.right.reg; Register r3 = Register.next(); swtich(comp.op){ case ‘>’: emit(new instruction(‘set1g’, r3, r1, r2));break; case ‘>=’: … … } comp.reg = r3; }
Applying Rules: Num Literal • For an immediate number • We just need to assign it to a register, which can be used later • Code: public void visit(NumLiteral num){ Register r1 = Register.next(); num.reg = r1; emit( new Instruction (‘mov’, r1, num.value) ); }
Applying Rules: Identifier • What we should do: • Just find out which register the value is saved in • If no register is found: error, the variable is not initialized public void visit(Identifier ident){ Register r1 = symbolTable.get(ident.name).reg; if (r1 != null) { ident.reg = r1;} else {throw exception … } }
Applying Rules: Assignment • Ident := expr • What we should do • First eval expr • Then find the register of the ident / Or create a new register for the ident • Insert the mov instruction
Applying Rules: Assignment • Ident := expr • What we should do • First eval expr • Then find the register of the ident / Or create a new register for the ident • Insert the mov instruction expr.accept(this); Register r1 = expr.reg; r2 = symbolTable.get(ident.name).reg; if(r2 == null){ r2 = Register.next(); symbolTable.get(ident.name).reg = r2; } emit(new Instruction('mov', r2, r1));
Applying Rules: If statement • Another example: if expr then stmt1 else stmt2; IfElseStmt thenStmt elseStmt cond
Applying Rules: If statement • What we want is: 1. evaluate cond expression 2. if return true: goto then stmt 3. else: goto else stmt 4. goto the end of the stmt on each of the branches
Applying Rules: If statement Eval Cond • Control Flow: Code pattern: <eval condition> JZ reg ELSE <then statements> JMP END ELSE: <else statements> END: True? JZ thenStmt elseStmt JMP end
Applying Rules: If statement • So in your code: public Register visit (IfElseStmtifelse){ ifelse.cond.accept(this); Register r1 = ifelse.cond.reg; Label elseLabel = Label.next(); Label endLabel = Label.next(); emit (new Instruction(‘JZ’, r1, elseLabel)) ifelse.thenStmt.accept(this); emit (new Instruction(‘JMP’, endLabel)) emit (elseLabel); ifelse.elseStmt.accept(this); emit (endLabel) }
Applying Rules: while statement while cond do stmt end WhileStmt stmt cond
Applying Rules: while statement • What we want is: 1. Set a label Start before evaluate cond expression 2. evaluate cond expression 3. if false: goto label End 4. else: go on to execute stmt 5. goto label Start
Applying Rules: while statement • Control Flow: Code pattern: Eval Cond Start: <eval condition> JZ reg END <stmt> JMP Start END: True? JMP JZ stmt end
Applying Rules: while statement • So in your code: public Register visit (WhileStmt while){ Label startLabel = Label.next(); emit(startLabel) while.cond.accept(this); Register r1 = while.cond.reg; Label endLabel = Label.next(); emit (new Instruction(‘JZ’, r1, endLabel)) while.stmt.accept(this); emit (new Instruction(‘JMP’, startLabel)) emit (endLabel) }
Instruction Set The Appendix A of MIPS Assembly Specification On the course website A more brief summary at http://xywang.100871.net/SPIM_instr.pdf
Instruction Set Registers and Memory address Memory instructions Arithmetic instructions Comparison instructions Branch instructions System call related instructions
Registers and Memory address (A-24) $zero: 0 $t0 – $t9: local variables $s0 – $s7: global variables $a0 – $a3: function arguments $v0, v1: function return values $fp: frame pointer (first byte) $sp: stack pointer (last byte)
Memory Instructions (A65) li: Load immediate value Example: li $t0, 2 la: Load address Example: la $t0, str lw: Load value from memory Example: lw $t0, -4($fp) sw: save value to memory Example: sw $t0, -4($fp)
Arithmetic instructions (A51-A57) add / addu / addi Example: addu $t0, $t1, $t2 sub / subu mul / mulo / mulou div / divu rem / remu
Comparison instructions (A57-A59) slt : set 1 if less than Example: slt $t0, $t1, $t2 slti: set 1 if less than immediate Example: slt $t0, $t1, 3 seq: set 1 if equal sgt: set 1 if greater sge, sle, sne
Branch instructions (A59-A63) j/b: jump to label Example: j bbb beqz / bnez: jump to label if equal or not equal to zero Example: beqz $t0 bbb beq, bne, bgt, …
System calls: for read/write int System call code: in $v0 1: print int, parameter in $a0 5: read int, result in $v0 Example: li $v0, 4 la $a0, newline syscall li $v0, 5 syscall add $t0, $v0, $zero
Control Flow Graph • An intermediate presentation of target code • Enables flow-oriented code optimization • Better understanding of the code
Basic Blocks • A block of the code that will be sequentially executed • With no jump instructions and labels for other instructions to jump to • Nodes in the control flow graph
Generate Control Flow Graph with Basic Blocks • In the generated code • Step 1: split the code to a number of basic blocks • Step 2: find the relationship between all basic blocks, for each basic block: • Its predecessors are the basic block directly before it (if no unconditional jump at the end), and all blocks can jump to it • Its successors are the basic block directly after it (if no unconditional jump at the end), and all blocks it jumps to
mov 0 => r_SQRT readint => r_N mov 0 => r_SQRT readint => r_N L1: cmp_LE r1, r_N => r2 jumpeqz r2 -> L2 add r_SQRT, 1 => r4 mov r4 => r_SQRT jump -> L1 L2: sub r_SQRT, r5 => r6 writeInt r_SQRT exit L1: cmp_LE r1, r_N => r2 jumpeqz r2 -> L2 break add r_SQRT, 1 => r4 mov r4 => r_SQRT jump -> L1 L2: sub r_SQRT, r5 => r6 writeInt r_SQRT exit
Block 1: mov 0 => r_SQRT readint => r_N Block 2: L1: cmp_LE r1, r_N => r2 jumpeqz r2 -> L2 Block 3: add r_SQRT, 1 => r4 mov r4 => r_SQRT jump -> L1 Block 4: L2: sub r_SQRT, r5 => r6 writeInt r_SQRT exit
Basic Transformation From 3 address code to MIPS code 3 address code: Assumes unlimited number of registers MIPS code: Only limited number of registers, but memory can be normally viewed as unlimited
Basic Transformation From 3 address code to MIPS code Therefore Any: Op r_x, r_y => r_z Can transform to: lw $t1, -4*x($fp) lw $t2, -4*y($fp) Op $t0, $t1, $t2 sw $t0, -4*z($fp)