UP | HOME

Intermediate code generation
Lecture 16

Table of Contents

Code generation

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 visitor
    • exprVisitor.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.

Author: Paul Gazzillo

Created: 2022-03-21 Mon 13:50