CS553 Colorado State University ========================================== Register allocation using data-flow analysis ========================================== -------------------- Data-flow analysis - how many registers needed? --> have students determine fewest number of names needed for values - assumptions? - values are read before being written ---------------------- Liveness analysis - things that need to be defined (start list on the board) program point future program point - idea: profile all variable defines and uses on a previous run and then use that information to allocate registers - why won't this work? - We perform liveness analysis on a control flow graph of each procedure. ---------------------- Control Flow Graphs (slides 4 and 5) - control flow graphs represent possible execution order between statements --> what loop construct did this control flow graph come from? ---------------------- Liveness by Example - discuss the live range for b --> what is the live range for a and c? When we see that a variable is used, we know that itŐs live as we move BACKWARDS in the flow graph. When we see that a variable is assigned into, we know that itŐs not live as we move BACKWARDS in the flow graph. ------------------------- More precise definition of liveness (Slides 8-11) The concept of uses and defs provides a more precise definition of liveness. --> what about dereferences to pointers and array accesses? Bases aren't all created equally. Discuss how Y is set up at the beginning of the function and Z is not. ------------------------- Computing Liveness (Slide 11-13) - there is a set of data-flow equations that describe the whole program - they should all be satisfied - want to minimize size of in and out sets --> write set of liveness data-flow equations for the example --> use the iterative solver algorithm to solve the equations ------------------------- Liveness Analysis in the MeggyJava compiler Current steps -parse into an AST -visit AST to allocate space on the stack for locals and space in the heap for member variables -visit AST to generate AVR code To perform data-flow analysis ... -need 3 address code like intermediate representation -each instruction will need to know when defining or using a temporary, local, or parameter -have expressions read from and assign to temporaries instead of using the stack -will need to create control flow graph with each 3-address code instruction as a node ----------------------- Common IR: 3-address code - Non-stack-based IRs are often 3-address code based (Register Transfer Language (RTL), LLVM, ...) - called 3-address code because each operation has at most 3 operands - 3-address code semantics the "addresses" can be any one of the following: -name indicates a named location in memory (all named locations have a base+offset) -constants -compiler temporaries -labels -function calls must indicate how many parameters to grab -conditional branch still has op and 3 addresses, x, y, L1 -labels represent locations in the text -variable names represent locations in stack or data - do an expression example (local1 - local2) + (local3 - local4) -> show AST -> 3 address code t1 = local1 - local2 t2 = local3 - local4 t3 = t1 + t2 - what order should the ast nodes be visited? depth first or reverse depthfirst? pre or post order? - what must the ordering of operations be? -can't we do local1-local2 before or after local3-local4? - how would you generate 3-address code in your MeggyJava compiler? - how could you translate 3-address code to AVR? - discuss issue with temporaries ---------------------------- Example of MeggyJava AST to 3-address code int a; int b; int c; int d; int e; int [] v; int [] z; Foo r; a = b + c + (d+e); v[i] = z[i] * 3 + v.length; r.bar(42); ------------------------- Register Allocation -> architectural registers (ISA) for AVR? - moves, if a variable is assigned to one register in part of the program and another register somewhere else, then might require a move --------------------------- Scope of register allocation Expression a = x + y + 1 t0 = x + y a = t0 + 1 - can use single register, or register pair, in place of all temporaries t0 Local, within a basic block - any upward exposed uses must be loaded from memory - any downward exposed defs must be stored to memory a = x + y b = a ... b used later in flow graph, but a not used later in flow graph Loop, all the basic blocks of a loop - good to keep iterator in register, for example - again need to determine upward exposed uses and downward exposed defs ----------------------------- Granularity --> make three diagrams of different symbolic registers - we are going to focus on variable granularity even though the other two are probably more common, variable is easier to implement ----------------------------- Global register allocation - interference graph is one way to represent a relation that contains node pairs, (n1,n2) in relation --> what does symmetric, reflexive and transitive mean? --> how does knowing these help in implementation? ---------------------------- Interference graph example (slide 20) --> when are the different variables live? --> which variables have interfering live ranges? - var being defined interferes with all variables that are live out ---------------------------- Computing the Interference Graph --> why is the special treatment of moves better? ---------------------------- Allocating Registers using the Interference Graph Assign a single register to all nodes with the same color. --> after constructing the whole interference graph, what could we do with variables involved in copies that could improve register allocation even further? ---------------------------- Spilling (slides 23-25) Spilling means the variable or symbolic register/temporary being spilled will be allocated a spot in memory (e.g. the stack). When used that variable will be loaded from memory and placed into the symbolic register. When defined the symbolic register will be written to memory. In example: After spilling b have two options: - recreate graph (option shown here) and attempt to recolor - keep some registers back to implement spill code and only color graph once ---------------------------- Greedy algorithm for coloring (slides 25-27) The number of registers needed for spills depends on the number of register operands required for a given instruction. ------------------------ mstrout@cs.colostate.edu, 4/26/11