cse322, programming languages and compilers 1 7/13/2015 lecture #2, april 5, 2007 overview of...
Post on 22-Dec-2015
214 views
TRANSCRIPT
Cse322, Programming Languages and Compilers
104/19/23
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.
Cse322, Programming Languages and Compilers
204/19/23
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.
Cse322, Programming Languages and Compilers
304/19/23
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
Cse322, Programming Languages and Compilers
404/19/23
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
Cse322, Programming Languages and Compilers
504/19/23
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.
Cse322, Programming Languages and Compilers
604/19/23
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?
Cse322, Programming Languages and Compilers
704/19/23
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)
Cse322, Programming Languages and Compilers
804/19/23
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
loadAOload at offset
Cse322, Programming Languages and Compilers
904/19/23
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.
Cse322, Programming Languages and Compilers
1004/19/23
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() *)
Cse322, Programming Languages and Compilers
1104/19/23
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
Cse322, Programming Languages and Compilers
1204/19/23
CompareThe 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 => r1loadAO rA,r1 => r2loadI 2 => r3loadI @y => r4loadAO rA,r4 => r5Mul r3,r5 => r6Sub r2,r6 => r7
Cse322, Programming Languages and Compilers
1304/19/23
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
Cse322, Programming Languages and Compilers
1404/19/23
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”
Cse322, Programming Languages and Compilers
1504/19/23
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 "
Cse322, Programming Languages and Compilers
1604/19/23
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;
•
Cse322, Programming Languages and Compilers
1704/19/23
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.
Cse322, Programming Languages and Compilers
1804/19/23
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;
Cse322, Programming Languages and Compilers
1904/19/23
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.
Cse322, Programming Languages and Compilers
2004/19/23
fun offset (Var(_,x)) =
let val result = NextRegister()
in emit (LoadI("@"^x,result));
result
end;
fun base x = Rarp;
Cse322, Programming Languages and Compilers
2104/19/23
Translationfun 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
Cse322, Programming Languages and Compilers
2204/19/23
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"));
Cse322, Programming Languages and Compilers
2304/19/23
- trans ex1;
loadI @x => r1loadAO rA,r1 => r2loadI 2 => r3loadI @y => r4loadAO rA,r4 => r5Mul r3,r5 => r6Sub 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
Cse322, Programming Languages and Compilers
2404/19/23
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
Cse322, Programming Languages and Compilers
2504/19/23
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}
Cse322, Programming Languages and Compilers
2604/19/23
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
Cse322, Programming Languages and Compilers
2704/19/23
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
Cse322, Programming Languages and Compilers
2804/19/23
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
Cse322, Programming Languages and Compilers
2904/19/23
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
Cse322, Programming Languages and Compilers
3004/19/23
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
Cse322, Programming Languages and Compilers
3104/19/23
Variable reuse.
• Consider translating x – (2 * x)
loadI @x => r1loadAO rA,r1 => r2loadI 2 => r3loadI @x => r4loadAO rA,r4 => r5Mul r3,r5 => r6Sub r2,r6 => r7
loadI @x => r1loadAO rA,r1 => r2loadI 2 => r3Mul r3,r2 => r4Sub r2,r4 => r5
loadI @x => r1loadAO rA,r1 => r1loadI 2 => r2Mul r2,r1 => r1Sub r2,r1 => r1
Register allocation
Cse322, Programming Languages and Compilers
3204/19/23
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
Cse322, Programming Languages and Compilers
3304/19/23
Using the dictionaryfun 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)
Cse322, Programming Languages and Compilers
3404/19/23
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
Cse322, Programming Languages and Compilers
3504/19/23
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?
Cse322, Programming Languages and Compilers
3604/19/23
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
Cse322, Programming Languages and Compilers
3704/19/23
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
Cse322, Programming Languages and Compilers
3804/19/23
Assignment #1CS322 Prog Lang & Compilers Prog Assignment #1Assigned Wednesday April 5, 2007. Due Monday, April 10, 2007
This assignment is to extend the program discussed in class fortranslating Arithmetic expressions to IR code. The extension is toevaluate binary operators in a manner that decreases the number ofregisters needed. The rule of thumb is that given a binary operator(exp1 + exp2) we should first translate the sub expression (eitherexp1 or exp2) that is more demanding. I.e. we should translate firstthe sub expression that when translated will require the mostregisters.
See the assignments link on the class web page for a full description.