Skip to content

Compiler

varkenvarken edited this page Feb 10, 2020 · 10 revisions

The current state of the compiler

compiler.py parses all of the c99 standard (no big deal because of the fantastic Pycparser package)

Basically all we have to focus on is code generation. It generates assembly code that can be parsed by the assembler

We focus on code generation first so we can test the robin cpu/soc we some realistic bits of code. The flip side is that we hardly do any semantic checking. For now it is perfectly acceptable to pass a char* to a function expecting an int for example

Currently working on

  • all sort of bugs in the code generation that pop up while implementing a soft float library

Next

  • switch statements, including labels.

Already working

  • function declarations and function definitions work.
  • Expressions that support most binary and unary arithmetical and logical operations including function calls and dereferencing and also the conditional operator ( ?: )
  • bitwise shift operators (<< >>)
  • compound assignments (+= -= ...) mostly implemented except for &&= ||=
  • while loops, do/while loops, for statements and if/else statements are implemented as is the comma operator
  • break or continue statements
  • automatic variables of type int and char are supported as well as pointers. int and char variables can have initializers
  • global variables of type int and char are supported as well as pointers. int and char variables can have initializers as can char* variables

Additional features

  • address of operator (&)
  • float
  • explicit casts

Will probably not be implemented

  • goto statement. Will certainly not be implemented.
  • struct?
  • union?
  • bitfields
  • typedef?
  • sizeof?

Optimization ideas

Already it is clear that the code generated by the compiler is quite bloated. Some easy to implement optimizations my help to reduce this, like

dealing with constants on the right hand side of a binary operation

Currently an expression like a & 0x0f generates code like this:

    move    r2,r10,0            ; load a
    push    r2                  ; binop(&)
    loadl   r2,#0x0f            ; int
    pop     r3                  ; binop(&)
    load    flags,#alu_and      ; binop(&)
    alu     r2,r3,r2

The reason for this is that code should be executed left to right and that both sides of a binary operation can be arbitrarily complex expressions in themselves. If the right hand side is a constant and the binary operation is commutative, it should be possible to make this far less complex.