1 / 70

Code Generation

Code Generation. Compiler Baojian Hua bjhua@ustc.edu.cn. Middle and Back End. translation. AST. IR1. translation. IR2. other IR and translation. asm. Back-end Structure. instruction selector. IR. Assem. register allocator. TempMap. instruction scheduler. Assem. Recap.

gaenor
Télécharger la présentation

Code Generation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Code Generation Compiler Baojian Hua bjhua@ustc.edu.cn

  2. Middle and Back End translation AST IR1 translation IR2 other IR and translation asm

  3. Back-end Structure instruction selector IR Assem register allocator TempMap instruction scheduler Assem

  4. Recap • What about “CODE”? CODE DATA Procedures Global Static Variables Global Dynamic Data Control Flow Local Variables Temporaries Statements Parameter Passing Data Access Read-only Data

  5. A Simpler Target ISA • To simplify the discussion, let’s start with a much simpler ISA---a stack machine • Stack machines once were very popular in the history • but not today, for its low speed • but we’d like to discuss it for: • generating code for stack machine is simpler • many (virtual) stack machines are in widely use today • Pascal P code • Java byte code • Postscript • …

  6. Code Generation for Stack Machines

  7. Stack Machine • Stack-based • no registers • ALU operates the stack and the memory • stack for expression calculation and function call (also called operand stack on JVM) Memory Stack ALU the stack: … Control

  8. Stack Machine ISA // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret A subset of the Java virtual machine language (JVML)! stack operations memory access Memory arithmetic Stack ALU function call and return Control

  9. Frame and Stack Each function comes with two storages: frame and stack • frame: holding arguments, locals and control • stack: computation // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … stack after: Control … 3

  10. ISA Semantics: push push NUM: top++; stack[top] = NUM; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … after: … 3 Control

  11. ISA Semantics: pop pop x: x = stack[top]; top--; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … 3 after: … 3 Control

  12. ISA Semantics: unwind unwind n: top -= n; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … v v … v after: … Control

  13. ISA Semantics: load load x: top++; stack[top] = x; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x x y … before: Stack ALU … after: … Control

  14. ISA Semantics: store store x: x = stack[top]; top--; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … v after: … Control

  15. ISA Semantics: add add: temp = stack[top-1] +stack[top]; top -= 2; push temp; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … 5 1 after: … 6 Control

  16. ISA Semantics: sub sub: temp = stack[top-1] -stack[top]; top -= 2; push temp; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … 5 1 after: … 4 Control

  17. ISA Semantics: mult sub: temp = stack[top-1] *stack[top]; top -= 2; push temp; // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret Memory frame: x y … before: Stack ALU … 5 2 after: … 10 Control

  18. ISA Semantics: call call f: // create a new frame for f // pop all arguments to f’s // frame // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret frame: frame for f: x y … m n … before: before(empty): … 5 2 after: …

  19. ISA Semantics: ret ret: // pop callee’s value and // push it onto the // caller’s stack top // ISA syntax s -> push NUM | pop x | unwind n | load x | store x | add | sub | mult | div | call f | ret frame: frame for f: x y … m n … before: before: … … … … v after: after(empty): …

  20. Extended SLP // Extending SLP with functions: (* is the Kleen // closure) prog -> func* func -> id (x1, …, xn){ s } s -> s; s | x := e | print (es) | return e e -> n | x | e+e | e-e | e*e | e/e | f(es) es-> e, es | \eps

  21. Sample Programs main (){ m := 10; n := 5; z := plus (m, n); print (z); } plus (x, y){ t = x+y; return t; }

  22. Recursive Decedent Code Generation // Invariant: expression’s value is on stack top gen_s (s1; s2) = gen_s (s1); gen_s (s2); gen_s (x := e) = gen_e (e); “store x” gen_s (print (es)) = gen_es (es); “call print” gen_s (return e) = gen_e (e); “ret” gen_e (n) = “push n” gen_e (x) = “load x” gen_e (e1+e2) = gen_e (e1); gen_e (e2); “add” gen_e (…) // similar for -, *, / gen_e (f(es)) = gen_es(es); “call f” gen_es (e; es) = gen_e (e); gen_es (es)

  23. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret main (){ m := 10; n := 5; z := plus (m, n); print (z); } plus (x, y){ t := x+y; return t; }

  24. Example pc 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m n z operand stack(empty) :

  25. Example pc 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m n z operand stack: 10

  26. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret pc frame for main: m n z operand stack: 10

  27. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret pc frame for main: m 10 n z operand stack:

  28. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret pc frame for main: m 10 n z operand stack: 5

  29. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret pc frame for main: m 10 n z operand stack: 5

  30. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret pc frame for main: m 10 n 5 z operand stack:

  31. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret pc frame for main: m 10 n 5 z operand stack: 10

  32. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: pc m 10 n 5 z operand stack: 10 5

  33. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z pc operand stack: 10 5 frame for plus: x y t operand stack:

  34. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z pc operand stack: frame for plus: x 10 y 5 t operand stack: 10

  35. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z operand stack: frame for plus: pc x 10 y 5 t operand stack: 10 5

  36. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z operand stack: frame for plus: x 10 y 5 t pc operand stack: 10 15 5

  37. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z operand stack: frame for plus: x 10 y 5 t operand stack: pc 15

  38. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z operand stack: frame for plus: x 10 y 5 t 15 operand stack: 15 pc

  39. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z operand stack: frame for plus: x 10 y 5 t 15 operand stack: 15 pc

  40. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z operand stack: pc 15 frame for plus: x 10 y 5 t 15 operand stack:

  41. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z 15 operand stack: 15 pc frame for plus: x 10 y 5 t 15 operand stack:

  42. Example 0: push 10 // <- main 1: store m 2: push 5 3: store n 4: load m 5: load n 6: call plus 7: store z 8: load z 9: call print 10: load x // <- plus 11: load y 12: add 13: store t 14: load t 15: ret frame for main: m 10 n 5 z 15 operand stack: 15 pc frame for plus: x 10 y 5 t 15 operand stack:

  43. Run the Stack machine code • Run the code on a real stack machine • if one is lucky to buy one… • Write an interpreter (virtual machine) • just like the JVM • Mimic a stack machine on non-stack machines: • E.g., use the call stack on x86 as the operand stack and the function frame • Or we may create a customized software stack

  44. Mimic stack machine on x86 // gen_s as before gen_e (n) = “pushl $n” gen_e (x) = “pushl x” gen_e (e1+e2) = gen_e (e1) gen_e (e2) “addl 0(%esp), 4(%esp)” “addl $4, %esp” correct?

  45. Mimic stack machine on x86 // gen_s as before gen_e (n) = “pushl $n” gen_e (x) = “pushl x” gen_e (e1+e2) = gen_e (e1) gen_e (e2) “popl %edx” “addl %edx, 0(%esp)”

  46. Better code generation • Generating stack machine code for x86 reveals a serious defect: • the generated code may be too slow • this will be more severe on RISC • which does not operate memory directly, so there may be a lot of “load” and “store” • A better idea is to introduce some registers into the stack machine • and some more instructions

  47. Stack Machine with one Register • Stack-based • but with one register: r Memory Stack ALU the stack: … r Control

  48. Revised Stack Machine ISA // ISA semantics (sample) add: r = stack[top]+r; top--; // ISA syntax v -> NUM | x | r s -> push v | pop v | unwind n | load v | store v | add | sub | mult | div | call f | ret | mov v, v before: 2 … 1 after “add”: … 3

  49. Recursive Decedent Code Generation (revised) // Invariant: expression value is in register “r” gen_s (s1; s2) = gen_s (s1); gen_s (s2); gen_s (x := e) = gen_e (e); “mov r, x” gen_s (print (es)) = gen_es (es); “call print” gen_s (return e) = gen_e(e); “ret” gen_e (n) = “mov n, r” gen_e (x) = “mov x, r” gen_e (e1+e2) = gen_e (e1) “push r” gen_e (e2) “add” gen_e (…) // similar for -, *, / gen_e (s, e) = gen_s (s); gen_e(e) gen_es (e; es) = gen_e (e); “push r”; gen_es (es)

  50. Example 0: mov 10, r // <- main 1: mov r, m 2: mov 5, r 3: mov r, n 4: load m 5: load n 6: call plus 7: mov r, z 8: load z 9: call print 10: mov x, r // <- plus 11: push r 12: mov y, r 13: add 13: mov r, t 14: load t 15: ret main (){ m := 10; n := 5; z := plus (m, n); print (z); } plus (x, y){ t = x+y; return t; }

More Related