120
Compilers and computer architecture: A realistic compiler to RISC-V Martin Berger 1 November / December 2019 1 Email: [email protected], Office hours: Wed 12-13 in Chi-2R312 1/1

Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

  • Upload
    others

  • View
    20

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compilers and computer architecture:A realistic compiler to RISC-V

Martin Berger 1

November / December 2019

1Email: [email protected], Office hours: Wed 12-13 inChi-2R312

1 / 1

Page 2: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Recall the function of compilers

2 / 1

Page 3: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Recall the structure of compilers

Lexical analysis

Syntax analysis

Source program

Semantic analysis,e.g. type checking

Intermediate code generation

Optimisation

Code generation

Translated program

3 / 1

Page 4: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Introduction

Now we look at more realistic code generation. In the previoustwo lectures we investigated key issues in compilation for morerealistic source and target languages, such as procedures andmemory alignment. We also introduced the RISC-Varchitecture, which has an especially clean instruction setarchitecture, and the ’new hotness’ on the CPU block.

4 / 1

Page 5: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Source languageSource is a simple imperative language with integers as soledata type and recursive procedures with arguments.

P → D;P | DD → def ID (A) = EA → Ane | εAne → ID,Ane | IDE → INT | ID | if E = E then E else E

| E + E | E − E | ID(EA) | ID := EEA → ε | EAneEAne → E | E ,EAne

Here ID ranges over identifiers, INT over integers.

Firstdeclared procedure is entry point (i.e. will be executed whenthe program is run) and must take 0 arguments. Procedurenames must be distinct, and distinct from all variable names. Allvariable names in a declaration are distinct.We assume that the program passed semantic analysis.

5 / 1

Page 6: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Source languageSource is a simple imperative language with integers as soledata type and recursive procedures with arguments.

P → D;P | DD → def ID (A) = EA → Ane | εAne → ID,Ane | IDE → INT | ID | if E = E then E else E

| E + E | E − E | ID(EA) | ID := EEA → ε | EAneEAne → E | E ,EAne

Here ID ranges over identifiers, INT over integers. Firstdeclared procedure is entry point (i.e. will be executed whenthe program is run) and must take 0 arguments. Procedurenames must be distinct, and distinct from all variable names. Allvariable names in a declaration are distinct.

We assume that the program passed semantic analysis.

6 / 1

Page 7: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Source languageSource is a simple imperative language with integers as soledata type and recursive procedures with arguments.

P → D;P | DD → def ID (A) = EA → Ane | εAne → ID,Ane | IDE → INT | ID | if E = E then E else E

| E + E | E − E | ID(EA) | ID := EEA → ε | EAneEAne → E | E ,EAne

Here ID ranges over identifiers, INT over integers. Firstdeclared procedure is entry point (i.e. will be executed whenthe program is run) and must take 0 arguments. Procedurenames must be distinct, and distinct from all variable names. Allvariable names in a declaration are distinct.We assume that the program passed semantic analysis.

7 / 1

Page 8: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Example program

def myFirstProg () = fib ( 3 );

def fib ( n ) =if n = 0 then

1else if n = 1 then

1else

fib ( n-1 ) + fib ( n-2 )

8 / 1

Page 9: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

We use RISC-V as an accumulator machine. So we are usingonly a tiny fraction of RISC-V’s power. This is to keep thecompiler easy.

Recall that in an accumulator machine all operations:I the first argument is assumed to be in the accumulator;I all remaining arguments sit on the (top of the) stack;I the result of the operation is stored in the accumulator;I after finishing the operation, all arguments are removed

from the stack.The code generator we will be presenting guarantees that allthese assumptions always hold.

9 / 1

Page 10: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

We use RISC-V as an accumulator machine. So we are usingonly a tiny fraction of RISC-V’s power. This is to keep thecompiler easy.

Recall that in an accumulator machine all operations:

I the first argument is assumed to be in the accumulator;I all remaining arguments sit on the (top of the) stack;I the result of the operation is stored in the accumulator;I after finishing the operation, all arguments are removed

from the stack.The code generator we will be presenting guarantees that allthese assumptions always hold.

10 / 1

Page 11: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

We use RISC-V as an accumulator machine. So we are usingonly a tiny fraction of RISC-V’s power. This is to keep thecompiler easy.

Recall that in an accumulator machine all operations:I the first argument is assumed to be in the accumulator;

I all remaining arguments sit on the (top of the) stack;I the result of the operation is stored in the accumulator;I after finishing the operation, all arguments are removed

from the stack.The code generator we will be presenting guarantees that allthese assumptions always hold.

11 / 1

Page 12: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

We use RISC-V as an accumulator machine. So we are usingonly a tiny fraction of RISC-V’s power. This is to keep thecompiler easy.

Recall that in an accumulator machine all operations:I the first argument is assumed to be in the accumulator;I all remaining arguments sit on the (top of the) stack;

I the result of the operation is stored in the accumulator;I after finishing the operation, all arguments are removed

from the stack.The code generator we will be presenting guarantees that allthese assumptions always hold.

12 / 1

Page 13: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

We use RISC-V as an accumulator machine. So we are usingonly a tiny fraction of RISC-V’s power. This is to keep thecompiler easy.

Recall that in an accumulator machine all operations:I the first argument is assumed to be in the accumulator;I all remaining arguments sit on the (top of the) stack;I the result of the operation is stored in the accumulator;

I after finishing the operation, all arguments are removedfrom the stack.

The code generator we will be presenting guarantees that allthese assumptions always hold.

13 / 1

Page 14: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

We use RISC-V as an accumulator machine. So we are usingonly a tiny fraction of RISC-V’s power. This is to keep thecompiler easy.

Recall that in an accumulator machine all operations:I the first argument is assumed to be in the accumulator;I all remaining arguments sit on the (top of the) stack;I the result of the operation is stored in the accumulator;I after finishing the operation, all arguments are removed

from the stack.The code generator we will be presenting guarantees that allthese assumptions always hold.

14 / 1

Page 15: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

To use RISC-V as an accumulator machine we need to decidewhat registers to use as stack pointer and accumulator.We make the following assumptions (which are in line with theassumptions the RISC-V community makes, see previouslecture slides).

I We use the general purpose register a0 as accumulator.I We use the general purpose register sp as stack pointer.I The stack pointer always points to the first free byte above

the stack.I The stack grows downwards.

We could have made other choices.

15 / 1

Page 16: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

To use RISC-V as an accumulator machine we need to decidewhat registers to use as stack pointer and accumulator.We make the following assumptions (which are in line with theassumptions the RISC-V community makes, see previouslecture slides).

I We use the general purpose register a0 as accumulator.

I We use the general purpose register sp as stack pointer.I The stack pointer always points to the first free byte above

the stack.I The stack grows downwards.

We could have made other choices.

16 / 1

Page 17: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

To use RISC-V as an accumulator machine we need to decidewhat registers to use as stack pointer and accumulator.We make the following assumptions (which are in line with theassumptions the RISC-V community makes, see previouslecture slides).

I We use the general purpose register a0 as accumulator.I We use the general purpose register sp as stack pointer.

I The stack pointer always points to the first free byte abovethe stack.

I The stack grows downwards.

We could have made other choices.

17 / 1

Page 18: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

To use RISC-V as an accumulator machine we need to decidewhat registers to use as stack pointer and accumulator.We make the following assumptions (which are in line with theassumptions the RISC-V community makes, see previouslecture slides).

I We use the general purpose register a0 as accumulator.I We use the general purpose register sp as stack pointer.I The stack pointer always points to the first free byte above

the stack.

I The stack grows downwards.

We could have made other choices.

18 / 1

Page 19: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

To use RISC-V as an accumulator machine we need to decidewhat registers to use as stack pointer and accumulator.We make the following assumptions (which are in line with theassumptions the RISC-V community makes, see previouslecture slides).

I We use the general purpose register a0 as accumulator.I We use the general purpose register sp as stack pointer.I The stack pointer always points to the first free byte above

the stack.I The stack grows downwards.

We could have made other choices.

19 / 1

Page 20: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Generating code for the language

To use RISC-V as an accumulator machine we need to decidewhat registers to use as stack pointer and accumulator.We make the following assumptions (which are in line with theassumptions the RISC-V community makes, see previouslecture slides).

I We use the general purpose register a0 as accumulator.I We use the general purpose register sp as stack pointer.I The stack pointer always points to the first free byte above

the stack.I The stack grows downwards.

We could have made other choices.

20 / 1

Page 21: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Assumption about data types

Our source language has integers.

We will translate them to the built-in (signed) 32 bit RISC-Vinteger data-type.

Other choices are possible (e.g. 64 bits, infinite precision, 16 bitetc). This one is by far the simplest.

For simplicity, we won’t worry about over/underflow ofarithmetic operations.

21 / 1

Page 22: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Assumption about data types

Our source language has integers.

We will translate them to the built-in (signed) 32 bit RISC-Vinteger data-type.

Other choices are possible (e.g. 64 bits, infinite precision, 16 bitetc). This one is by far the simplest.

For simplicity, we won’t worry about over/underflow ofarithmetic operations.

22 / 1

Page 23: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Assumption about data types

Our source language has integers.

We will translate them to the built-in (signed) 32 bit RISC-Vinteger data-type.

Other choices are possible (e.g. 64 bits, infinite precision, 16 bitetc). This one is by far the simplest.

For simplicity, we won’t worry about over/underflow ofarithmetic operations.

23 / 1

Page 24: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Assumption about data types

Our source language has integers.

We will translate them to the built-in (signed) 32 bit RISC-Vinteger data-type.

Other choices are possible (e.g. 64 bits, infinite precision, 16 bitetc). This one is by far the simplest.

For simplicity, we won’t worry about over/underflow ofarithmetic operations.

24 / 1

Page 25: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation

Let’s start easy and generate code expressions.

For simplicity we’ll ignore some issues like placing alignmentcommands.

As with the translation to an idealised accumulator machine afew weeks ago, we compile expressions by recursively walkingthe AST. We want to write the following:

def genExp ( e : Exp ) =if e is of form

IntLiteral ( n ) then ...Variable ( x ) then ...If ( cond , thenBody, elseBody ) then ...Add ( l, r ) then ...Sub ( l, r ) then ...Call ( f, args ) then ... } }

25 / 1

Page 26: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation

Let’s start easy and generate code expressions.

For simplicity we’ll ignore some issues like placing alignmentcommands.

As with the translation to an idealised accumulator machine afew weeks ago, we compile expressions by recursively walkingthe AST. We want to write the following:

def genExp ( e : Exp ) =if e is of form

IntLiteral ( n ) then ...Variable ( x ) then ...If ( cond , thenBody, elseBody ) then ...Add ( l, r ) then ...Sub ( l, r ) then ...Call ( f, args ) then ... } }

26 / 1

Page 27: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation

Let’s start easy and generate code expressions.

For simplicity we’ll ignore some issues like placing alignmentcommands.

As with the translation to an idealised accumulator machine afew weeks ago, we compile expressions by recursively walkingthe AST. We want to write the following:

def genExp ( e : Exp ) =if e is of form

IntLiteral ( n ) then ...Variable ( x ) then ...If ( cond , thenBody, elseBody ) then ...Add ( l, r ) then ...Sub ( l, r ) then ...Call ( f, args ) then ... } }

27 / 1

Page 28: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: integer literals

Let’s start with the simplest case.

def genExp ( e : Exp ) =if e is of form

IntLiteral ( n ) thenli a0 n

Convention: code in red is RISC-V code to be executed atrun-time. Code in black is compiler code. We are also goingto be a bit sloppy about the datatype RISC-V_I of RISC-Vinstructions.

This preserves all invariants to do with the stack and theaccumulator as required. Recall that li is a pseudo instructionand will be expanded by the assembler into several real RISC-Vinstructions.

28 / 1

Page 29: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: integer literals

Let’s start with the simplest case.

def genExp ( e : Exp ) =if e is of form

IntLiteral ( n ) thenli a0 n

Convention: code in red is RISC-V code to be executed atrun-time. Code in black is compiler code. We are also goingto be a bit sloppy about the datatype RISC-V_I of RISC-Vinstructions.

This preserves all invariants to do with the stack and theaccumulator as required. Recall that li is a pseudo instructionand will be expanded by the assembler into several real RISC-Vinstructions.

29 / 1

Page 30: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: integer literals

Let’s start with the simplest case.

def genExp ( e : Exp ) =if e is of form

IntLiteral ( n ) thenli a0 n

Convention: code in red is RISC-V code to be executed atrun-time. Code in black is compiler code. We are also goingto be a bit sloppy about the datatype RISC-V_I of RISC-Vinstructions.

This preserves all invariants to do with the stack and theaccumulator as required. Recall that li is a pseudo instructionand will be expanded by the assembler into several real RISC-Vinstructions.

30 / 1

Page 31: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: addition

def genExp ( e : Exp ) =if e is of form

Add ( l, r ) thengenExp ( l )sw a0 0(sp)addi sp sp -4genExp ( r )lw t1 4(sp)add a0 t1 a0addi sp sp 4

Note that this evaluates from left to right! Recall also that thestack grows downwards and that the stack pointer points to thefirst free memory cell above the stack.

Question: Why not store the result of compiling the leftargument directly in t1? Consider 1+(2+3)

31 / 1

Page 32: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: addition

def genExp ( e : Exp ) =if e is of form

Add ( l, r ) thengenExp ( l )sw a0 0(sp)addi sp sp -4genExp ( r )lw t1 4(sp)add a0 t1 a0addi sp sp 4

Note that this evaluates from left to right! Recall also that thestack grows downwards and that the stack pointer points to thefirst free memory cell above the stack.

Question: Why not store the result of compiling the leftargument directly in t1?

Consider 1+(2+3)

32 / 1

Page 33: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: addition

def genExp ( e : Exp ) =if e is of form

Add ( l, r ) thengenExp ( l )sw a0 0(sp)addi sp sp -4genExp ( r )lw t1 4(sp)add a0 t1 a0addi sp sp 4

Note that this evaluates from left to right! Recall also that thestack grows downwards and that the stack pointer points to thefirst free memory cell above the stack.

Question: Why not store the result of compiling the leftargument directly in t1? Consider 1+(2+3)

33 / 1

Page 34: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: minus

We want to translate e − e′. We need new RISC-V command:

sub reg1 reg2 reg3

It subtracts the content of reg3 from the content of reg2 andstores the result in reg1. I.e. reg1 := reg2 - reg3.

34 / 1

Page 35: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: minus

def genExp ( e : Exp ) =if e is of form

Minus ( l, r ) thengenExp ( l )sw a0 0 spaddi sp sp -4genExp ( r )lw t1 4(sp)sub a0 t1 a0 // only change from additionaddi sp sp 4

Note that sub a0 t1 a0 deducts a0 from t1.

35 / 1

Page 36: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: conditional

We want to translate if e1 = e2 then e else e′. We need twonew RISC-V commands:

beq reg1 reg2 label

b label

beq branches (= jumps) to label if the content of reg1 isidentical to the content of reg2. Otherwise it does nothing andmoves on to the next command.

In contrast b makes an unconditional jump to label.

36 / 1

Page 37: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: conditional

We want to translate if e1 = e2 then e else e′. We need twonew RISC-V commands:

beq reg1 reg2 label

b label

beq branches (= jumps) to label if the content of reg1 isidentical to the content of reg2. Otherwise it does nothing andmoves on to the next command.

In contrast b makes an unconditional jump to label.

37 / 1

Page 38: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: conditionaldef genExp ( e : Exp ) =

if e is of formIf ( l, r, thenBody, elseBody ) then

val elseBranch = newLabel () // not neededval thenBranch = newLabel ()val exitLabel = newLabel ()

genExp ( l )sw a0 0(sp)addi sp sp -4genExp ( r )lw t1 4(sp)addi sp sp 4beq a0 t1 thenBranch

elseBranch + ":"genExp ( elseBody )b exitLabel

thenBranch + ":"genExp ( thenBody )

exitLabel + ":" }

newLabel returns new, distinct string every time it is called.

38 / 1

Page 39: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: conditionaldef genExp ( e : Exp ) =

if e is of formIf ( l, r, thenBody, elseBody ) then

val elseBranch = newLabel () // not neededval thenBranch = newLabel ()val exitLabel = newLabel ()

genExp ( l )sw a0 0(sp)addi sp sp -4genExp ( r )lw t1 4(sp)addi sp sp 4beq a0 t1 thenBranch

elseBranch + ":"genExp ( elseBody )b exitLabel

thenBranch + ":"genExp ( thenBody )

exitLabel + ":" }

newLabel returns new, distinct string every time it is called. 39 / 1

Page 40: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

The code a compiler emits for procedurecalls and declarations depends on thelayout of the activation record (AR).

The AR stores all the data that’s neededto execute an invocation of a procedure.

ARs are held on the stack, becauseprocedure entries and exits are adhereto a bracketing discipline.

Note that invocation result and (some)procedure arguments are often passedin register not in AR (for efficiency)

Result

Argument: 3

Return address

Result

Argument: 2

Return address

Main's AR

f( 3 )

f( 2 )

main

40 / 1

Page 41: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

The code a compiler emits for procedurecalls and declarations depends on thelayout of the activation record (AR).

The AR stores all the data that’s neededto execute an invocation of a procedure.

ARs are held on the stack, becauseprocedure entries and exits are adhereto a bracketing discipline.

Note that invocation result and (some)procedure arguments are often passedin register not in AR (for efficiency)

Result

Argument: 3

Return address

Result

Argument: 2

Return address

Main's AR

f( 3 )

f( 2 )

main

41 / 1

Page 42: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

The code a compiler emits for procedurecalls and declarations depends on thelayout of the activation record (AR).

The AR stores all the data that’s neededto execute an invocation of a procedure.

ARs are held on the stack, becauseprocedure entries and exits are adhereto a bracketing discipline.

Note that invocation result and (some)procedure arguments are often passedin register not in AR (for efficiency)

Result

Argument: 3

Return address

Result

Argument: 2

Return address

Main's AR

f( 3 )

f( 2 )

main

42 / 1

Page 43: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

The code a compiler emits for procedurecalls and declarations depends on thelayout of the activation record (AR).

The AR stores all the data that’s neededto execute an invocation of a procedure.

ARs are held on the stack, becauseprocedure entries and exits are adhereto a bracketing discipline.

Note that invocation result and (some)procedure arguments are often passedin register not in AR (for efficiency)

Result

Argument: 3

Return address

Result

Argument: 2

Return address

Main's AR

f( 3 )

f( 2 )

main

43 / 1

Page 44: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR!

What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

44 / 1

Page 45: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

45 / 1

Page 46: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

46 / 1

Page 47: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

47 / 1

Page 48: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

48 / 1

Page 49: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

49 / 1

Page 50: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why?

Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

50 / 1

Page 51: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

Let’s design an AR! What assumptions can we make?

The result is always in the accumulator, so no need for to storethe result in the AR.

The only variables in the language are procedure parameters.We hold them in AR: for the procedure call f(e1, ...,en) justpush the result of evaluating e1, ...,en onto the stack.

The AR needs to store the return address.

The stack calling discipline ensures that on invocation exit sp isthe same as on invocation entry.

Also: no registers need to be preserved in accumulatormachines. Why? Because no register is used except for theaccumulator and t1, and when a procedure is invoked, allprevious evaluations of expressions are already discharged or’tucked away’ on the stack.

51 / 1

Page 52: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

So ARs for a procedure with n arguments look like this:

caller’s FPargument n...argument 1return address

A pointer to the top of current AR (i.e. where the returnaddress sits) is useful (though not necessary) see later. Thispointer is called frame pointer and lives in register fp. Weneed to restore the caller’s FP on procedure exit, so we store itin the AR upon procedure entry. The FP makes accessingvariables easier (see later).

Arguments are stored in reverse order to make indexing a biteasier.

52 / 1

Page 53: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

So ARs for a procedure with n arguments look like this:

caller’s FPargument n...argument 1return address

A pointer to the top of current AR (i.e. where the returnaddress sits) is useful (though not necessary) see later. Thispointer is called frame pointer and lives in register fp. Weneed to restore the caller’s FP on procedure exit, so we store itin the AR upon procedure entry. The FP makes accessingvariables easier (see later).

Arguments are stored in reverse order to make indexing a biteasier.

53 / 1

Page 54: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarationsLet’s look at an example: assume we call f (7,100,33)

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

FP

SP

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

Return addressFP

SP

Callee's responsibility

Caller's responsibility

Jump

54 / 1

Page 55: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

To be able to get the return addess for a procedure call easily,we need a new RISC-V instruction:

jal label

Note that jal stands for jump and link. This instruction doesthe following:

Jumps unconditionally to label, stores the address of nextinstruction (syntactically following jal label) in register ra.

On many other architectures, the return address isautomatically placed on the stack by a call instruction.

On RISC-V we must push the return address on stack explicitly.This can only be done by callee, because address is availableonly after jal has executed.

55 / 1

Page 56: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

To be able to get the return addess for a procedure call easily,we need a new RISC-V instruction:

jal label

Note that jal stands for jump and link. This instruction doesthe following:

Jumps unconditionally to label, stores the address of nextinstruction (syntactically following jal label) in register ra.

On many other architectures, the return address isautomatically placed on the stack by a call instruction.

On RISC-V we must push the return address on stack explicitly.This can only be done by callee, because address is availableonly after jal has executed.

56 / 1

Page 57: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

To be able to get the return addess for a procedure call easily,we need a new RISC-V instruction:

jal label

Note that jal stands for jump and link. This instruction doesthe following:

Jumps unconditionally to label, stores the address of nextinstruction (syntactically following jal label) in register ra.

On many other architectures, the return address isautomatically placed on the stack by a call instruction.

On RISC-V we must push the return address on stack explicitly.This can only be done by callee, because address is availableonly after jal has executed.

57 / 1

Page 58: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls/declarations

To be able to get the return addess for a procedure call easily,we need a new RISC-V instruction:

jal label

Note that jal stands for jump and link. This instruction doesthe following:

Jumps unconditionally to label, stores the address of nextinstruction (syntactically following jal label) in register ra.

On many other architectures, the return address isautomatically placed on the stack by a call instruction.

On RISC-V we must push the return address on stack explicitly.This can only be done by callee, because address is availableonly after jal has executed.

58 / 1

Page 59: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls

Example of procedure call with 3 arguments. General case issimilar.

case Call ( f, List ( e1, e2, e3 ) ) thensw fp 0(sp) // save FP on stackaddi sp sp -4genExp ( e3 ) // we choose right-to-left ev. ordersw a0 0(sp) // save 3rd argument on stackaddi sp sp -4genExp ( e2 )sw a0 0(sp) // save 2nd argument on stackaddi sp sp -4genExp ( e1 )sw a0 0(sp) // save 1st argument on stackaddi sp sp -4jal ( f + "_entry" ) // jump to f, save return

// addr in ra

59 / 1

Page 60: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls

Example of procedure call with 3 arguments. General case issimilar.

case Call ( f, List ( e1, e2, e3 ) ) thensw fp 0(sp) // save FP on stackaddi sp sp -4genExp ( e3 ) // we choose right-to-left ev. ordersw a0 0(sp) // save 3rd argument on stackaddi sp sp -4genExp ( e2 )sw a0 0(sp) // save 2nd argument on stackaddi sp sp -4genExp ( e1 )sw a0 0(sp) // save 1st argument on stackaddi sp sp -4jal ( f + "_entry" ) // jump to f, save return

// addr in ra

60 / 1

Page 61: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR? For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

61 / 1

Page 62: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR? For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

62 / 1

Page 63: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR? For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

63 / 1

Page 64: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR? For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

64 / 1

Page 65: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR?

For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

65 / 1

Page 66: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR? For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

66 / 1

Page 67: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSeveral things are worth noting.

I The caller first saves the FP (i.e. pointer to top of its ownAR).

I Then the caller saves procedure parameters in reverseorder (right-to-left).

I Implicitly the caller saves the return address in ra byexecuting jal. The return address is still not in the AR onthe stack. The AR is incomplete. Completion is the callee’sresponsibility.

I How big is the AR? For a procedure with n arguments theAR (without return address) is 4 + 4 ∗ n = 4(n + 2) byteslong. This is know at compile time and is important forthe compilation of procedure bodies.

I The translation of procedure invocations is generic in thenumber of procedure arguments, nothing particular about3.

67 / 1

Page 68: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure callsSo far we perfectly adhere to the lhs of this picture (except 33,100, 7).

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

FP

SP

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

Return addressFP

SP

Callee's responsibility

Caller's responsibility

Jump

68 / 1

Page 69: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

In order to compile a declaration d like

def f ( x1, ..., xn ) = body

we use a procedure for compiling declarations like so:

def genDecl ( d ) = ...

69 / 1

Page 70: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

We need two new RISC-V instructions:

jr reg

mv reg reg’

The former (jr reg) jumps to the address stored in registerreg.

The latter (mv reg reg’) copies the content of register reg’into the register reg.

70 / 1

Page 71: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

We need two new RISC-V instructions:

jr reg

mv reg reg’

The former (jr reg) jumps to the address stored in registerreg.

The latter (mv reg reg’) copies the content of register reg’into the register reg.

71 / 1

Page 72: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

We need two new RISC-V instructions:

jr reg

mv reg reg’

The former (jr reg) jumps to the address stored in registerreg.

The latter (mv reg reg’) copies the content of register reg’into the register reg.

72 / 1

Page 73: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

We need two new RISC-V instructions:

jr reg

mv reg reg’

The former (jr reg) jumps to the address stored in registerreg.

The latter (mv reg reg’) copies the content of register reg’into the register reg.

73 / 1

Page 74: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

def genDecl ( d : Declaration ) =val sizeAR = ( 2 + d.args.size ) * 4

// each procedure argument takes 4 bytes,// in addition the AR stores the return// address and old FP

d.id + "_entry:" // label to jump tomv fp sp // FP points to top of current ARsw ra 0(sp) // put return address on stackaddi sp sp -4 // now AR is fully createdgenExp ( d.body )lw ra 4(sp) // load return address into ra

// could also use fpaddi sp sp sizeAR // pop AR off stack in one golw fp 0(sp) // restore old FPjr ra // hand back control to caller

74 / 1

Page 75: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

On entry

FP

SP

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

Return address

On exit

FP

SP

Caller's AR

Before call

FP

Caller's AR

After call

SP SP

FP

So we preserve the invariant that the stack looks exactly thesame before and after a procedure call!

75 / 1

Page 76: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: procedure calls, callee’s side

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

On entry

FP

SP

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

Return address

On exit

FP

SP

Caller's AR

Before call

FP

Caller's AR

After call

SP SP

FP

So we preserve the invariant that the stack looks exactly thesame before and after a procedure call!

76 / 1

Page 77: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution: Use frame pointer fp.I Always points to the top of current AR as long as

invocation is active.I The FP does not (appear to) move, so we can find all

variables at a fixed offset from fp.

77 / 1

Page 78: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution: Use frame pointer fp.I Always points to the top of current AR as long as

invocation is active.I The FP does not (appear to) move, so we can find all

variables at a fixed offset from fp.

78 / 1

Page 79: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution: Use frame pointer fp.I Always points to the top of current AR as long as

invocation is active.I The FP does not (appear to) move, so we can find all

variables at a fixed offset from fp.

79 / 1

Page 80: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution:

Use frame pointer fp.I Always points to the top of current AR as long as

invocation is active.I The FP does not (appear to) move, so we can find all

variables at a fixed offset from fp.

80 / 1

Page 81: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution: Use frame pointer fp.

I Always points to the top of current AR as long asinvocation is active.

I The FP does not (appear to) move, so we can find allvariables at a fixed offset from fp.

81 / 1

Page 82: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution: Use frame pointer fp.I Always points to the top of current AR as long as

invocation is active.

I The FP does not (appear to) move, so we can find allvariables at a fixed offset from fp.

82 / 1

Page 83: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: frame pointerVariables are just the procedure parameters in this language.

They are all on the stack in the AR, pushed by the caller. Howdo we access them? The obvious solution (use the SP withappropriate offset) does not work (at least not easily).

Problem: The stack grows and shrinks when intermediateresults are computed (in the accumulator machine approach),so the variables are not on a fixed offset from sp. For examplein

def f ( x, y, z ) = x + ( ( x * z ) + ( y - y ) )

Solution: Use frame pointer fp.I Always points to the top of current AR as long as

invocation is active.I The FP does not (appear to) move, so we can find all

variables at a fixed offset from fp.83 / 1

Page 84: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: variable use

Let’s compile xi which is the i-th (starting to count from 1)parameter of def f(x1, x2, ..., xn) = body works likethis (using offset in AR):

def genExp ( e : Exp ) =if e is of form Variable ( xi ) then

val offset = 4*ilw a0 offset(fp)

Putting the arguments in reverse order on the stack makes theoffseting calculation val offset = 4*i a tiny bit easier.

Key insight: access at fixed offset relative to a dynamicallychanging pointer. Offset and pointer location are known atcompile time.

This idea is pervasive in compilation.

84 / 1

Page 85: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: variable use

Let’s compile xi which is the i-th (starting to count from 1)parameter of def f(x1, x2, ..., xn) = body works likethis (using offset in AR):

def genExp ( e : Exp ) =if e is of form Variable ( xi ) then

val offset = 4*ilw a0 offset(fp)

Putting the arguments in reverse order on the stack makes theoffseting calculation val offset = 4*i a tiny bit easier.

Key insight: access at fixed offset relative to a dynamicallychanging pointer. Offset and pointer location are known atcompile time.

This idea is pervasive in compilation.

85 / 1

Page 86: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: variable use

Let’s compile xi which is the i-th (starting to count from 1)parameter of def f(x1, x2, ..., xn) = body works likethis (using offset in AR):

def genExp ( e : Exp ) =if e is of form Variable ( xi ) then

val offset = 4*ilw a0 offset(fp)

Putting the arguments in reverse order on the stack makes theoffseting calculation val offset = 4*i a tiny bit easier.

Key insight: access at fixed offset relative to a dynamicallychanging pointer. Offset and pointer location are known atcompile time.

This idea is pervasive in compilation.

86 / 1

Page 87: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: variable use

Caller's FP

Third argument: 33

Second argument: 100

First argument: 7

Caller's AR

Return addressFP

In the declaration def f (x, y,z) = ..., we have:

I x is at address fp + 4

I y is at address fp + 8

I z is at address fp + 12

Note that this work becauseindexing begins at 1 in this case,and arguments are pushed onstack from right to left.

87 / 1

Page 88: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Translation of variable assignmentGiven that we know now that reading a variable is translated as

if e is of form Variable ( xi ) thenval offset = 4*ilw a0 offset(fp)

How would you translate an assignment

xi := e

Since xi is the i-th (starting to count from 1) formal parameterof the ambient procedure declaration, we can simply do:

def genExp ( exp : Exp ) =if exp is of form Assign ( xi, e ) then

val offset = 4*igenExp ( e )sw a0 offset(fp)

Easy!

88 / 1

Page 89: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Translation of variable assignmentGiven that we know now that reading a variable is translated as

if e is of form Variable ( xi ) thenval offset = 4*ilw a0 offset(fp)

How would you translate an assignment

xi := e

Since xi is the i-th (starting to count from 1) formal parameterof the ambient procedure declaration, we can simply do:

def genExp ( exp : Exp ) =if exp is of form Assign ( xi, e ) then

val offset = 4*igenExp ( e )sw a0 offset(fp)

Easy!

89 / 1

Page 90: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Translation of variable assignmentGiven that we know now that reading a variable is translated as

if e is of form Variable ( xi ) thenval offset = 4*ilw a0 offset(fp)

How would you translate an assignment

xi := e

Since xi is the i-th (starting to count from 1) formal parameterof the ambient procedure declaration, we can simply do:

def genExp ( exp : Exp ) =if exp is of form Assign ( xi, e ) then

val offset = 4*igenExp ( e )sw a0 offset(fp)

Easy!

90 / 1

Page 91: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Translation of variable assignmentGiven that we know now that reading a variable is translated as

if e is of form Variable ( xi ) thenval offset = 4*ilw a0 offset(fp)

How would you translate an assignment

xi := e

Since xi is the i-th (starting to count from 1) formal parameterof the ambient procedure declaration, we can simply do:

def genExp ( exp : Exp ) =if exp is of form Assign ( xi, e ) then

val offset = 4*igenExp ( e )sw a0 offset(fp)

Easy!

91 / 1

Page 92: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

92 / 1

Page 93: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: summary remarksThe code of variable access, procedure calls and declarationsdepends totally on the layout of the AR, so the AR must bedesigned together with the code generator, and all parts of thecode generator must agree on AR conventions. It’s just asimportant to be clear about the nature of the stack (growsupwards or downwards), frame pointer etc.

Access at fixed offset relative to dynamically changing pointer.Offset and pointer location are known at compile time.

Code and layout also depends on CPU.

Code generation happens by recursive AST walk.

Industrial strength compilers are more complicated:I Try to keep values in registers, especially the current stack

frame. E.g. compilers for RISC-V usually pass first fourprocedure arguments in registers a0 - a3.

I Intermediate values, local variables are held in registers,not on the stack.

93 / 1

Page 94: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: summary remarksThe code of variable access, procedure calls and declarationsdepends totally on the layout of the AR, so the AR must bedesigned together with the code generator, and all parts of thecode generator must agree on AR conventions. It’s just asimportant to be clear about the nature of the stack (growsupwards or downwards), frame pointer etc.

Access at fixed offset relative to dynamically changing pointer.Offset and pointer location are known at compile time.

Code and layout also depends on CPU.

Code generation happens by recursive AST walk.

Industrial strength compilers are more complicated:I Try to keep values in registers, especially the current stack

frame. E.g. compilers for RISC-V usually pass first fourprocedure arguments in registers a0 - a3.

I Intermediate values, local variables are held in registers,not on the stack.

94 / 1

Page 95: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: summary remarksThe code of variable access, procedure calls and declarationsdepends totally on the layout of the AR, so the AR must bedesigned together with the code generator, and all parts of thecode generator must agree on AR conventions. It’s just asimportant to be clear about the nature of the stack (growsupwards or downwards), frame pointer etc.

Access at fixed offset relative to dynamically changing pointer.Offset and pointer location are known at compile time.

Code and layout also depends on CPU.

Code generation happens by recursive AST walk.

Industrial strength compilers are more complicated:I Try to keep values in registers, especially the current stack

frame. E.g. compilers for RISC-V usually pass first fourprocedure arguments in registers a0 - a3.

I Intermediate values, local variables are held in registers,not on the stack.

95 / 1

Page 96: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: summary remarksThe code of variable access, procedure calls and declarationsdepends totally on the layout of the AR, so the AR must bedesigned together with the code generator, and all parts of thecode generator must agree on AR conventions. It’s just asimportant to be clear about the nature of the stack (growsupwards or downwards), frame pointer etc.

Access at fixed offset relative to dynamically changing pointer.Offset and pointer location are known at compile time.

Code and layout also depends on CPU.

Code generation happens by recursive AST walk.

Industrial strength compilers are more complicated:

I Try to keep values in registers, especially the current stackframe. E.g. compilers for RISC-V usually pass first fourprocedure arguments in registers a0 - a3.

I Intermediate values, local variables are held in registers,not on the stack.

96 / 1

Page 97: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: summary remarksThe code of variable access, procedure calls and declarationsdepends totally on the layout of the AR, so the AR must bedesigned together with the code generator, and all parts of thecode generator must agree on AR conventions. It’s just asimportant to be clear about the nature of the stack (growsupwards or downwards), frame pointer etc.

Access at fixed offset relative to dynamically changing pointer.Offset and pointer location are known at compile time.

Code and layout also depends on CPU.

Code generation happens by recursive AST walk.

Industrial strength compilers are more complicated:I Try to keep values in registers, especially the current stack

frame. E.g. compilers for RISC-V usually pass first fourprocedure arguments in registers a0 - a3.

I Intermediate values, local variables are held in registers,not on the stack.

97 / 1

Page 98: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Code generation: summary remarksThe code of variable access, procedure calls and declarationsdepends totally on the layout of the AR, so the AR must bedesigned together with the code generator, and all parts of thecode generator must agree on AR conventions. It’s just asimportant to be clear about the nature of the stack (growsupwards or downwards), frame pointer etc.

Access at fixed offset relative to dynamically changing pointer.Offset and pointer location are known at compile time.

Code and layout also depends on CPU.

Code generation happens by recursive AST walk.

Industrial strength compilers are more complicated:I Try to keep values in registers, especially the current stack

frame. E.g. compilers for RISC-V usually pass first fourprocedure arguments in registers a0 - a3.

I Intermediate values, local variables are held in registers,not on the stack.

98 / 1

Page 99: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

What we have not covered is procedures taking non integerarguments.

This is easy: the only difference from a code generationperspective between integer types and other types asprocedure arguments is the size of the data. But that size isknown at compile-time (at least for languages that are staticallytyped). For example the type double is often 64 bits. So wereserve 8 bytes for arguments of that type in the procedure’sAR layout. We may have to use two calls to lw and sw to loadand store such arguments, but otherwise code generation isunchanged.

99 / 1

Page 100: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

What we have not covered is procedures taking non integerarguments.

This is easy: the only difference from a code generationperspective between integer types and other types asprocedure arguments is the size of the data. But that size isknown at compile-time (at least for languages that are staticallytyped). For example the type double is often 64 bits. So wereserve 8 bytes for arguments of that type in the procedure’sAR layout. We may have to use two calls to lw and sw to loadand store such arguments, but otherwise code generation isunchanged.

100 / 1

Page 101: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

Consider a procedure with thefollowing signature:

int f ( int x,double y,int z ) = { ... }

(Not valid in our mini-language).Assuming that double is stored as64 bits, then the AR would look likeon the right.

Caller's FP

int x

Double y

int z

return address

1632

1636

1640

1648

1652

1644

How does the code generator know what size the variableshave?Using the information stored in the symbol table, which wascreated by the type checker and passed to the code-generator.

101 / 1

Page 102: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

Consider a procedure with thefollowing signature:

int f ( int x,double y,int z ) = { ... }

(Not valid in our mini-language).Assuming that double is stored as64 bits, then the AR would look likeon the right.

Caller's FP

int x

Double y

int z

return address

1632

1636

1640

1648

1652

1644

How does the code generator know what size the variableshave?

Using the information stored in the symbol table, which wascreated by the type checker and passed to the code-generator.

102 / 1

Page 103: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

Consider a procedure with thefollowing signature:

int f ( int x,double y,int z ) = { ... }

(Not valid in our mini-language).Assuming that double is stored as64 bits, then the AR would look likeon the right.

Caller's FP

int x

Double y

int z

return address

1632

1636

1640

1648

1652

1644

How does the code generator know what size the variableshave?Using the information stored in the symbol table, which wascreated by the type checker and passed to the code-generator.

103 / 1

Page 104: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

Due to the simplistic accumulator machine approach, cannot dothe same with the return value, e.g.

double f ( int x, double y, int z ) = ...

This is because the accumulator holds the return value ofprocedure calls, and the accumulator is fixed at 32 bits.

In this case we’d have to move to an approach that holds thereturn value also in the AR (either for all arguments, or only forarguments that don’t fit in a register – we know at compile timewhich is which).

104 / 1

Page 105: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

Due to the simplistic accumulator machine approach, cannot dothe same with the return value, e.g.

double f ( int x, double y, int z ) = ...

This is because the accumulator holds the return value ofprocedure calls, and the accumulator is fixed at 32 bits.

In this case we’d have to move to an approach that holds thereturn value also in the AR (either for all arguments, or only forarguments that don’t fit in a register – we know at compile timewhich is which).

105 / 1

Page 106: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Non-integer procedure arguments

Due to the simplistic accumulator machine approach, cannot dothe same with the return value, e.g.

double f ( int x, double y, int z ) = ...

This is because the accumulator holds the return value ofprocedure calls, and the accumulator is fixed at 32 bits.

In this case we’d have to move to an approach that holds thereturn value also in the AR (either for all arguments, or only forarguments that don’t fit in a register – we know at compile timewhich is which).

106 / 1

Page 107: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Example def sumto(n) = if n=0 then 0 else n+sumto(n-1)

sumto_entry:mv fp, spsw ra, 0(sp)addi sp, sp, -4lw a0, 4(fp)sw a0, 0(sp)addi sp, sp, -4li a0, 0lw t1, 4(sp)addi sp, sp, 4beq t1, a0, then3

else4:lw a0, 4(fp)sw a0, 0(sp)addi sp, sp, -4sw fp, 0(sp)addi sp, sp, -4lw a0, 4(fp)sw a0, 0(sp)

addi sp, sp, -4li a0, 1lw t1, 4(sp)addi sp, sp, 4sub a0, t1, a0sw a0, 0(sp)addi sp, sp, -4jal sumto_entrylw t1, 4(sp)addi sp, sp, 4add a0, t1, a0b exit5

then3:li a0, 0

exit5:lw ra, 4(sp)addi sp, sp, 12lw fp, 0(sp)jr ra

107 / 1

Page 108: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Interesting observations (1)

Stack allocated memory is much faster than heap allocation,because (1) acquiring stack memory is just a constant-timepush operation, and (2) the whole AR can be ’deleted’ (=popped off the stack) in a single, constant-time operation. Wewill soon learn about heap-allocation (section ongarbage-collection), which is much more expensive. This is whylow-level language (C, C++, Rust) don’t have garbage collection(by default).

108 / 1

Page 109: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Interesting observations (2): inefficiency of thetranslation

As already pointed out at the beginning of this course, stack-and accumulator machines are inefficient.

Consider this fromthe previous slide (compilation of parts of n = 0 in sumto):

lw a0, 4(fp) // first we load n into the// accumulator from the stack

sw a0, 0(sp) // then we push n back onto// the stack

addi sp, sp, -4li a0, 0lw t1, 4(sp) // now we load n back from

// the stack into a temporary

This is the price we pay for the simplicity of compilation strategy.

It’s possible to do much better, e.g. saving it directly in t1 usingbetter compilation strategies and optimisation techniques.

109 / 1

Page 110: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Interesting observations (2): inefficiency of thetranslation

As already pointed out at the beginning of this course, stack-and accumulator machines are inefficient. Consider this fromthe previous slide (compilation of parts of n = 0 in sumto):

lw a0, 4(fp) // first we load n into the// accumulator from the stack

sw a0, 0(sp) // then we push n back onto// the stack

addi sp, sp, -4li a0, 0lw t1, 4(sp) // now we load n back from

// the stack into a temporary

This is the price we pay for the simplicity of compilation strategy.

It’s possible to do much better, e.g. saving it directly in t1 usingbetter compilation strategies and optimisation techniques.

110 / 1

Page 111: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Interesting observations (2): inefficiency of thetranslation

As already pointed out at the beginning of this course, stack-and accumulator machines are inefficient. Consider this fromthe previous slide (compilation of parts of n = 0 in sumto):

lw a0, 4(fp) // first we load n into the// accumulator from the stack

sw a0, 0(sp) // then we push n back onto// the stack

addi sp, sp, -4li a0, 0lw t1, 4(sp) // now we load n back from

// the stack into a temporary

This is the price we pay for the simplicity of compilation strategy.

It’s possible to do much better, e.g. saving it directly in t1 usingbetter compilation strategies and optimisation techniques.

111 / 1

Page 112: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Interesting observations (2): inefficiency of thetranslation

As already pointed out at the beginning of this course, stack-and accumulator machines are inefficient. Consider this fromthe previous slide (compilation of parts of n = 0 in sumto):

lw a0, 4(fp) // first we load n into the// accumulator from the stack

sw a0, 0(sp) // then we push n back onto// the stack

addi sp, sp, -4li a0, 0lw t1, 4(sp) // now we load n back from

// the stack into a temporary

This is the price we pay for the simplicity of compilation strategy.

It’s possible to do much better, e.g. saving it directly in t1 usingbetter compilation strategies and optimisation techniques.

112 / 1

Page 113: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.I Emit code enabling the OS to call the first procedure (like

Java’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.2. Jump-and-link’ing to the entry point (here: first procedure).3. Code that hands back control gracefully to the OS after

program termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

113 / 1

Page 114: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.I Emit code enabling the OS to call the first procedure (like

Java’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.2. Jump-and-link’ing to the entry point (here: first procedure).3. Code that hands back control gracefully to the OS after

program termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

114 / 1

Page 115: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.

I Emit code enabling the OS to call the first procedure (likeJava’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.2. Jump-and-link’ing to the entry point (here: first procedure).3. Code that hands back control gracefully to the OS after

program termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

115 / 1

Page 116: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.I Emit code enabling the OS to call the first procedure (like

Java’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.2. Jump-and-link’ing to the entry point (here: first procedure).3. Code that hands back control gracefully to the OS after

program termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

116 / 1

Page 117: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.I Emit code enabling the OS to call the first procedure (like

Java’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.

2. Jump-and-link’ing to the entry point (here: first procedure).3. Code that hands back control gracefully to the OS after

program termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

117 / 1

Page 118: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.I Emit code enabling the OS to call the first procedure (like

Java’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.2. Jump-and-link’ing to the entry point (here: first procedure).

3. Code that hands back control gracefully to the OS afterprogram termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

118 / 1

Page 119: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSo far we have only compiled expressions and singledeclarations, but a program is a sequence of declarations, andit is called from, and returns to the OS. To compile a wholeprogram we do the following:

I Creating the ’preamble’, e.g. setting up data declarations,alignment commands etc.

I Generate code for each declaration.I Emit code enabling the OS to call the first procedure (like

Java’s main – other languages might have differentconventions) ’to get the ball rolling’. This essentiallyinvolves

1. Creating (the caller’s side of) an activation record.2. Jump-and-link’ing to the entry point (here: first procedure).3. Code that hands back control gracefully to the OS after

program termination. Termination means doing a return tothe place after (2). This part is highly OS specific.

119 / 1

Page 120: Compilers and computer architecture: A realistic compiler ...users.sussex.ac.uk/~mfb21/compilers/slides/12.pdf · Intermediate code generation Optimisation Code generation Translated

Compiling whole programsSay we had a program declaring 4 procedures f1, f2, f3, andf4 in this order. Then a fully formed compiler would typicallygenerate code as follows.

preamble:...// e.g. alignment commands if needed

entry_point: // this is where the OS jumps to// at startup

... // create AR for initial call to f1jal f1_entry // jump to f1... // cleanup, hand back control to OS

// make sure you don’t ’fall’ into f1f1_entry:

... // f1 body codef2_entry:

... // f2 body codef3_entry:

... // f3 body codef4_entry:

... // f4 body code120 / 1