380 likes | 511 Views
Code Generation. Professor Yihjia Tsai Tamkang University. Outline. Introduction Run-time Storage Management Basic Blocks Flow Graphs Liveness Analysis Student Presentations. Introduction. Requirements of a code generator Code generated must be correct
E N D
Code Generation Professor Yihjia Tsai Tamkang University
Outline • Introduction • Run-time Storage Management • Basic Blocks • Flow Graphs • Liveness Analysis • Student Presentations
Introduction • Requirements of a code generator • Code generated must be correct • Code generated must be high quality (which uses resources effectively on target machine) • Code must have very low cost (where cost is execution time or code size etc.,…) • Code generator itself must be efficient
Code Generation: Overview • Identify program segments in IR as a dag • Partition the dag into a set of disjoint trees • Machine instructions are (tree) patterns • Each pattern has a cost • Selection of machine instructions means covering (or tiling) each tree of the dag by patterns • So that total cost is the lowest (or very low)
Issues to Consider • What is the input (form of IR)? • May assume input is error-free • What is the target? • Machine, absolute/relocatable/assembly • Memory mgmt. • Names in IR become memory addresses • Instruction selection • Register allocation
Run-time Storage Mgmt. • How to manage activation records? • Static allocation • Position of activation record fixed at compile time • Stack allocation • New activation record pushed onto stack at each invocation of a function • Record popped when activation ends
Static Allocation • A “call” statement in IR implemented by a sequence of 2 target-code instructions • MOV (save return addr in callee activation record ) and a GOTO (to callee code) • Return from callee implemented by GOTO (to location pointed by callee activation record) • Example (E.g. 9.1, p. 523, Dragon book) • Assume “action” instruction takes 20 bytes
Example Activation record for c (64 bytes) 0: return addr • Input: 3AC // code for c action call p action halt // code for p action return 60: j Activation record for p (88 bytes) 0: return addr 84: n
Example …contd // code for c 100: action // c’s activation record 120: MOV #140, 364 300: ….. 132: GOTO 200 304: ….. 140: action ……. 160: halt 360: …. // p’s activation record //code for p 364: … 200: action 368: … 220: GOTO *364 ……. 448: …
Stack Allocation • Uses relative addresses for storage in activation records • Positions not known until run-time • Relative addresses taken as offsets from a known position (e.g., SP register) • Function call: caller increments SP, saves return addr and transfers control to callee • Return: callee transfers control back, caller restores SP
Example // code for s action call q action halt // code for p action return // code for q action call p action call q action call q return Input: 3AC How can we generate code with stack allocation? (Assume: stack grows upwards)
Example …contd // code for s 100: MOV #600, SP 108: action 128: ADD #ssize, SP 136: MOV #152, *SP 144: GOTO 300 152: SUB #ssize, SP 160: action 180: halt // code for p 200: action 220: GOTO *0(SP) // stack starts here 600: #ssize, #qsize : sizes of activation records for s, q
Example …contd // code for q 300: action 320: ADD #qsize, SP 328: MOV #344, *SP 336: GOTO 200 344: SUB #qsize, SP 352: action 372: ADD #qsize, SP 380: MOV #396, *SP 388: GOTO 300 396: SUB #qsize, SP 404: action … // code for p 200: action 220: GOTO *0(SP) // stack starts here 600:
Basic Blocks • A basic block is a sequence of consecutive statements in which flow of control: • Enters at the beginning • Leaves at the end • (no halt or branch except at the end) • Ignore calculations and storage operations • Can lump together non-branch instructions
Algorithm to Obtain Basic Blocks • Input: a program of 3AC statements • Output: a list of basic blocks (each 3AC statement in exactly one basic block) • Determine the set of leaders, i.e., 1st stmts • The 1st stmt of the program is a leader • A target stmt of a GOTO is a leader • A stmt immediately following a GOTO is a leader • For each leader, its basic block ends before next basic block or at the end of program
Exercise • Given the following code segment, obtain: • The 3AC statements for this computation • The list of basic blocks by applying the algorithm to the 3AC prod = 0; i = 1; do { prod = prod + a[i] * b[i]; i = i + 1; } while ( i <= 20 );
Flow Graphs • A directed graph representing a program • Also called control-flow graph • Nodes in the graph represent computation • Each statement (or basic block) is a node • One node is distinguished as initial • Directed edges represent flow of control • There is an edge from node n1 to node n2 if n2 can immediately follow n1 in execution
Flow Graphs …contd • Edge from n1 to n2 exists if: • There is a GOTO from (the last stmt of) n1 to (the 1st stmt of) n2 • n2 immediately follows n1 in the sequence of the program and n1 does not end with GOTO • Here, we say: • n1 a predecessor of n2, n2 a successor of n1 • Example : for code in slide 9-16
Exercise • Draw the flow graph for the following code segment (may consider a stmt as a node) a ← 0 L1: b ← a + 1 c ← c + b a ← b * 2 if a < N goto L1 return c
Liveness Analysis • An example application • IR code (say 3AC) may have large # of temps and program vars • But we have limited # of registers • Need to know which temps/vars are in use at the same time (for efficient use of registers) • A variable is live if it holds a value needed in the future • This analysis is called liveness analysis
Liveness Analysis …contd • Within a basic block context • A var is live at a given point if its value is used after that point (maybe in another basic block) • A var is dead if it is never used later • Liveness analysis is done using a flow graph in which each stmt is a node • We analyze liveness by going backward in a basic block starting from the end
Example 1)a ← 0 2) L1: b ← a + 1 3) c ← c + b 4) a ← b * 2 5) if a < N goto L1 6) return c • Live range of b:{34, 23}, a: {12, 452}, c:{12…6} • Vars a and b can share one register
Liveness Analysis …contd • Next-use info collected in this analysis • Can be used in different situations • Register assignment, temp’s in stack frame • “Use” of a var/name • Suppose stmt i is “x := k”; stmt j has x as an operand; control can flow from i to j with no intervening stmt assigning a value to x • We say stmt jusesvalue of x computed at i
Liveness Analysis …contd • At a stmt k: “x := y <op> z”, check symbol table and update info as follows • Attach to stmt k, current info in symbol table on status (live/dead) & next use for x, y and z • In symbol table, set x to dead and no next use • In symbol table, set y, z to live and their next uses to k • Steps 2 and 3 must be in that order! (because we may have “x := x <op> y”
Example • Suppose we have: “d = (a+b) * (c-b);” • Suppose the 3AC for this is in a basic block as: (1) u := a + b (2) v := c – b (3) w := u * v (4) d := w • Show how the liveness analysis proceeds
Example (1) u := a + b (2) v := c – b (3) w := u * v (4) d := w • At the end of block, in the symbol table • Program vars a, b, c, d are marked “live” • Temp vars u, v, w marked “dead” • All vars marked “no next use”
At the end: Attached Info This info used later during code generation
Dataflow Problems • Liveness of variables flows along edges of flow graps • Determining the live range of each var is an example of a dataflow problem • Other examples • Estimate values of a var at a given point • Finding available expressions and deleting duplicates • Reaching expressions analysis
Storage for Temp’s • Temporary names are generated by the compiler during compilation (e.g., in 3AC) • Temp’s can be held in activation records • But with many temp’s, storage requirement can be large • But we may be able to pack 2 temp’s in the same location if they are not live simultaneously • Next-use info within basic blocks can be used
Transformations on Basic Blocks • A basic block computes a set of expressions that are live on exit from block • Many transformations possible within a block without changing these expressions • Local optimizations • Improve the target code for the block
Example Transformations • Common sub-expression elimination • Dead-code elimination • Suppose x is dead (never used subsequently) at the point of stmt “x = y + z;” in a basic block • Then this stmt can be safely removed
Example Transformations …contd • Constant folding • Sub-expressions whose operands are constants can be replaced by the values at compile-time • Copy propagation • If we have “x = y;” followed later by a use of x as an operand, we may substitute y for x; the copy stmt may become useless code
Example Transformations …contd • Reduction in strength • Replacing expensive operations by cheaper ones • E.g., replace multiplication by two by shifting • Renaming temp variables • Interchange of statements