What?

  • Converts the AST into Internal Representation (IR) Graph, which is fed into the Compiler Backend.
  • There’s a fundamental problem with the AST. It doesn’t actually denote the order of which the code occurs (control-flow or data-flow). The IR helps that problem

What is the IR Graph?

Basically, we take an AST, and then convert it into English-like MIPS. So we go from:

IfStatement
├── Condition: BinaryOp('>', Var(x), IntLiteral(10))
├── ThenBranch: Assignment(Var(y), BinaryOp('+', Var(x), IntLiteral(5)))
└── ElseBranch: Assignment(Var(y), IntLiteral(20))

To:

block0:
    t1 = load x
    t2 = t1 > 10
    branch_if t2 block1 block2
 
block1:   // then branch
    t3 = t1 + 5
    store y, t3
    jump block3
 
block2:   // else branch
    store y, 20
    jump block3
 
block3:   // join point
    // continue execution

This then get’s converted into a graph:

The Details:

  • Mutations are problematic. When optimising our IR, we actually rename our variables (e.g. x, which changed) to something that is only used once.
    • This is called Static Single Assignment - when each variable is a target of exactly one assignment.