TECHNISCHE UNIVERSITÄT MÜNCHEN FAKULTÄT FÜR INFORMATIK Compiler Construction I Dr. Michael Petter, Dr. Axel Simon SoSe 2014 1 / 104
Topic: Semantic Analysis 2 / 104
Topic: Code Synthesis 3 / 104
Generating Code: Overview We inductively generate instructions from the AST: there is a rule stating how to generate code for each non-terminal of the grammar the code is merely another attribute in the syntax tree code generation makes use of the already computed attributes 4 / 104
Generating Code: Overview We inductively generate instructions from the AST: there is a rule stating how to generate code for each non-terminal of the grammar the code is merely another attribute in the syntax tree code generation makes use of the already computed attributes In order to specify the code generation, we require a semantics of the language we are compiling (here: C standard) the semantic of the machine instructions 4 / 104
Generating Code: Overview We inductively generate instructions from the AST: there is a rule stating how to generate code for each non-terminal of the grammar the code is merely another attribute in the syntax tree code generation makes use of the already computed attributes In order to specify the code generation, we require a semantics of the language we are compiling (here: C standard) the semantic of the machine instructions we commence by specifying machine instruction semantics 4 / 104
Code Synthesis Chapter 1: The Register C-Machine 5 / 104
The Register C-Machine (RCMa) We generate Code for the Register C-Machine. The Register C-Machine is a virtual machine (VM). there exists no processor that can execute its instructions... but we can build an interpreter for it we provide a visualization environment for the R-CMa the R-CMa has no double, float, char, short or long types the R-CMa has no instructions to communicate with the operating system the R-CMa has an unlimited supply of registers 6 / 104
The Register C-Machine (RCMa) We generate Code for the Register C-Machine. The Register C-Machine is a virtual machine (VM). there exists no processor that can execute its instructions... but we can build an interpreter for it we provide a visualization environment for the R-CMa the R-CMa has no double, float, char, short or long types the R-CMa has no instructions to communicate with the operating system the R-CMa has an unlimited supply of registers The R-CMa is more realistic than it may seem: the mentioned restrictions can easily be lifted the Java virtual machine (JVM) is similar to the R-CMa but has no registers an interpreter of R-CMA can run on any platform 6 / 104
Virtual Machines A virtual machines has the following ingredients: any virtual machine provides a set of instructions instructions are executed on virtual hardware the virtual hardware is a collection of data structures that is accessed and modified by the VM instructions... and also by other components of the run-time system, namely functions that go beyond the instruction semantics the interpreter is part of the run-time system 7 / 104
Components of a Virtual Machine Consider Java as an example: C 0 1 PC S 0 SP A virtual machine such as the JVM has the following structure: S: the data store a memory region in which cells can be stored in LIFO order stack. SP: ( = stack pointer) pointer to the last used cell in S beyond S, the memory containing the heap follows 8 / 104
Components of a Virtual Machine Consider Java as an example: C 0 1 PC S 0 SP A virtual machine such as the JVM has the following structure: S: the data store a memory region in which cells can be stored in LIFO order stack. SP: ( = stack pointer) pointer to the last used cell in S beyond S, the memory containing the heap follows C is the memory storing code each cell of C holds exactly one virtual instruction C can only be read PC ( = program counter) address of the instruction that is to be executed next PC contains 0 initially 8 / 104
Executing a Program the machine loads an instruction form C[PC] into an instruction register IR in order to execute it before evaluating the instruction, the PC is incremented by one while (true) { IR = C[PC]; PC++; execute (IR); } node: the PC must be incremented before the execution, since an instruction may modify the PC the loop is exited by evaluating a halt instruction that returns directly to the operating system 9 / 104
Code Synthesis Chapter 2: Evaluation of Expressions 10 / 104
Simple Expressions and Assignments Task: evaluate the expression (1 + 7) 3 that is, generate an instruction sequence that computes the value of the expression and stores it on top of the stack 11 / 104
Simple Expressions and Assignments Task: evaluate the expression (1 + 7) 3 that is, generate an instruction sequence that Idea: computes the value of the expression and stores it on top of the stack first compute the value of the sub-expressions store the intermediate result on top of the stack apply the operator 11 / 104
General Principle Evaluating an operation op(a 1,... a n ) the arguments a 1,... a n must be on top of the stack the execution of the operation op consumes its arguments any resulting values are stored on top of the stack iconst q q SP++; S[SP] = q; the instruction iconst q puts the int-constant q onto the stack 12 / 104
Binary Operators Operators with two arguments run as follows: 3 8 imul 24 SP--; S[SP] = S[SP] S[SP+1]; 13 / 104
Binary Operators Operators with two arguments run as follows: 3 8 imul 24 SP--; S[SP] = S[SP] S[SP+1]; imul expects two arguments on top of the stack, consumes them and puts the result on top of the stack 13 / 104
Binary Operators Operators with two arguments run as follows: 3 8 imul 24 SP--; S[SP] = S[SP] S[SP+1]; imul expects two arguments on top of the stack, consumes them and puts the result on top of the stack other arithmetic and logical operations iadd, isub, idiv, imod, etc. work analogously 13 / 104
Composition of Instructions Example: generate code for 1 + 7: iconst 1 iconst 7 iadd Execution of this instruction sequence: 7 iconst 1 1 iconst 7 1 iadd 8 14 / 104
Expressions with Variables Variables occupy a memory cell in S: z: y: x: 15 / 104
Expressions with Variables Variables occupy a memory cell in S: z: y: x: Associating addresses with variables can be done while creating the symbol table. The address is stored in any case at the node of the declaration of a variable. 15 / 104
Expressions with Variables Variables occupy a memory cell in S: z: y: x: Associating addresses with variables can be done while creating the symbol table. The address is stored in any case at the node of the declaration of a variable. For each use of a variable, the address has to be looked up by inspecting its declaration node. 15 / 104
Expressions with Variables Variables occupy a memory cell in S: z: y: x: Associating addresses with variables can be done while creating the symbol table. The address is stored in any case at the node of the declaration of a variable. For each use of a variable, the address has to be looked up by inspecting its declaration node. in the sequel, we use a mathematical map ρ, that contains mappings form a variable x to the (relative) address of x; the map ρ is called address environment (or simply environment). 15 / 104
Reading from a Variable The instruction iload k loads the value at address k, where k is relative to the top of the stack 13 iload k 13 13 S[SP+1] = S[SP-k]; SP = SP+1; Example: Compute x + 2 where ρ = {x 1}: 16 / 104
Reading from a Variable The instruction iload k loads the value at address k, where k is relative to the top of the stack 13 iload k 13 13 S[SP+1] = S[SP-k]; SP = SP+1; Example: Compute x + 2 where ρ = {x 1}: iload 1 iconst 2 iadd 16 / 104
Code Synthesis Chapter 3: Generating Code for the Register C-Machine 17 / 104
Motivation for the Register C-Machine A modern RISC processor features a fixed number of universal registers. 18 / 104
Motivation for the Register C-Machine A modern RISC processor features a fixed number of universal registers. arithmetic operations can only use these registers as arguments access to memory are done via instructions to load and store to and from registers unlike the stack, registers have to be explicitly saved before a function is called 18 / 104
Motivation for the Register C-Machine A modern RISC processor features a fixed number of universal registers. arithmetic operations can only use these registers as arguments access to memory are done via instructions to load and store to and from registers unlike the stack, registers have to be explicitly saved before a function is called A translation for a RISC processor must therefore: 18 / 104
Motivation for the Register C-Machine A modern RISC processor features a fixed number of universal registers. arithmetic operations can only use these registers as arguments access to memory are done via instructions to load and store to and from registers unlike the stack, registers have to be explicitly saved before a function is called A translation for a RISC processor must therefore: 1 store variables and function arguments in registers 2 save the content of registers onto the stack before calling a function 3 express any arbitrary computation using finitely many registers 18 / 104
Motivation for the Register C-Machine A modern RISC processor features a fixed number of universal registers. arithmetic operations can only use these registers as arguments access to memory are done via instructions to load and store to and from registers unlike the stack, registers have to be explicitly saved before a function is called A translation for a RISC processor must therefore: 1 store variables and function arguments in registers 2 save the content of registers onto the stack before calling a function 3 express any arbitrary computation using finitely many registers only consider the first two problems (and deal with the other two later) 18 / 104
Principle of the Register C-Machine The R-CMa is composed of a stack, heap and a code segment, just like the JVM; it additionally has register sets: local registers are R 1, R 2,... R i,... global register are R 0, R 1,... R j,... C 0 1 PC S 0 SP R loc R 1 R 6 R glob R 0 R 4 19 / 104
The Register Sets of the R-CMa The two register sets have the following purpose: 1 the local registers R i save temporary results store the contents of local variables of a function can efficiently be stored and restored from the stack 20 / 104
The Register Sets of the R-CMa The two register sets have the following purpose: 1 the local registers R i save temporary results store the contents of local variables of a function can efficiently be stored and restored from the stack 2 the global registers R i save the parameters of a function store the result of a function 20 / 104
The Register Sets of the R-CMa The two register sets have the following purpose: 1 the local registers R i save temporary results store the contents of local variables of a function can efficiently be stored and restored from the stack 2 the global registers R i save the parameters of a function store the result of a function Note: for now, we only use registers to store temporary computations 20 / 104
The Register Sets of the R-CMa The two register sets have the following purpose: 1 the local registers R i save temporary results store the contents of local variables of a function can efficiently be stored and restored from the stack 2 the global registers R i save the parameters of a function store the result of a function Note: for now, we only use registers to store temporary computations Idea for the translation: use a register counter i: registers R j with j < i are in use registers R j with j i are available 20 / 104
Translation of Simple Expressions Using variables stored in registers; loading constants: instruction semantics intuition loadc R i c R i = c load constant move R i R j R i = R j copy R j to R i 21 / 104
Translation of Simple Expressions Using variables stored in registers; loading constants: instruction semantics intuition loadc R i c R i = c load constant move R i R j R i = R j copy R j to R i We define the following translation schema (with ρ x = a): code i R c ρ = loadc R i c code i R x ρ = move R i R a code i R x = e ρ = code i R e ρ move R a R i 21 / 104
Translation of Simple Expressions Using variables stored in registers; loading constants: instruction semantics intuition loadc R i c R i = c load constant move R i R j R i = R j copy R j to R i We define the following translation schema (with ρ x = a): code i R c ρ = loadc R i c code i R x ρ = move R i R a code i R x = e ρ = code i R e ρ move R a R i Note: all instructions use the Intel convention (in contrast to the AT&T convention): op dst src 1... src n. 21 / 104
Translation of Expressions Let op = {add, sub, div, mul, mod, le, gr, eq, leq, geq, and, or}. The R-CMa provides an instruction for each operator op. op R i R j R k where R i is the target register, R j the first and R k the second argument. Correspondingly, we generate code as follows: code i R e 1 op e 2 ρ = code i R e 1 ρ coder i+1 e 2 ρ op R i R i R i+1 22 / 104
Translation of Expressions Let op = {add, sub, div, mul, mod, le, gr, eq, leq, geq, and, or}. The R-CMa provides an instruction for each operator op. op R i R j R k where R i is the target register, R j the first and R k the second argument. Correspondingly, we generate code as follows: code i R e 1 op e 2 ρ = code i R e 1 ρ coder i+1 e 2 ρ op R i R i R i+1 Example: Translate 3*4 with i = 4: code 4 R 3 *4 ρ = code 4 R 3 ρ code 5 R 4 ρ mul R 4 R 4 R 5 22 / 104
Translation of Expressions Let op = {add, sub, div, mul, mod, le, gr, eq, leq, geq, and, or}. The R-CMa provides an instruction for each operator op. op R i R j R k where R i is the target register, R j the first and R k the second argument. Correspondingly, we generate code as follows: code i R e 1 op e 2 ρ = code i R e 1 ρ coder i+1 e 2 ρ op R i R i R i+1 Example: Translate 3*4 with i = 4: code 4 R 3 *4 ρ = loadc R 4 3 loadc R 5 4 mul R 4 R 4 R 5 22 / 104
Managing Temporary Registers Observe that temporary registers are re-used: translate 3*4+3*4 with t = 4: where we obtain code 4 R 3 *4+3*4 ρ = code 4 R 3 *4 ρ code 5 R 3 *4 ρ add R 4 R 4 R 5 code i R 3 *4 ρ = loadc R i 3 loadc R i+1 4 mul R i R i R i+1 code 4 R 3 *4+3*4 ρ = 23 / 104
Managing Temporary Registers Observe that temporary registers are re-used: translate 3*4+3*4 with t = 4: where we obtain code 4 R 3 *4+3*4 ρ = code 4 R 3 *4 ρ code 5 R 3 *4 ρ add R 4 R 4 R 5 code i R 3 *4 ρ = loadc R i 3 loadc R i+1 4 mul R i R i R i+1 code 4 R 3 *4+3*4 ρ = loadc R 4 3 loadc R 5 4 mul R 4 R 4 R 5 loadc R 5 3 loadc R 6 4 mul R 5 R 5 R 6 add R 4 R 4 R 5 23 / 104
Semantics of Operators The operators have the following semantics: add R i R j R k sub R i R j R k div R i R j R k mul R i R j R k mod R i R j R k R i = R j + R k R i = R j R k R i = R j /R k R i = R j R k R i = sgn(r k )k wobei R j = n R k + k n 0, 0 k < R k le R i R j R k R i = if R j < R k then 1 else 0 gr R i R j R k R i = if R j > R k then 1 else 0 eq R i R j R k R i = if R j = R k then 1 else 0 leq R i R j R k R i = if R j R k then 1 else 0 geq R i R j R k R i = if R j R k then 1 else 0 and R i R j R k R i = R j & R k // bit-wise and or R i R j R k R i = R j R k // bit-wise or 24 / 104
Semantics of Operators The operators have the following semantics: add R i R j R k sub R i R j R k div R i R j R k mul R i R j R k mod R i R j R k R i = R j + R k R i = R j R k R i = R j /R k R i = R j R k R i = sgn(r k )k wobei R j = n R k + k n 0, 0 k < R k le R i R j R k R i = if R j < R k then 1 else 0 gr R i R j R k R i = if R j > R k then 1 else 0 eq R i R j R k R i = if R j = R k then 1 else 0 leq R i R j R k R i = if R j R k then 1 else 0 geq R i R j R k R i = if R j R k then 1 else 0 and R i R j R k R i = R j & R k // bit-wise and or R i R j R k R i = R j R k // bit-wise or Note: all registers and memory cells contain operands in Z 24 / 104
Translation of Unary Operators Unary operators op = {neg, not} take only two registers: code i R op e ρ = codei R e ρ op R i R i 25 / 104
Translation of Unary Operators Unary operators op = {neg, not} take only two registers: code i R op e ρ = codei R e ρ op R i R i Note: We use the same register. 25 / 104
Translation of Unary Operators Unary operators op = {neg, not} take only two registers: code i R op e ρ = codei R e ρ op R i R i Note: We use the same register. Example: Translate -4 into R 5 : code 5 R -4 ρ = code5 R 4 ρ neg R 5 R 5 25 / 104
Translation of Unary Operators Unary operators op = {neg, not} take only two registers: code i R op e ρ = codei R e ρ op R i R i Note: We use the same register. Example: Translate -4 into R 5 : code 5 R -4 ρ = loadc R 5 4 neg R 5 R 5 25 / 104
Translation of Unary Operators Unary operators op = {neg, not} take only two registers: code i R op e ρ = codei R e ρ op R i R i Note: We use the same register. Example: Translate -4 into R 5 : code 5 R -4 ρ = loadc R 5 4 neg R 5 R 5 The operators have the following semantics: not R i R j R i if R j = 0 then 1 else 0 neg R i R j R i R j 25 / 104
Applying Translation Schema for Expressions Suppose the following function void f(void) { is given: int x,y,z; x = y+z*3; } Let ρ = {x 1, y 2, z 3} be the address environment. Let R 4 be the first free register, that is, i = 4. code 4 x=y+z*3 ρ = code 4 R y+z *3 ρ move R 1 R 4 26 / 104
Applying Translation Schema for Expressions Suppose the following function void f(void) { is given: int x,y,z; x = y+z*3; } Let ρ = {x 1, y 2, z 3} be the address environment. Let R 4 be the first free register, that is, i = 4. code 4 x=y+z*3 ρ = code 4 R y+z *3 ρ move R 1 R 4 code 4 R y+z*3 ρ = move R 4 R 2 code 5 R z *3 ρ add R 4 R 4 R 5 26 / 104
Applying Translation Schema for Expressions Suppose the following function void f(void) { is given: int x,y,z; x = y+z*3; } Let ρ = {x 1, y 2, z 3} be the address environment. Let R 4 be the first free register, that is, i = 4. code 4 x=y+z*3 ρ = code 4 R y+z *3 ρ move R 1 R 4 code 4 R y+z*3 ρ = move R 4 R 2 code 5 R z *3 ρ add R 4 R 4 R 5 code 5 R z*3 ρ = move R 5 R 3 code 6 R 3 ρ mul R 5 R 5 R 6 26 / 104
Applying Translation Schema for Expressions Suppose the following function void f(void) { is given: int x,y,z; x = y+z*3; } Let ρ = {x 1, y 2, z 3} be the address environment. Let R 4 be the first free register, that is, i = 4. code 4 x=y+z*3 ρ = code 4 R y+z *3 ρ move R 1 R 4 code 4 R y+z*3 ρ = move R 4 R 2 code 5 R z *3 ρ add R 4 R 4 R 5 code 5 R z*3 ρ = move R 5 R 3 code 6 R 3 ρ mul R 5 R 5 R 6 code 6 R 3 ρ = loadc R 6 3 26 / 104
Applying Translation Schema for Expressions Suppose the following function void f(void) { is given: int x,y,z; x = y+z*3; } Let ρ = {x 1, y 2, z 3} be the address environment. Let R 4 be the first free register, that is, i = 4. code 4 x=y+z*3 ρ = code 4 R y+z *3 ρ move R 1 R 4 code 4 R y+z*3 ρ = move R 4 R 2 code 5 R z *3 ρ add R 4 R 4 R 5 code 5 R z*3 ρ = move R 5 R 3 code 6 R 3 ρ mul R 5 R 5 R 6 code 6 R 3 ρ = loadc R 6 3 the assignment x=y+z*3 is translated as move R 4 R 2 ; move R 5 R 3 ; loadc R 6 3; mul R 5 R 5 R 6 ; add R 4 R 4 R 5 ; move R 1 R 4 26 / 104
Code Synthesis Chapter 4: Statements and Control Structures 27 / 104
About Statements and Expressions General idea for translation: code i s ρ : generate code for statement s code i R e ρ : generate code for expression e into R i Throughout: i, i + 1,... are free (unused) registers 28 / 104
About Statements and Expressions General idea for translation: code i s ρ : generate code for statement s code i R e ρ : generate code for expression e into R i Throughout: i, i + 1,... are free (unused) registers For an expression x = e with ρ x = a we defined: code i R x = e ρ = code i R e ρ However, x = e is also a statement: move R a R i 28 / 104
About Statements and Expressions General idea for translation: code i s ρ : generate code for statement s code i R e ρ : generate code for expression e into R i Throughout: i, i + 1,... are free (unused) registers For an expression x = e with ρ x = a we defined: code i R x = e ρ = code i R e ρ However, x = e is also a statement: Define: move R a R i code i e 1 = e 2 ρ = code i R e 1 = e 2 ρ The temporary register R i is ignored here. More general: code i e ρ = code i R e ρ 28 / 104
About Statements and Expressions General idea for translation: code i s ρ : generate code for statement s code i R e ρ : generate code for expression e into R i Throughout: i, i + 1,... are free (unused) registers For an expression x = e with ρ x = a we defined: code i R x = e ρ = code i R e ρ However, x = e is also a statement: Define: move R a R i code i e 1 = e 2 ρ = code i R e 1 = e 2 ρ The temporary register R i is ignored here. More general: code i e ρ = code i R e ρ Observation: the assignment to e 1 is a side effect of the evaluating the expression e 1 = e 2. 28 / 104
Translation of Statement Sequences The code for a sequence of statements is the concatenation of the instructions for each statement in that sequence: code i (s ss) ρ = code i s ρ code i ss ρ code i ε ρ = // empty sequence of instructions Note here: s is a statement, ss is a sequence of statements 29 / 104
Jumps In order to diverge from the linear sequence of execution, we need jumps: jump A A PC PC PC = A; 30 / 104
Conditional Jumps A conditional jump branches depending on the value in R i :!0 Ri jumpz Ri A!0 Ri PC PC 0 Ri PC jumpz Ri A if (R i == 0) PC = A; 0 Ri A PC 31 / 104
Management of Control Flow In order to translate statements with control flow, we need to emit jump instructions. during the translation of an if (c) construct, it is not yet clear where to jump to in case that c is false 32 / 104
Management of Control Flow In order to translate statements with control flow, we need to emit jump instructions. during the translation of an if (c) construct, it is not yet clear where to jump to in case that c is false instruction sequences may be arranged in a different order minimize the number of unconditional jumps minimize in a way so that fewer jumps are executed inside loops replace far jumps through near jumps (if applicable) 32 / 104
Management of Control Flow In order to translate statements with control flow, we need to emit jump instructions. during the translation of an if (c) construct, it is not yet clear where to jump to in case that c is false instruction sequences may be arranged in a different order minimize the number of unconditional jumps minimize in a way so that fewer jumps are executed inside loops replace far jumps through near jumps (if applicable) organize instruction sequence into blocks without jumps 32 / 104
Management of Control Flow In order to translate statements with control flow, we need to emit jump instructions. during the translation of an if (c) construct, it is not yet clear where to jump to in case that c is false instruction sequences may be arranged in a different order minimize the number of unconditional jumps minimize in a way so that fewer jumps are executed inside loops replace far jumps through near jumps (if applicable) organize instruction sequence into blocks without jumps To this end, we define: Definition A basic block consists of a sequence of statements ss that does not contain a jump a set of outgoing edges to other basic blocks where each edge may be labelled with a condition 32 / 104
Basic Blocks and the Register C-Machine The R-CMa features only a single conditional jump, namely jumpz. code ss c Outgoing edges must have the following form: 33 / 104
Basic Blocks and the Register C-Machine The R-CMa features only a single conditional jump, namely jumpz. code ss c Outgoing edges must have the following form: 1 a single edge (unconditional jump), translated with jump 33 / 104
Basic Blocks and the Register C-Machine The R-CMa features only a single conditional jump, namely jumpz. code ss c Outgoing edges must have the following form: 1 a single edge (unconditional jump), translated with jump 2 two edges, one with c = 0 as condition and one without condition, translated with jumpz and jump, respectively 33 / 104
Basic Blocks and the Register C-Machine The R-CMa features only a single conditional jump, namely jumpz. code ss c Outgoing edges must have the following form: 1 a single edge (unconditional jump), translated with jump 2 two edges, one with c = 0 as condition and one without condition, translated with jumpz and jump, respectively 3 a set of edges and one default edge, used for switch statement, translated with jumpi and jump (to be discussed later) 33 / 104
Formalizing the Translation Involving Control Flow For simplicity of defining translations of instructions involving control flow, we use symbolic jump targets. This translation can be used in practice, but a second run through the emitted instructions is necessary to resolve the symbolic addresses to actual addresses. 34 / 104
Formalizing the Translation Involving Control Flow For simplicity of defining translations of instructions involving control flow, we use symbolic jump targets. This translation can be used in practice, but a second run through the emitted instructions is necessary to resolve the symbolic addresses to actual addresses. Alternatively, we can emit relative jumps without a second pass: relative jumps have targets that are offsets to the current PC sometime relative jumps only possible for small offsets ( near jumps) if all jumps are relative: the code becomes position independent (PIC), that is, it can be moved to a different address the generated code can be loaded without relocating absolute jumps 34 / 104
Formalizing the Translation Involving Control Flow For simplicity of defining translations of instructions involving control flow, we use symbolic jump targets. This translation can be used in practice, but a second run through the emitted instructions is necessary to resolve the symbolic addresses to actual addresses. Alternatively, we can emit relative jumps without a second pass: relative jumps have targets that are offsets to the current PC sometime relative jumps only possible for small offsets ( near jumps) if all jumps are relative: the code becomes position independent (PIC), that is, it can be moved to a different address the generated code can be loaded without relocating absolute jumps generating a graph of basic blocks is useful for program optimization where the statements inside basic blocks are simplified 34 / 104
Simple Conditional We first consider s if ( c ) ss....and present a translation without basic blocks. Idea: emit the code of c and ss in sequence insert a jump instruction in-between, so that correct control flow is ensured code i s ρ = code i R c ρ jumpz R i A code i ss ρ A :... code R jumpz code for ss for c 35 / 104
General Conditional code c code tt code ee Translation of if ( c ) tt else ee. code i if(c) tt else ee ρ = A : B : code i R c ρ jumpz R i A code i tt ρ jump B code i ee ρ code R for c jumpz code for tt jump code for ee 36 / 104
Example for if-statement Let ρ = {x 4, y 7} and let s be the statement if (x>y) { /* (i) */ x = x - y; /* (ii) */ } else { y = y - x; /* (iii) */ } Then code i s ρ yields: 37 / 104
Example for if-statement Let ρ = {x 4, y 7} and let s be the statement if (x>y) { /* (i) */ x = x - y; /* (ii) */ } else { y = y - x; /* (iii) */ } Then code i s ρ yields: (i) (ii) (iii) move R i R 4 move R i+1 R 7 move R i R 4 move R i+1 R 7 A : move R i R 7 move R i+1 R 4 gr R i R i R i+1 jumpz R i A sub R i R i R i+1 move R 4 R i jump B B : sub R i R i R i+1 move R 7 R i 37 / 104
Iterating Statements We only consider the loop s while (e) s. For this statement we define: code i while(e) s ρ = A : code i R e ρ jumpz R i B code i s ρ jump A B : code R for e jumpz code for s jump 38 / 104
Example: Translation of Loops Let ρ = {a 7, b 8, c 9} and let s be the statement: while (a>0) { /* (i) */ c = c + 1; /* (ii) */ a = a - b; /* (iii) */ } Then code i s ρ evaluates to: 39 / 104
Example: Translation of Loops Let ρ = {a 7, b 8, c 9} and let s be the statement: while (a>0) { /* (i) */ c = c + 1; /* (ii) */ a = a - b; /* (iii) */ } Then code i s ρ evaluates to: (i) (ii) (iii) A : move R i R 7 loadc R i+1 0 gr R i R i R i+1 jumpz R i B move R i R 9 loadc R i+1 1 add R i R i R i+1 move R 9 R i B : move R i R 7 move R i+1 R 8 sub R i R i R i+1 move R 7 R i jump A 39 / 104
for-loops The for-loop s for (e 1 ; e 2 ; e 3 ) s is equivalent to the statement sequence e 1 ; while (e 2 ) {s e 3 ; } as long as s does not contain a continue statement. Thus, we translate: code i for(e 1 ; e 2 ; e 3 ) s ρ = code i R e 1 ρ A : B : code i R e 2 ρ jumpz R i B code i s ρ code i R e 3 ρ jump A 40 / 104
The switch-statement Idea: Suppose choosing from multiple options in constant time if possible use a jump table that, at the ith position, holds a jump to the ith alternative in order to realize this idea, we need an indirect jump instruction 41 / 104
The switch-statement Idea: Suppose choosing from multiple options in constant time if possible use a jump table that, at the ith position, holds a jump to the ith alternative in order to realize this idea, we need an indirect jump instruction q Ri B PC jumpi Ri A PC = A + R i ; q Ri A+q PC 41 / 104
Consecutive Alternatives Let switch s be given with k consecutive case alternatives: switch (e) { case c 0 : s 0 ; break;. case c k 1 : s k 1 ; break; default: s; break; } that is, c i + 1 = c i+1 for i = [0, k 1]. 42 / 104
Consecutive Alternatives Let switch s be given with k consecutive case alternatives: switch (e) { case c 0 : s 0 ; break;. case c k 1 : s k 1 ; break; default: s; break; } that is, c i + 1 = c i+1 for i = [0, k 1]. Define code i s ρ as follows: code i s ρ = code i R e ρ A 0 :. A k 1 : check i c 0 c k 1 B code i s 0 ρ jump D. code i s k 1 ρ jump D B : jump A 0.. jump A k 1 C : 42 / 104
Consecutive Alternatives Let switch s be given with k consecutive case alternatives: switch (e) { case c 0 : s 0 ; break;. case c k 1 : s k 1 ; break; default: s; break; } that is, c i + 1 = c i+1 for i = [0, k 1]. Define code i s ρ as follows: code i s ρ = code i R e ρ A 0 :. A k 1 : check i c 0 c k 1 B code i s 0 ρ jump D. code i s k 1 ρ B : jump A 0 jump D check i l u B checks if l R i < u holds and jumps accordingly.. C :. jump A k 1 42 / 104
Translation of the check i Macro The macro check i l u B checks if l R i < u. Let k = u l. if l R i < u it jumps to B + R i l if R i < l or R i u it jumps to C B : jump A 0. C :. jump A k 1 43 / 104
Translation of the check i Macro The macro check i l u B checks if l R i < u. Let k = u l. if l R i < u it jumps to B + R i l if R i < l or R i u it jumps to C we define: check i l u B = loadc R i+1 l geq R i+2 R i R i+1 jumpz R i+2 E sub R i R i R i+1 loadc R i+1 k geq R i+2 R i R i+1 jumpz R i+2 D E : loadc R i k D : jumpi R i B B : jump A 0.. jump A k 1 C : 43 / 104
Translation of the check i Macro The macro check i l u B checks if l R i < u. Let k = u l. if l R i < u it jumps to B + R i l if R i < l or R i u it jumps to C we define: check i l u B = loadc R i+1 l geq R i+2 R i R i+1 jumpz R i+2 E sub R i R i R i+1 loadc R i+1 k geq R i+2 R i R i+1 jumpz R i+2 D E : loadc R i k D : jumpi R i B B : jump A 0.. jump A k 1 C : Note: a jump jumpi R i B with R i = k winds up at C. 43 / 104
Improvements for Jump Tables This translation is only suitable for certain switch-statement. In case the table starts with 0 instead of u we don t need to subtract it from e before we use it as index if the value of e is guaranteed to be in the interval [l, u], we can omit check can we implement the switch-statement using an L-attributed system without symbolic labels? 44 / 104
Improvements for Jump Tables This translation is only suitable for certain switch-statement. In case the table starts with 0 instead of u we don t need to subtract it from e before we use it as index if the value of e is guaranteed to be in the interval [l, u], we can omit check can we implement the switch-statement using an L-attributed system without symbolic labels? difficult since B is unknown when check i is translated use symbolic labels or basic blocks 44 / 104
General translation of switch-statements In general, the values of the various cases may be far apart: generate an if-ladder, that is, a sequence of if-statements 45 / 104
General translation of switch-statements In general, the values of the various cases may be far apart: generate an if-ladder, that is, a sequence of if-statements for n cases, an if-cascade (tree of conditionals) can be generated O(log n) tests 45 / 104
General translation of switch-statements In general, the values of the various cases may be far apart: generate an if-ladder, that is, a sequence of if-statements for n cases, an if-cascade (tree of conditionals) can be generated O(log n) tests if the sequence of numbers has small gaps ( 3), a jump table may be smaller and faster 45 / 104
General translation of switch-statements In general, the values of the various cases may be far apart: generate an if-ladder, that is, a sequence of if-statements for n cases, an if-cascade (tree of conditionals) can be generated O(log n) tests if the sequence of numbers has small gaps ( 3), a jump table may be smaller and faster one could generate several jump tables, one for each sets of consecutive cases 45 / 104
General translation of switch-statements In general, the values of the various cases may be far apart: generate an if-ladder, that is, a sequence of if-statements for n cases, an if-cascade (tree of conditionals) can be generated O(log n) tests if the sequence of numbers has small gaps ( 3), a jump table may be smaller and faster one could generate several jump tables, one for each sets of consecutive cases an if cascade can be re-arranged by using information from profiling, so that paths executed more frequently require fewer tests 45 / 104
Translation into Basic Blocks Problem: How do we connect the different basic blocks? Idea: translation of a function: create an empty block and store a pointer to it in the node of the function declaration 46 / 104
Translation into Basic Blocks Problem: How do we connect the different basic blocks? Idea: translation of a function: create an empty block and store a pointer to it in the node of the function declaration pass this block down to the translation of statements 46 / 104
Translation into Basic Blocks Problem: How do we connect the different basic blocks? Idea: translation of a function: create an empty block and store a pointer to it in the node of the function declaration pass this block down to the translation of statements each new statement is appended to this basic block 46 / 104
Translation into Basic Blocks Problem: How do we connect the different basic blocks? Idea: translation of a function: create an empty block and store a pointer to it in the node of the function declaration pass this block down to the translation of statements each new statement is appended to this basic block a two-way if-statement creates three new blocks: 1 one for the then-branch, connected with the current block by a jumpz-edge 2 one for the else-branch, connected with the current block by a jump-edge 3 one for the following statements, connect to the then- and else-branch by a jump edge 46 / 104
Translation into Basic Blocks Problem: How do we connect the different basic blocks? Idea: translation of a function: create an empty block and store a pointer to it in the node of the function declaration pass this block down to the translation of statements each new statement is appended to this basic block a two-way if-statement creates three new blocks: 1 one for the then-branch, connected with the current block by a jumpz-edge 2 one for the else-branch, connected with the current block by a jump-edge 3 one for the following statements, connect to the then- and else-branch by a jump edge similar for other constructs 46 / 104
Translation into Basic Blocks Problem: How do we connect the different basic blocks? Idea: translation of a function: create an empty block and store a pointer to it in the node of the function declaration pass this block down to the translation of statements each new statement is appended to this basic block a two-way if-statement creates three new blocks: 1 one for the then-branch, connected with the current block by a jumpz-edge 2 one for the else-branch, connected with the current block by a jump-edge 3 one for the following statements, connect to the then- and else-branch by a jump edge similar for other constructs For better navigation in later stages, it can be necessary to also add backward edges. 46 / 104
Code Synthesis Chapter 5: Functions 47 / 104
Ingredients of a Function The definition of a function consists of a name with which it can be called; a specification of its formal parameters; possibly a result type; a sequence of statements. In C we have: Observe: code i R f ρ = loadc _f with _f starting address of f function names must have an address assigned to them since the size of functions is unknown before they are translated, the addresses of forward-declared functions must be inserted later 48 / 104
Memory Management in Functions int fac(int x) { if (x<=0) return 1; else return x*fac(x-1); } int main(void) { int n; n = fac(2) + fac(1); printf("%d", n); } At run-time several instance may be active, that is, the function has been called but has not yet returned. The recursion tree in the example: main fac fac fac fac fac printf 49 / 104
Memory Management in Function Variables The formal parameters and the local variables of the various (instances) of a function must be kept separate Idea for implementing functions: 50 / 104
Memory Management in Function Variables The formal parameters and the local variables of the various (instances) of a function must be kept separate Idea for implementing functions: set up a region of memory each time it is called 50 / 104
Memory Management in Function Variables The formal parameters and the local variables of the various (instances) of a function must be kept separate Idea for implementing functions: set up a region of memory each time it is called in sequential programs this memory region can be allocate on the stack 50 / 104
Memory Management in Function Variables The formal parameters and the local variables of the various (instances) of a function must be kept separate Idea for implementing functions: set up a region of memory each time it is called in sequential programs this memory region can be allocate on the stack thus, each instance of a function has its own region on the stack 50 / 104
Memory Management in Function Variables The formal parameters and the local variables of the various (instances) of a function must be kept separate Idea for implementing functions: set up a region of memory each time it is called in sequential programs this memory region can be allocate on the stack thus, each instance of a function has its own region on the stack these regions are called stack frames) 50 / 104
Organization of a Stack Frame stack representation: grows upwards SP points to the last used stack cell SP FP PCold FPold EPold local memory callee organizational cells local memory caller 51 / 104
Organization of a Stack Frame stack representation: grows upwards SP points to the last used stack cell SP FP PCold FPold EPold local memory callee organizational cells local memory caller FP = frame pointer: points to the last organizational cell use to recover the previously active stack frame 51 / 104
Organization of a Stack Frame stack representation: grows upwards SP points to the last used stack cell SP FP PCold FPold EPold local memory callee organizational cells local memory caller FP = frame pointer: points to the last organizational cell use to recover the previously active stack frame EP has to do with the heap, will come to that later 51 / 104
Split of Obligations Definition Let f be the current function that calls a function g. f is dubbed caller g is dubbed callee The code for managing function calls has to be split between caller and callee. This split cannot be done arbitrarily since some information is only known in that caller or only in the callee. Observation: The space requirement for parameters is only know by the caller: Example: printf 52 / 104
Principle of Function Call and Return actions taken on entering g: 1. compute the start address of g 2. compute actual parameters 3. backup of caller-save registers 4. backup of FP, EP 5. set the new FP 6. back up of PC and jump to the beginning of g 7. setup new EP 8. allocate space for local variables actions taken on leaving g: 1. compute the result 2. restore FP, EP, SP 3. return to the call site in f, that is, restore PC 4. restore the caller-save registers 5. clean up stack } } saveloc mark are in f call } } } enter are in g alloc return are in g } } } restoreloc are in f pop k 53 / 104
Managing Registers during Function Calls The two register sets (global and local) are used as follows: automatic variables live in local registers R i intermediate results also live in local registers R i parameters global registers R i (with i 0) global variables: 54 / 104
Managing Registers during Function Calls The two register sets (global and local) are used as follows: automatic variables live in local registers R i intermediate results also live in local registers R i parameters global registers R i (with i 0) global variables: let s suppose there are none convention: 54 / 104
Managing Registers during Function Calls The two register sets (global and local) are used as follows: automatic variables live in local registers R i intermediate results also live in local registers R i parameters global registers R i (with i 0) global variables: let s suppose there are none convention: the i th argument of a function is passed in register R i 54 / 104
Managing Registers during Function Calls The two register sets (global and local) are used as follows: automatic variables live in local registers R i intermediate results also live in local registers R i parameters global registers R i (with i 0) global variables: let s suppose there are none convention: the i th argument of a function is passed in register R i the result of a function is stored in R 0 54 / 104
Managing Registers during Function Calls The two register sets (global and local) are used as follows: automatic variables live in local registers R i intermediate results also live in local registers R i parameters global registers R i (with i 0) global variables: let s suppose there are none convention: the i th argument of a function is passed in register R i the result of a function is stored in R 0 local registers are saved before calling a function 54 / 104
Managing Registers during Function Calls The two register sets (global and local) are used as follows: automatic variables live in local registers R i intermediate results also live in local registers R i parameters global registers R i (with i 0) global variables: let s suppose there are none convention: the i th argument of a function is passed in register R i the result of a function is stored in R 0 local registers are saved before calling a function Definition Let f be a function that calls g. A register R i is called caller-saved if f backs up R i and g may overwrite it callee-saved if f R i does not back up g must restore it before it returns 54 / 104
Translation of Function Calls A function call g(e 1,... e n ) is translated as follows: code i R g(e 1,... e n ) ρ = code i R g ρ code i+1 R e 1 ρ. code i+n R e n ρ move R 1 R i+1. move R n R i+n saveloc R 1 R i 1 mark call R i restoreloc R 1 R i 1 move R i R 0 55 / 104
Translation of Function Calls A function call g(e 1,... e n ) is translated as follows: code i R g(e 1,... e n ) ρ = code i R g ρ code i+1 R e 1 ρ. code i+n R e n ρ move R 1 R i+1. move R n R i+n saveloc R 1 R i 1 mark call R i restoreloc R 1 R i 1 move R i R 0 New instructions: saveloc R i R j pushes the registers R i, R i+1... R j onto the stack mark backs up the organizational cells call R i calls the function at the address in R i restoreloc R i R j pops R j, R j 1,... R i off the stack 55 / 104
Translation of Function Calls A function call g(e 1,... e n ) is translated as follows: code i R g(e 1,... e n ) ρ = code i R g ρ code i+1 R e 1 ρ. code i+n R e n ρ move R 1 R i+1. move R n R i+n saveloc R 1 R i 1 mark call R i restoreloc R 1 R i 1? = code i R e 1 ρ move R 1 R i. code i R e n ρ move R n R i code i R g ρ saveloc R 1 R i 1 mark call R i restoreloc R 1 R i 1 move R i R 0 move R i R 0 New instructions: saveloc R i R j pushes the registers R i, R i+1... R j onto the stack mark backs up the organizational cells call R i calls the function at the address in R i restoreloc R i R j pops R j, R j 1,... R i off the stack 55 / 104
Rescuing EP and FP The instruction mark allocates stack space for the return value and the organizational cells and backs up FP and EP. FP EP e FP EP e e mark S[SP+1] = EP; S[SP+2] = FP; SP = SP + 2; 56 / 104
Calling a Function The instruction call rescues the value of PC+1 onto the stack and sets FP and PC. FP q p q Ri call Ri Ri PC p PC q SP = SP+1; S[SP] = PC; FP = SP; PC = Ri; 57 / 104
Result of a Function The global register set is also used to communicate the result value of a function: code i return e ρ = code i R e ρ move R 0 R i return 58 / 104
Result of a Function The global register set is also used to communicate the result value of a function: alternative without result value: code i return e ρ = code i R e ρ move R 0 R i return code i return ρ = return 58 / 104
Result of a Function The global register set is also used to communicate the result value of a function: alternative without result value: code i return e ρ = code i R e ρ move R 0 R i return code i return ρ = return global registers are otherwise not used inside a function body: advantage: at any point in the body another function can be called without backing up global registers disadvantage: on entering a function, all global registers must be saved 58 / 104
Return from a Function The instruction return relinquishes control of the current stack frame, that is, it restores PC, EP and FP. PC FP EP p e return PC FP EP p e PC = S[FP]; EP = S[FP-2]; SP = FP-3; FP = S[SP+2]; 59 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: return 60 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: the function has n parameters return 60 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: the function has n parameters return the local variables are stored in registers R 1,... R l 60 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: the function has n parameters return the local variables are stored in registers R 1,... R l the parameters of the function are in R 1,... R n 60 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: the function has n parameters return the local variables are stored in registers R 1,... R l the parameters of the function are in R 1,... R n ρ is obtained by extending ρ with the bindings in decls and the function parameters args 60 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: the function has n parameters return the local variables are stored in registers R 1,... R l the parameters of the function are in R 1,... R n ρ is obtained by extending ρ with the bindings in decls and the function parameters args return is not always necessary 60 / 104
Translation of Functions The translation of a function is thus defined as follows: code 1 t r f(args){decls ss} ρ = enter q move R l+1 R 1.. move R l+n R n code l+n+1 ss ρ Assumptions: the function has n parameters return the local variables are stored in registers R 1,... R l the parameters of the function are in R 1,... R n ρ is obtained by extending ρ with the bindings in decls and the function parameters args return is not always necessary Are the move instructions always necessary? 60 / 104
Translation of Whole Programs A program P = F 1 ;... F n must have a single main function. code 1 P ρ = loadc R 1 _main mark call R 1 halt _f 1 : code 1 F 1 ρ ρ f1.. _f n : code 1 F n ρ ρ fn 61 / 104
Translation of Whole Programs A program P = F 1 ;... F n must have a single main function. code 1 P ρ = loadc R 1 _main mark call R 1 halt _f 1 : code 1 F 1 ρ ρ f1.. _f n : code 1 F n ρ ρ fn Assumptions: ρ = assuming that we have no global variables ρ fi contain the addresses the local variables { ρ2 (x) if x dom(ρ ρ 1 ρ 2 = λx. 2 ) ρ 1 (x) otherwise 61 / 104
Translation of the fac-function Consider: int fac(int x) { if (x<=0) then return 1; else return x*fac(x-1); } _fac: enter 5 3 mark+call move R 1 R 1 save param. i = 2 move R 2 R 1 if (x<=0) loadc R 3 0 leq R 2 R 2 R 3 jumpz R 2 _A to else loadc R 2 1 return 1 move R 0 R 2 return jump _B code is dead _A: move R 2 R 1 x*fac(x-1) i = 3 move R 3 R 1 x-1 i = 4 loadc R 4 1 sub R 3 R 3 R 4 i = 3 move R 1 R 3 fac(x-1) loadc R 3 _fac saveloc R 1 R 2 _B: mark call R 3 restoreloc R 1 R 2 move R 3 R 0 mul R 2 R 2 R 3 move R 0 R 2 return return return x*... 62 / 104
Topic: Variables in Memory 63 / 104
Register versus Memory so far: all variables are stored in registers all function parameters and the return value are stored in registers 64 / 104