Download presentation
Presentation is loading. Please wait.
1
Cse322, Programming Languages and Compilers 1 7/13/2015 Lecture #2, April 5, 2007 Overview of backend issues (storage locations, registers, aliasing), Translating arithmetic, Register allocation, Reducing demand for registers, Reuse of registers, List.find, Anonymous functions.
2
Cse322, Programming Languages and Compilers 2 7/13/2015 Assignments Reading –Read chapter 7 sections 7.4 and 7.5 –Possible Quiz next Monday on the reading. Programming assignment #1 is now available on the class website under the assignments link. PLEASE take note of this as this page is not in the handout.
3
Cse322, Programming Languages and Compilers 3 7/13/2015 Over view of Back-end issues Code Shape –How to choose the correct shape for a language construct »Case – cascading if then else, binary search, dispatch table »Commutative associative operators Instruction Choice –Which assembly level instructions to use Register allocation –How to use registers vs memory Instruction scheduling –Reording instructions
4
Cse322, Programming Languages and Compilers 4 7/13/2015 Assigning Storage Locations Lifetime and scope determine some storage issues –Parameters –Local variables –Global variables –Scoped variables »Static scope in block structured languages »Overridden instance variables in OO languages –Un-named values (x+3) in y = (x+3) * z
5
Cse322, Programming Languages and Compilers 5 7/13/2015 Registers Limited numbers, requires resource allocation Not all values fit in a register Some variables (with short lifetimes) only live in registers Others need to be “stored” when the register is needed for another purpose. Locations whose “address” is needed (for call by reference, or for pointer-to uses) cannot reside in registers.
6
Cse322, Programming Languages and Compilers 6 7/13/2015 Aliasing Sometimes there are more than 1 name for a location. Pointers int a, *b; b = &a; Reference parameters int f(ref int a, ref int b) { int c; c := a; a := b; b := c } call f(x,x) Array References Are x[i] and x[j-n] different?
7
Cse322, Programming Languages and Compilers 7 7/13/2015 Translating Arithmetic Most machines have a full complement of arithmetic, logical, and shifting operations. Such operations are almost always register based. Translating requires. –Getting values in registers –Choosing an order to perform operations –Emitting instructions Subtleties –Using the fewest registers –Constant folding ie. (x + 3 + 5) -> (x + 8)
8
Cse322, Programming Languages and Compilers 8 7/13/2015 Consider loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 loadI @y => r4 loadAO rA,r4 => r5 Mul r3,r5 => r6 Sub r2,r6 => r7 - x * 2 y loadAO load at offset
9
Cse322, Programming Languages and Compilers 9 7/13/2015 Creating an algorithm Design data structures to hold source (expressions) and target code (IR). Decide how to treat registers Decide how to deal with generating IR sequences.
10
Cse322, Programming Languages and Compilers 10 7/13/2015 Expressions We will reuse the Exp datatype from CS321 datatype Exp = Literal of Constant (* 5, 6.3, true *) | Binop of BINOP * Exp * Exp (* x + 3 *) | Var of Exp option * Id (* object.x, y *) | Relop of RELOP * Exp * Exp (* x < 7.7 *) | Not of Exp (* ! x *) | ArrayElm of Exp * Exp * (Basic TC) (* x[3] *) | ArrayLen of Exp (* x.length() *) | Call of Exp * Id *(Id TC)* Exp list (* x.f(1,z) *) | NewArray of Basic * Exp (* new int[3] *) | NewObject of Id (* new point() *)
11
Cse322, Programming Languages and Compilers 11 7/13/2015 IR and Registers We define a new ML datatype for IR –For today it will only have three general kinds of instructions type Reg = int; datatype IR = LoadI of (string * Reg) | LoadAO of (Reg * Reg * Reg) | Arith of (BINOP * Reg * Reg * Reg); datatype BINOP = ADD | SUB | MUL | DIV (* Arithmetic *) | AND | OR; (* logical *) BINOP is reused from the CS321 as well
12
Cse322, Programming Languages and Compilers 12 7/13/2015 Compare The abstract syntax datatype IR = LoadI of (string * Reg) | LoadAO of (Reg * Reg * Reg) | Arith of (BINOP * Reg * Reg * Reg); With the concrete syntax loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 loadI @y => r4 loadAO rA,r4 => r5 Mul r3,r5 => r6 Sub r2,r6 => r7
13
Cse322, Programming Languages and Compilers 13 7/13/2015 Computing the concrete Syntax We can write a pattern matching ML program to compute the concrete syntax from the datatype representing the abstract syntax. It is an ordinary pattern-matching ML program. datatype IR = LoadI of (string * Reg) | LoadAO of (Reg * Reg * Reg) | Arith of (BINOP * Reg * Reg * Reg); We will need to write three parts –Converting registers to strings –Converting BINOP to strings –Converting IR itself to a string
14
Cse322, Programming Languages and Compilers 14 7/13/2015 Registers to strings type Reg = int; fun showReg 0 = "rA" | showReg n = "r"^Int.toString n; A register is just an integer, we can use the library function int.toString to turn it into a string We use the convention that register 0 is the activation record pointer, which we print as “rA” Other registers print the integer value preceded by “r”
15
Cse322, Programming Languages and Compilers 15 7/13/2015 Op to string A very simple pattern match across the 6 cases. fun showOp ADD = "Add " | showOp SUB = "Sub " | showOp MUL = "Mul " | showOp DIV = "Div " | showOp AND = "And " | showOp OR = "Or "
16
Cse322, Programming Languages and Compilers 16 7/13/2015 IR to string Note the extensive use of “^” the string concatenation function. fun showIR (LoadI(s,r)) = "loadI "^s^" => "^showReg r | showIR (LoadAO(x,y,z)) = "loadAO "^showReg x^","^showReg y^" => "^ showReg z | showIR (Arith(m,x,y,z)) = showOp m^" "^showReg x^","^ showReg y^" => "^showReg z;
17
Cse322, Programming Languages and Compilers 17 7/13/2015 Emitting instructions Emitting instructions is an effect. It is implicit in the functions “expr”, “base”, and “offsett”. Instructions are accumulated in the reference variable “emitted” val emitted = ref ([]: IR list); fun emit x = emitted := (x :: (!emitted)); Note that the instructions are accumulated in the reverse order they are emitted.
18
Cse322, Programming Languages and Compilers 18 7/13/2015 Registers Registers are nothing more than integers. We need a way to allocate them incrementally We need to be able to reset the allocation. val Rarp = 0; val firstRegister = 1; val regCount = ref firstRegister; fun resetRegister () = regCount := firstRegister; fun NextRegister() = let val n = !regCount in (regCount := n+1; n) end;
19
Cse322, Programming Languages and Compilers 19 7/13/2015 Base and offsett We assume that all variables can be accessed as an offset from some base address. The function “base” loads the base address for a variable into a register by emitting the correct code and then returns the register. The function “offset” loads the offset into a register by emitting code, and then returns the register. For simplicity –The base address is always assumed stored in the activation record pointer stored in register 0, which we write “ra” –The offset is some constant we write as “@x” for variable “x”, i.e. the address or offset for “x” –Later on we will relax these assumptions.
20
Cse322, Programming Languages and Compilers 20 7/13/2015 fun offset (Var(_,x)) = let val result = NextRegister() in emit (LoadI("@"^x,result)); result end; fun base x = Rarp;
21
Cse322, Programming Languages and Compilers 21 7/13/2015 Translation fun expr node = case node of Var(loc,x) => let val t1 = base node val t2 = offset node val result = NextRegister() in emit (LoadAO(t1,t2,result)); result end | Binop(m,x,y) => let val t1 = expr x val t2 = expr y val result = NextRegister() in emit (Arith(m,t1,t2,result)); result end | Literal(loc,Cint n) => let val result = NextRegister() in emit (LoadI(n,result)); result end
22
Cse322, Programming Languages and Compilers 22 7/13/2015 Results fun var x = (Var(NONE,x)); fun const n = Literal(Cint n); val ex1 = Binop(SUB, (* x – (2 * y) *) var "x", Binop(MUL, const 2, var "y"));
23
Cse322, Programming Languages and Compilers 23 7/13/2015 - trans ex1; loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 loadI @y => r4 loadAO rA,r4 => r5 Mul r3,r5 => r6 Sub r2,r6 => r7 val it = [LoadI ("@x",1),LoadAO (0,1,2),LoadI ("2",3), LoadI ("@y",4),LoadAO (Arith (MUL,3,5,6), Arith (SUB,2,6,7)] : IR list
24
Cse322, Programming Languages and Compilers 24 7/13/2015 The function trans fun trans x = let val _ = emitted := [] val _ = resetRegister () val result = expr x val instrs = rev (!emitted) val _ = print "\n"; fun sh x = print(showIR x^"\n") val _ = map sh instrs val _ = print "\n\n"; in instrs end; Reset the emitted instructions and the next register counter The emiited instructions are collected in reverse order Print the instructions for the user to inspect
25
Cse322, Programming Languages and Compilers 25 7/13/2015 Register Allocation Register allocation assigns physical registers to each logical registers. Think of it as a renaming, where we have a limited number of names. We can reuse a register after we have no further demands on it. no further demand loadI @x => r1 { } loadAO rA,r1 => r2 {r1} loadI 2 => r3 {r1} loadI @y => r4 {r1} loadAO rA,r4 => r5 {r1,r4} Mul r3,r5 => r6 {r1,r3,r4,r5} Sub r2,r6 => r7 {r1,r2,r3,r4,r5,r6}
26
Cse322, Programming Languages and Compilers 26 7/13/2015 Immediate reuse. loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 loadI @y => r4 loadAO rA,r4 => r5 Mul r3,r5 => r6 Sub r2,r6 => r7 loadI @x => r1 loadAO rA,r1 => r1 loadI 2 => r2 loadI @y => r3 loadAO rA,r3 => r3 Mul r2,r3 => r2 Sub r1,r2 => r2
27
Cse322, Programming Languages and Compilers 27 7/13/2015 Can we do better? x – (2 * y) Loading x first (before computing (2 * y)) causes the lifetime of r2 to be very long. Suppose we translated (2*y) before x? loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 loadI @y => r4 loadAO rA,r4 => r5 Mul r3,r5 => r6 Sub r2,r6 => r7
28
Cse322, Programming Languages and Compilers 28 7/13/2015 Translating (2 * y) first loadI @y => r1 loadAO rA,r1 => r2 loadI 2 => r3 Mul r2,r3 => r4 loadI @x => r5 loadAO rA,r5 => r6 Sub r4,r6 => r7 loadI @y => r1 loadAO rA,r1 => r1 loadI 2 => r2 Mul r2,r1 => r1 loadI @x => r2 loadAO rA,r2 => r2 Sub r2,r1 => r1 Before register allocation After register allocation
29
Cse322, Programming Languages and Compilers 29 7/13/2015 Compare loadI @y => r1 loadAO rA,r1 => r1 loadI 2 => r2 Mul r2,r1 => r1 loadI @x => r2 loadAO rA,r2 => r2 Sub r2,r1 => r1 loadI @x => r1 loadAO rA,r1 => r1 loadI 2 => r2 loadI @y => r3 loadAO rA,r3 => r3 Mul r2,r3 => r2 Sub r1,r2 => r2 Translating x first translating (2 * y) first
30
Cse322, Programming Languages and Compilers 30 7/13/2015 Rule of thumb To avoid tying up registers for a long time, we should translate subexpressions which are large first. How do we determine large? An expression is larger than another expression, it requires more registers to translate. Chicken an egg problem. –To translate we need to know how many registers –To know how many registers we need to translate –Solution »Pre-processing »Dynamic exploration
31
Cse322, Programming Languages and Compilers 31 7/13/2015 Variable reuse. Consider translating x – (2 * x) loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 loadI @x => r4 loadAO rA,r4 => r5 Mul r3,r5 => r6 Sub r2,r6 => r7 loadI @x => r1 loadAO rA,r1 => r2 loadI 2 => r3 Mul r3,r2 => r4 Sub r2,r4 => r5 loadI @x => r1 loadAO rA,r1 => r1 loadI 2 => r2 Mul r2,r1 => r1 Sub r2,r1 => r1 Register allocation
32
Cse322, Programming Languages and Compilers 32 7/13/2015 How could we implement this? If we kept a dictionary of which register (if any) a variable resides in, we could try this first in the Var case of “expr” case node of Var(loc,x) => let val t1 = base node val t2 = offset node val result = NextRegister() in emit (LoadAO(t1,t2,result)); result end
33
Cse322, Programming Languages and Compilers 33 7/13/2015 Using the dictionary fun expr2 dict node = case node of Var(loc,x) => (case List.find (fn (nm,r) => x=nm) (!dict) of NONE => let val t1 = base node val t2 = offset node val result = NextRegister() in emit (LoadAO(t1,t2,result)); dict := (x,result)::(!dict); result end | SOME(x,r) => r)
34
Cse322, Programming Languages and Compilers 34 7/13/2015 The List.find programming pattern Case List.find (fn (nm,r) => x=nm) (!dict) of NONE => … | SOME(_,z) => … In SML we use library functions all the time. –Int.toString –List.find The List.find function is particularly useful. –It takes a function as an argument –List.find : ('a -> bool) -> 'a list -> 'a option – It is worth studying this function closely
35
Cse322, Programming Languages and Compilers 35 7/13/2015 Anonymous functions Study: (fn x => (x+1)) –It is an anonymous function. A function without a name. –It has one parameter “x” –It adds one to its parameter, and returns the result. (fn x => (x+1)) 4; val it = 5 : int Any non-recursive function can be written anonymously. –(fn x => x = 5) »Tests if its parameter is equal to 5 (fn x => x=5) 8; val it = false : bool; –(fn x => fn y => (x,y)) »Has two parameters »Returns a pair –(fn (x,y) => (not y, x+3)) »What is the type of this function?
36
Cse322, Programming Languages and Compilers 36 7/13/2015 List.find Used for searching a list. –List.find : ('a -> bool) -> 'a list -> 'a option Uses a function as a parameter to determine if the search is successful. E.g. Is there an even element in a list? List.find even [1,3,5]; val it = NONE : int option List.find even [1,3,4]; val it = SOME 4 : int option
37
Cse322, Programming Languages and Compilers 37 7/13/2015 List.find and anonymous functions List.find (fn x => x = "Tim") ["Tom", "Jane"]; val it = NONE : string option List.find (fn x => even x andalso x>10) [2,4,5,12]; val it = SOME 12 : int option
38
Cse322, Programming Languages and Compilers 38 7/13/2015 Assignment #1 CS322 Prog Lang & Compilers Prog Assignment #1 Assigned Wednesday April 5, 2007. Due Monday, April 10, 2007 This assignment is to extend the program discussed in class for translating Arithmetic expressions to IR code. The extension is to evaluate binary operators in a manner that decreases the number of registers needed. The rule of thumb is that given a binary operator (exp1 + exp2) we should first translate the sub expression (either exp1 or exp2) that is more demanding. I.e. we should translate first the sub expression that when translated will require the most registers. See the assignments link on the class web page for a full description.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.