34
1 6.001 SICP Compilation • Context: special purpose vs. universal machines • Compilation vs. Interpretation • Evolution from ec-eval to compiler • Why is compiled code more efficient than interpreter? • Some ideas in compiler implementation • Target, linkages, & register management

6.001 SICP Compilation

  • Upload
    stacey

  • View
    65

  • Download
    1

Embed Size (px)

DESCRIPTION

6.001 SICP Compilation. Context: special purpose vs. universal machines Compilation vs. Interpretation Evolution from ec-eval to compiler Why is compiled code more efficient than interpreter? Some ideas in compiler implementation Target, linkages, & register management. - PowerPoint PPT Presentation

Citation preview

Page 1: 6.001  SICP Compilation

1

6.001 SICPCompilation

• Context: special purpose vs. universal machines• Compilation vs. Interpretation

• Evolution from ec-eval to compiler• Why is compiled code more efficient than interpreter?

• Some ideas in compiler implementation• Target, linkages, & register management

Page 2: 6.001  SICP Compilation

2

Special-Purpose Machines

Register Machine

Input Output

a b

rem

t

a, b holdintegers asinput

a holdsgcd(a,b)

Example: gcd register machine

Page 3: 6.001  SICP Compilation

3

Universal Machine

MITScheme

Scheme Evaluator as Universal Machine

(gcd 12 8) 4

(define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

• Able to reconfigure (or program) our universal machine to perform the desired computation

Page 4: 6.001  SICP Compilation

4

Universal Machine

mc-eval

MC-Eval is a Universal Machine

(define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

(gcd 12 8) 4

MITScheme

Page 5: 6.001  SICP Compilation

5

Alternative Language versions possible

Universal Machine

(define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

C Languageversion ofScheme

Evaluator

(gcd 12 8) 4

MIT Scheme is a C program!

Page 6: 6.001  SICP Compilation

6

Universal Machine

EC-Eval – Register Machine Code

UniversalRegisterMachine

ec-eval:StoredMachineInstructions

(define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

(gcd 12 8) 4

Page 7: 6.001  SICP Compilation

7

Compiler

UniversalRegisterMachine

12 8 4

gcd:StoredMachineInstructions

(define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

compiler

Not necessarily a universal machine

Page 8: 6.001  SICP Compilation

8

Compilation – A Plan

• Use same register machine as ec-eval... except we don't hard-wire in the ec-eval controller

• Look at the machine instructions that ec-eval used• save these instructions for later execution

• Compiler implementation:• ev-xxx serve as initial template for compile-xxx

• We'll see that this is grossly inefficient• many machine instructions are executed during

interpretation that are not necessary during compilation

• so we will examine compiler ideas that lead us toward more efficient generated machine code

Page 9: 6.001  SICP Compilation

9

Register Machine for Compiler

• 7 registers

• exp temporary register (rarely used)

• env current environment

• continue return point

• val resulting value

• unev temporary register (rarely used)

• proc operator value

• argl argument values

• Abstract operations

• environment model, primitive procedures

• syntax operations now needed by compiler but not in output compiled code

Page 10: 6.001  SICP Compilation

10

Watching ec-eval on (f x) – pg. 1

1. (save continue)2. (save env)3. (assign unev (op operands) (reg exp))4. (save unev)5. (assign exp (op operator) (reg exp))6. (assign continue (label ev-appl-did-operator))7. (goto (label eval-dispatch))8. (test (op self-evaluating?) (reg exp))9. (branch (label ev-self-eval))10. (test (op variable?) (reg exp))11. (branch (label ev-variable))12. (assign val (op lookup-variable-value) (reg exp) (reg env))13. (goto (reg continue))14. (restore unev)15. (restore env)16. (assign argl (op empty-arglist))17. (assign proc (reg val))18. (test (op no-operands?) (reg unev))

prepare to eval operator (save env, operands,continue)

figure out what operator is...

ah, it's a variable so look up

;ev-appl-did-operator

store operator in proc

Page 11: 6.001  SICP Compilation

11

Watching ec-eval on (f x) – pg. 2

20. (branch (label apply-dispatch))21. (save proc)22. (save argl)23. (assign exp (op first-operand) (reg unev))24. (test (op last-operand?) (reg unev))25. (branch (label ev-appl-last-arg))26. (assign continue (label ev-appl-accum-last-arg))27. (goto (label eval-dispatch))28. (test (op self-evaluating?) (reg exp))29. (branch (label ev-self-eval))30. (test (op variable?) (reg exp))31. (branch (label ev-variable))32. (assign val (op lookup-variable-value) (reg exp) (reg env))33. (goto (reg continue))34. (restore argl)35. (assign argl (op adjoin-arg) (reg val) (reg argl))36. (restore proc)

; computation proceeds at apply-dispatch

branch never taken

eval each of the operands...

figure out how to evalfirst operand

goto accum-last-arg at line 33

add to arg list

have proc and argl;ready to apply

Page 12: 6.001  SICP Compilation

12

Key difference: compiling vs. interpreting

• Interpreter/evaluator• See expression for first time at run-time• Have to test to determine what kind of expression

• Compiler:• We see expression at compile-time• Can pre-determine what registers needed or changed

– can be much more efficient in saves/restores!

Page 13: 6.001  SICP Compilation

13

Register Usage – (f x)save

assignrestore

reference

33. (save continue)34. (save env)35. (assign unev (op operands) (reg exp))36. (save unev)37. (assign exp (op operator) (reg exp))38. (assign continue (label ev-appl-did-operator))39. (assign val (op lookup-variable-value) (reg exp) (reg env))40. (restore unev)41. (restore env)42. (assign argl (op empty-arglist))43. (assign proc (reg val))44. (save proc)45. (save argl)46. (assign exp (op first-operand) (reg unev))47. (assign continue (label ev-appl-accum-last-arg))48. (assign val (op lookup-variable-value) (reg exp) (reg env))49. (restore argl)50. (assign argl (op adjoin-arg) (reg val) (reg argl))51. (restore proc)

exp

env

val

contin

ue

unev

proc

argl

• eliminated syntax instructions used in ec-eval which can bepre-computed by the compiler

Page 14: 6.001  SICP Compilation

14

Don't need continuations:save

assignrestore

reference

1. (save continue)2. (save env)3. (assign unev (op operands) (reg exp))4. (save unev)5. (assign exp (op operator) (reg exp))6. (assign continue (label ev-appl-did-operator))33. (assign val (op lookup-variable-value) (reg exp) (reg env))34. (restore unev)35. (restore env)36. (assign argl (op empty-arglist))37. (assign proc (reg val))38. (save proc)39. (save argl)40. (assign exp (op first-operand) (reg unev))41. (assign continue (label ev-appl-accum-last-arg))42. (assign val (op lookup-variable-value) (reg exp) (reg env))43. (restore argl)44. (assign argl (op adjoin-arg) (reg val) (reg argl))45. (restore proc)

exp

env

val

contin

ue

unev

proc

argl

• no internal branches; don't need to save or assign continue register

Page 15: 6.001  SICP Compilation

15

Recognize form of (f x)save

assignrestore

reference

2. (save env)3. (assign unev (op operands) (reg exp))4. (save unev)5. (assign exp (op operator) (reg exp)) 20. (assign val (op lookup-variable-value) (reg exp) (reg env))21. (restore unev)22. (restore env)23. (assign argl (op empty-arglist))24. (assign proc (reg val))25. (save proc)26. (save argl)27. (assign exp (op first-operand) (reg unev)) 33. (assign val (op lookup-variable-value) (reg exp) (reg env))34. (restore argl)35. (assign argl (op adjoin-arg) (reg val) (reg argl))36. (restore proc)

exp

env

val

contin

ue

unev

proc

argl

• compiler knows operator & operands are variables (ec-eval had to discover this at runtime)

(const f)

(const x)

Page 16: 6.001  SICP Compilation

16

Remove extras saves and restoressave

assignrestore

reference

2. (save env) 12. (assign val (op lookup-variable-value) (const f) (reg env)) 20. (restore env)21. (assign argl (op empty-arglist))22. (assign proc (reg val))23. (save proc)24. (save argl) 31. (assign val (op lookup-variable-value) (const x) (reg env))33. (restore argl)34. (assign argl (op adjoin-arg) (reg val) (reg argl))35. (restore proc)

exp

env

val

contin

ue

unev

proc

argl

• detect when no change to reg between save and restore

Page 17: 6.001  SICP Compilation

17

Optimize Register Targetsave

assignrestore

reference

12. (assign val (op lookup-variable-value) (const f) (reg env)) 16. (assign argl (op empty-arglist))17. (assign proc (reg val)) 21. (save argl) 31. (assign val (op lookup-variable-value) (const x) (reg env))33. (restore argl)34. (assign argl (op adjoin-arg) (reg val) (reg argl))

exp

env

val

contin

ue

unev

proc

argl

• assign to proc directly (no needto assign to val, then from val to proc)

proc

Page 18: 6.001  SICP Compilation

18

Optimize argument listsave

assignrestore

reference

12. (assign proc (op lookup-variable-value) (const f) (reg env)) 16. (assign argl (op empty-arglist)) 21. (save argl) 31. (assign val (op lookup-variable-value) (const x) (reg env))33. (restore argl)34. (assign argl (op list) (reg val))

exp

env

val

contin

ue

unev

proc

argl

• recognize that we have only one argument (adjoin directly onto empty list argl)

Page 19: 6.001  SICP Compilation

19

Our compiler: (compile '(f x) 'val 'next) results

; Same three lines from our register usage exercise: (assign proc (op lookup-variable-value) (const f) (reg env))

(assign val (op lookup-variable-value) (const x) (reg env))

(assign argl (op list) (reg val))

; standard pattern for <apply-dispatch> (test (op primitive-procedure?) (reg proc))

(branch (label primitive-branch9))

compiled-branch8

(assign continue (label after-call7))

(assign val (op compiled-procedure-entry) (reg proc))

(goto (reg val))

primitive-branch9

(assign val (op apply-primitive-procedure) (reg proc) (reg argl))

after-call7

; falls through to "next" code

Page 20: 6.001  SICP Compilation

20

Compiler Implementation Concepts

• Instruction Sequences• compile a given expression• produce and append instruction

sequences together as needed

• Target• the register desired to hold value at

end of instruction sequence

• Linkages• how to connect instruction sequence

to other instruction sequences (next, return, named label)

(f x)

MachineInstructionSequence

(compile exp target linkage)

Page 21: 6.001  SICP Compilation

21

Examples – Targets & Linkages

(compile <exp> <target> <linkage>)

• Different Targets:(compile 'x 'val 'next) (assign val (op lookup-variable-value) (const x) (reg env))

(compile 'x 'proc 'next) (assign proc (op lookup-variable-value) (const x) (reg env))

•Linkage 'return:(compile 'x 'val 'return) (assign val (op lookup-variable-value) (const x) (reg env))(goto (reg continue))

•Linkage '<named-label>:(compile 'x 'val 'after-x-lookup) (assign val (op lookup-variable-value) (const x) (reg env))(goto (label after-x-lookup))

Page 22: 6.001  SICP Compilation

22

compiler – dispatch on expression type

(define (compile exp target linkage) (cond ((self-evaluating? exp) (compile-self-evaluating exp target linkage)) ((quoted? exp) (compile-quoted exp target linkage)) ((variable? exp) (compile-variable exp target linkage)) ((assignment? exp) (compile-assignment exp target linkage)) ((definition? exp) (compile-definition exp target linkage)) ((if? exp) (compile-if exp target linkage)) ((lambda? exp) (compile-lambda exp target linkage)) ((begin? exp) (compile-sequence (begin-actions exp) target linkage)) ((application? exp) (compile-application exp target linkage)) (else (error "Unknown exp type -- COMPILE” exp))))

Page 23: 6.001  SICP Compilation

23

Look at a basic case:

• Back in ec-eval, we had:ev-self-eval (assign val (reg exp)) (goto (reg continue))

• Compiled code template: (assign <target> (const <expression>)) <linkage>

• Compiler procedure (partial) that handles linkage:(define (compile-self-evaluating exp target linkage) (end-with-linkage linkage `((assign ,target (const ,exp)))))

Page 24: 6.001  SICP Compilation

24

Compiling Linkages

(define (end-with-linkage linkage instruction-sequence) (preserving '(continue) ;ignore this for now instruction-sequence (compile-linkage linkage)))

(define (compile-linkage linkage) (cond ((eq? linkage 'return) (make-instruction-sequence '(continue) '() '((goto (reg continue)))))

((eq? linkage 'next) (empty-instruction-sequence))

(else (make-instruction-sequence '() '() `((goto (label ,linkage)))))))

Page 25: 6.001  SICP Compilation

25

Compiling Application – More General Case

• In general, may need to save/restore registers;e.g. eval of operator may itself modify env, continue

[(save continue)][(save env)]<evaluate operator; result in proc>[(restore env)][(save proc)]<evaluate operands; result in argl>[(restore proc)][(restore continue)]<apply procedure in proc to args in argl, and link>

• Paranoid/simple approach: save & restore anyway• More efficient approach: manage register usage carefully

Page 26: 6.001  SICP Compilation

26

Managing Registers – Encode the Contract!

; needs: exp expression to evaluate; env environment; continue return point; output: val value of expression; modifies: unev ; stack: unchanged

(make-instruction-sequence needs modifies statements)

machinestatements(machine

code)

registersmodified

by sequence

registersneeded (used by

sequence)

instructionsequence

• "instruction sequence" data structure:• remember registers needed and modified in addition to code

Page 27: 6.001  SICP Compilation

27

Appending Machine Instructions

• If we know code-1 and code-2 don't interfere, just append code• Update merged "needs" and "modifies" data for combined sequence

modifies-1needs-1code-1

modifies-2needs-2code-2

modifies-1UNION

modifies-2

needs-1UNION

(needs-2 –modifies-1)

code-1

code-2

(append-instruction-sequences seq-1 seq-2)

Page 28: 6.001  SICP Compilation

28

Preserving Needed Registers

• A "smart" append of two code sequences which "preserves" registers• save any of specified registers if (and only if) seq-1 clobbers them

modifies-1needs-1code-1

modifies-2needs-2code-2

(preserving regs seq-1 seq-2)save regs(needs-2

ANDmod-1)

modifies-1UNION

modifies-2

needs-1UNION

(needs-2 –modifies-1)

code-1

restore

code-2

Page 29: 6.001  SICP Compilation

29

Now Understand Compile of Application

[(save continue)][(save env)]<evaluate operator; result in proc>[(restore env)][(save proc)]<evaluate operands; result in argl>[(restore proc)][(restore continue)]<apply procedure in proc to args in argl, and link>

(define (compile-application exp target linkage) (let ((proc-code (compile (operator exp) 'proc 'next)) (arg-codes (map (lambda (arg) (compile arg 'val 'next)) (operands exp)))) (preserving '(env continue) proc-code (preserving '(proc continue)

(construct-arglist arg-codes) (compile-procedure-call target linkage)))))

Same templateas before

Page 30: 6.001  SICP Compilation

30

De-compilation & Optimization (assign proc (op lookup-variable-value)

(const +) (reg env))

(assign val (const 10))

(assign argl (op list) (reg val))

(test (op primitive-procedure?) (reg proc))

(branch (label primitive-branch9))

compiled-branch8

(assign continue (label after-call7))

(assign val (op compiled-procedure-entry)

(reg proc))

(goto (reg val))

primitive-branch9

(assign val (op apply-primitive-procedure)

(reg proc) (reg argl))

after-call7

• Optimization: constant '(10) directly into argl• Optimization?: replace whole thing with value 10

MachineInstructionSequence

decompile

Schemeexpression

(+ 10)

Page 31: 6.001  SICP Compilation

31

Summary

• Compilation vs. Interpretation• Interpretation: evaluate expressions at run-time • Compilation: analyze program code and generate

register machine instructions for later execution

• Some ideas in compilation – towards efficient code• Templates, targets & linkages• Strategies for register management• Many further optimizations possible!

Page 32: 6.001  SICP Compilation

32

May 3, 2000 Recitation Problem 6.001

• Decompile the following register code (what expression was compiled to produce these machine instructions)?

(assign proc (op lookup-variable-value) (const list) (reg env))(assign val (op lookup-variable-value) (const y) (reg env))(assign argl (op list) (reg val))(assign val (op lookup-variable-value) (const x) (reg env))(assign argl (op cons) (reg val) (reg argl))(assign val (op lookup-variable-value) (const +) (reg env))(assign argl (op cons) (reg val) (reg argl));; proceed with apply-dispatch pattern

Page 33: 6.001  SICP Compilation

33

Watching ec-eval on (f x) – pg. 1

1. (save continue)2. (save env)3. (assign unev (op operands) (reg exp))4. (save unev)5. (assign exp (op operator) (reg exp))6. (assign continue (label ev-appl-did-operator))7. (goto (label eval-dispatch))8. (test (op self-evaluating?) (reg exp))9. (branch (label ev-self-eval))10. (test (op variable?) (reg exp))11. (branch (label ev-variable))12. (assign val (op lookup-variable-value) (reg exp) (reg env))13. (goto (reg continue))14. (restore unev)15. (restore env)16. (assign argl (op empty-arglist))17. (assign proc (reg val))18. (test (op no-operands?) (reg unev))

prepare to eval operator (save env, operands,continue)

figure out what operator is...

ah, it's a variable so look up

store operand in proc

Page 34: 6.001  SICP Compilation

34

Watching ec-eval on (f x) – pg. 2

20. (branch (label apply-dispatch))21. (save proc)22. (save argl)23. (assign exp (op first-operand) (reg unev))24. (test (op last-operand?) (reg unev))25. (branch (label ev-appl-last-arg))26. (assign continue (label ev-appl-accum-last-arg))27. (goto (label eval-dispatch))28. (test (op self-evaluating?) (reg exp))29. (branch (label ev-self-eval))30. (test (op variable?) (reg exp))31. (branch (label ev-variable))32. (assign val (op lookup-variable-value) (reg exp) (reg env))33. (goto (reg continue))34. (restore argl)35. (assign argl (op adjoin-arg) (reg val) (reg argl))36. (restore proc)

; computation proceeds at apply-dispatch

figure out how to evalfirst operand

add to arg list

have proc and argl;ready to apply

eval each of the operands...

branch never taken

goto accum-last-arg at line 33