- The compiler must preserve the meaning of the program being compiled.
- The compiler must improve the input program in some discenible way.
Source program --> Front End --> IR --> Optimization --> Back End --> Target Program
Front End:
- focuses on understanding the source-language program.
- translate source program to IR.
- Scanner-->Parser-->Elaboration
- Scanner takes a stream of characters and converts it to a stream of classified words:
"a <- a x 2;" --> (var, "a"), (assign_op, "<-"), (var, "a"), (mult_op, "x"), (const, "2"), (endmark, ";") - Parsing is the process of automatically finding derivations:
- derivation rules:
- assignment sentence -> lhs assign_op rhs
- rhs -> var
- assign_op -> assign_op
- lhs -> var
- lhs -> var rest
- rest -> op var
- rest -> op rest
- op -> mult_op, add_op, sub_op, div_op ...
- derivate step:
- rhs assign_op rhs
- var assign_op rhs
- var assign_op var rest
- var assign_op var op var
- var assign_op var mult_op var
- derivation rules:
Optimization:
- analysis determines where the compiler can safely and profitably apply the technique.
- rewrite code into more efficient form.
Back End:
- foucuses on mapping IR to the target machine instruction set.
- in this phase we assume IR contains no syntactic or semantic errors.
- Inst Selection-->Inst Scheduling-->Reg Allocation(all based on IR)
- ILOC for a <- a x 2:
loadAI Rarp, @a => Ra // load 'a'
loadI 2 => R2 // const 2 into 2
mult Ra, R2 => Ra // Ra <- a x 2
storeAI Ra => Rarp, @a // write Ra back to 'a' - Inst Selection:
mult Ra, R2 => Ra --> add Ra, Ra => Ra - Inst Scheduling, try to find minimize the number of cycles for procedures
IR (TBD: use module in systemverilog as an example):
- include self-instance
- include child instance instantiate in this module (use this to build our instance tree)
- include xmr list
- include other features (initial/always block, node, assertion...)