Intermediate code generation
Lecture 16
Table of Contents
Code generation
- Keep in mind both
Expressions
- Use expression visitor
- Return value is a temporary variable that holds the expression's value at run-time
call
- for each param
- recursively generate code for the expression
- emit a PARAM
- emit a CALL
negate
- recursively generate code for the expression
- emit const 0
- emit a substraction
not
- emit the equivalent logic using goto instructions
for example,
! true
CONST _t1 1 # true GOTOZE _l1 _t1 # branch if false CONST _t2 0 # set result to false, i.e., negate true GOTO _l2 # goto the end LABEL _l1 # false block CONST 1 # set result to true, i.e., negate false LABEL _l2 # end label
binary arithmetic operators
- recursively generate code for the left operand
- recursively generate code for the rigth operand
- emit the corresponding arithmetic opcode
- PLUS for addition, MINUS for substraction, MULT for multiplication, DIV for division
binary relational operators
- recursively generate code for the left operand
- recursively generate code for the right operand
- emit the equivalent logic using goto instructions
- GOTONE for equals, GOTONE for not equals, GOTOGE for less than, GOTOLE, for greater than, GOTOGT for less than or equals, GOTOLT for greater than or equals
- notice that these are the logical opposite operations
- in my implementation i put the "if" branch first, so branch only if condition is false
- could also put "else" branch first and not use the opposite operations
for example,
2 =
x=CONST _t1 2 # lhs # rhs is just x GOTONE _l1 _t1 x # branch if false CONST _t2 1 # set result to true, i.e., values are equal GOTO _l2 # goto the end LABEL _l1 # false block CONST _t2 0 # set result to false, i.e., values are not equal LABEL _l2 # end label # _t2 now holds results of =2 == x=
binary boolean operators
- recursively generate code for the left operand
- recursively generate code for the right operand
- emit the corresponding boolean operator code
- and: if either of the two operands are false, then the result is false, otherwise it's true
- or: if either of the two operands are true, then the result is true, otherwise it's false
for example,
=x and y=
GOTOZE _l1 x # go to false branch GOTOZE _l1 y # go to false branch CONST _t1 1 # result is true if neither operand is false GOTO _l2 # goto end label LABEL _l1 # false block CONST _t1 0 # result is false LABEL _l2 E end label
for example,
=x or y=
GOTONZ _l1 x # go to true branch GOTONZ _l1 y # go to true branch CONST _t1 0 # result is false if neither operand is true GOTO _l2 # goto end label LABEL _l1 # true block CONST _t1 1 # result is true LABEL _l2 E end label
variables (given)
- just use the variable name as the result of visiting the variable
- no code needed to emit
num (given)
- create a fresh temp variable
- emit a CONST
parens (given)
- does not code emission
- just recursively emit code
Statements
program (given)
- does nothing, just visit its children
function (given)
- add formal parameters as local variables
- add true and false as local variables
- add declarations as local variables
- emit CONST to set true and false
- recursively emit code for the body statement
- save the emitted function code
input
- emit INPUT
output
- recursively generate code for the expression
assignment
- recursively generate code for the expression
- emit an ASSIGN
while
- emit the head label
- recursively generate code for the conditional expression, saving the resulting temp variable
- emit a branch for when the condition is false to the end label
- recursively generate code for the body statement
- emit an unconditional branch to the head label
- emit the end label
example of
while(x > 0) { x = x - 1; }
LABEL _l0_main # head label # generated code for x > 0 CONST _t2 0 GOTOLE _l2_main x _t2 CONST _t3 1 GOTO _l3_main LABEL _l2_main CONST _t3 0 LABEL _l3_main GOTOZE _l1_main _t3 # branch for false # generated code for the body CONST _t4 1 SUB _t5 x _t4 ASSIGN x _t5 GOTO _l0_main # branch to head LABEL _l1_main # end label
ifthenelse
- recursively generate code for the condition expression
- emit a branch for when the condition is false to the else label
- recursively generate code for the if body
- emit an unconditional branch to the end label (to skip the else body)
- emit the else label
- recursively generate code for the else body
- emit the end label
return (given)
- recursively generate code for the expression
- emit the RETURN
skip
- emit a NOP
compound
- for each statement context in
ctx.stmt()
, call visit on the statement context
Complete example
- AST
- visitor traversal
- temporary variable handling
- emitted code
while(x > 0) { x = x - 1; }
LABEL _l0_main # head label # generated code for x > 0 CONST _t2 0 GOTOLE _l2_main x _t2 CONST _t3 1 GOTO _l3_main LABEL _l2_main CONST _t3 0 LABEL _l3_main GOTOZE _l1_main _t3 # branch for false # generated code for the body CONST _t4 1 SUB _t5 x _t4 ASSIGN x _t5 GOTO _l0_main # branch to head LABEL _l1_main # end label
Implementation specifics
- recursively generate code for an expression
visit(...)
when in the expression visitorexprVisitor.visit(...)
when in the statement visitor
- recursively generate code for a statement
visit(...)
while in the statement visitor
- generate a fresh temp variable
currentfunc.freshTemp()
- generate a fresh label
currentfunc.freshLabel()
- emit an intermediate code op
currentfunc.add(new TAC(TAC.OP..., ...))
Compiler project
Implement the code generator for SimpleC according to the operational semantics and informal language semantics discussed in class.
You may use the starter code for this project and intermediate code helper classes (TAC.java and TACFunction.java). Please develop and use your own test cases. Ask any questions about semantic decisions or details of the intermediate representation in class or in chat.
To get the repo ready, uncomment the CodeGen phase in the main driver and Makefile:
diff --git a/Compiler.java b/Compiler.java index 8ae0512..8b75d09 100644 --- a/Compiler.java +++ b/Compiler.java @@ -26,9 +26,10 @@ public class Compiler { TypeChecker typechecker = new TypeChecker(); typechecker.visit(tree); - // // Phase 3: Intermediate code gen. - // CodeGen codegen = new CodeGen(); - // codegen.visit(tree); + // Phase 3: Intermediate code gen. + CodeGen codegen = new CodeGen(); + codegen.visit(tree); + System.err.println(codegen.functionlist); // // Phase 4: Machine-independent optimization. diff --git a/Makefile b/Makefile index bb418b2..4b4bdab 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ SOURCE := \ SimpleCParser.java \ Compiler.java \ TypeChecker.java \ - # TAC.java \ - # TACFunction.java \ - # CodeGen.java \ + TAC.java \ + TACFunction.java \ + CodeGen.java \ # ASMGen.java
Submission
Push the complete code generator to the main branch of your github repository. Be sure that it builds with make
from the root directory and can be run with java Compiler program.simplec
.
Grading
The intermediate code is written by the driver to stderr, which will be used to evaluate your code gen output, e.g., the input program
main() { return 1; }
should, somewhere in the output (other output is okay, as long as the intermediate code is there), be
[main CONST _t0 1 ASSIGN true _t0 CONST _t1 0 ASSIGN false _t1 CONST _t2 1 RETURN _t2 ]
Grading will use several new programs to ensure that the code generator is handling all SimpleC constructs.