Presentation is loading. Please wait.

Presentation is loading. Please wait.

6.001 SICP Compilation Context: special purpose vs. universal machines

Similar presentations


Presentation on theme: "6.001 SICP Compilation Context: special purpose vs. universal machines"— Presentation transcript:

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

2 Special-Purpose Machines
Register Machine Input Output a b rem t a, b hold integers as input a holds gcd(a,b) Example: gcd register machine

3 Scheme Evaluator as Universal Machine
MIT Scheme (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 MC-Eval is a Universal Machine
(define (gcd a b) (if (= b 0) a (gcd b (remainder a b)))) (gcd 12 8) 4 MIT Scheme

5 Alternative Language versions possible
Universal Machine MIT Scheme is a C program! C Language version of Scheme Evaluator (gcd 12 8) 4 (define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

6 EC-Eval – Register Machine Code
Universal Machine Universal Register Machine ec-eval: Stored Machine Instructions (define (gcd a b) (if (= b 0) a (gcd b (remainder a b)))) (gcd 12 8) 4

7 Not necessarily a universal machine
Compiler Not necessarily a universal machine gcd: Stored Machine Instructions Universal Register Machine 12 8 4 (define (gcd a b) (if (= b 0) a (gcd b (remainder a b)))) compiler

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
(save continue) (save env) (assign unev (op operands) (reg exp)) (save unev) (assign exp (op operator) (reg exp)) (assign continue (label ev-appl-did-operator)) (goto (label eval-dispatch)) (test (op self-evaluating?) (reg exp)) (branch (label ev-self-eval)) (test (op variable?) (reg exp)) (branch (label ev-variable)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (goto (reg continue)) (restore unev) (restore env) (assign argl (op empty-arglist)) (assign proc (reg val)) (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
(branch (label apply-dispatch)) (save proc) (save argl) (assign exp (op first-operand) (reg unev)) (test (op last-operand?) (reg unev)) (branch (label ev-appl-last-arg)) (assign continue (label ev-appl-accum-last-arg)) (goto (label eval-dispatch)) (test (op self-evaluating?) (reg exp)) (branch (label ev-self-eval)) (test (op variable?) (reg exp)) (branch (label ev-variable)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (goto (reg continue)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) (restore proc) ; computation proceeds at apply-dispatch branch never taken eval each of the operands... figure out how to eval first 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 assign restore
argl proc unev continue val env exp save assign restore reference eliminated syntax instructions used in ec-eval which can be pre-computed by the compiler (save continue) (save env) (assign unev (op operands) (reg exp)) (save unev) (assign exp (op operator) (reg exp)) (assign continue (label ev-appl-did-operator)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (restore unev) (restore env) (assign argl (op empty-arglist)) (assign proc (reg val)) (save proc) (save argl) (assign exp (op first-operand) (reg unev)) (assign continue (label ev-appl-accum-last-arg)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) (restore proc)

14 Don't need continuations:
argl proc unev continue val env exp save assign restore reference no internal branches; don't need to save or assign continue register (save continue) (save env) (assign unev (op operands) (reg exp)) (save unev) (assign exp (op operator) (reg exp)) (assign continue (label ev-appl-did-operator)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (restore unev) (restore env) (assign argl (op empty-arglist)) (assign proc (reg val)) (save proc) (save argl) (assign exp (op first-operand) (reg unev)) (assign continue (label ev-appl-accum-last-arg)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) (restore proc)

15 Recognize form of (f x) save assign restore
argl proc unev continue val env exp save assign restore reference compiler knows operator & operands are variables (ec-eval had to discover this at runtime) (save env) (assign unev (op operands) (reg exp)) (save unev) (assign exp (op operator) (reg exp)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (restore unev) (restore env) (assign argl (op empty-arglist)) (assign proc (reg val)) (save proc) (save argl) (assign exp (op first-operand) (reg unev)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) (restore proc) (const f) (const x)

16 Remove extras saves and restores
argl proc unev continue val env exp save assign restore reference detect when no change to reg between save and restore (save env) (assign val (op lookup-variable-value) (const f) (reg env)) (restore env) (assign argl (op empty-arglist)) (assign proc (reg val)) (save proc) (save argl) (assign val (op lookup-variable-value) (const x) (reg env)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) (restore proc)

17 Optimize Register Target
argl proc unev continue val env exp save assign restore reference assign to proc directly (no need to assign to val, then from val to proc) (assign val (op lookup-variable-value) (const f) (reg env)) (assign argl (op empty-arglist)) (assign proc (reg val)) (save argl) (assign val (op lookup-variable-value) (const x) (reg env)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) proc

18 Optimize argument list
argl proc unev continue val env exp save assign restore reference recognize that we have only one argument (adjoin directly onto empty list argl) (assign proc (op lookup-variable-value) (const f) (reg env)) (assign argl (op empty-arglist)) (save argl) (assign val (op lookup-variable-value) (const x) (reg env)) (restore argl) (assign argl (op list) (reg val))

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) Machine Instruction Sequence (compile exp target linkage) (f x)

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)  (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: Compiled code template:
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) instruction sequence machine statements (machine code) registers modified by sequence needed (used by sequence) "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 (append-instruction-sequences seq-1 seq-2) modifies-1 needs-1 code-1 modifies-1 UNION modifies-2 needs-1 (needs-2 – modifies-1) code-1 code-2 modifies-2 needs-2 code-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 (preserving regs seq-1 seq-2) save regs (needs-2 AND mod-1) modifies-1 needs-1 code-1 needs-1 UNION (needs-2 – modifies-1) modifies-1 UNION modifies-2 code-1 restore modifies-2 needs-2 code-2 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 template as 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 Machine Instruction Sequence decompile Scheme expression (+ 10) Optimization: constant '(10) directly into argl Optimization?: replace whole thing with value 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)) ;; proceed with apply-dispatch pattern

33 Watching ec-eval on (f x) – pg. 1
(save continue) (save env) (assign unev (op operands) (reg exp)) (save unev) (assign exp (op operator) (reg exp)) (assign continue (label ev-appl-did-operator)) (goto (label eval-dispatch)) (test (op self-evaluating?) (reg exp)) (branch (label ev-self-eval)) (test (op variable?) (reg exp)) (branch (label ev-variable)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (goto (reg continue)) (restore unev) (restore env) (assign argl (op empty-arglist)) (assign proc (reg val)) (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
(branch (label apply-dispatch)) (save proc) (save argl) (assign exp (op first-operand) (reg unev)) (test (op last-operand?) (reg unev)) (branch (label ev-appl-last-arg)) (assign continue (label ev-appl-accum-last-arg)) (goto (label eval-dispatch)) (test (op self-evaluating?) (reg exp)) (branch (label ev-self-eval)) (test (op variable?) (reg exp)) (branch (label ev-variable)) (assign val (op lookup-variable-value) (reg exp) (reg env)) (goto (reg continue)) (restore argl) (assign argl (op adjoin-arg) (reg val) (reg argl)) (restore proc) ; computation proceeds at apply-dispatch branch never taken eval each of the operands... figure out how to eval first operand goto accum-last-arg at line 33 add to arg list have proc and argl; ready to apply


Download ppt "6.001 SICP Compilation Context: special purpose vs. universal machines"

Similar presentations


Ads by Google