Upload
stacey
View
65
Download
1
Tags:
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
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
2
Special-Purpose Machines
Register Machine
Input Output
a b
rem
t
a, b holdintegers asinput
a holdsgcd(a,b)
Example: gcd register machine
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
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
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!
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
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
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
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
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
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
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!
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
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
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)
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
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
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)
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
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)
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))
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))))
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)))))
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)))))))
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
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
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)
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
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
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)
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!
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
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
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