2021-04-13 21:17:37 +02:00
|
|
|
(load "util.scm")
|
2021-04-15 18:41:52 +02:00
|
|
|
(load "misc/ch5-compiler.scm")
|
2021-04-13 21:17:37 +02:00
|
|
|
|
2021-04-15 03:47:04 +02:00
|
|
|
(display "\nex-5.31 - save-and-restore-for-apply\n")
|
2021-04-13 21:17:37 +02:00
|
|
|
|
|
|
|
; 1. save and restore env around operator
|
|
|
|
; 2. save and restore env around each operand (except last)
|
|
|
|
; 3. save and restore argl around each operand
|
|
|
|
; 4. save and restore proc around operand sequence
|
|
|
|
|
|
|
|
; (f 'x 'y)
|
|
|
|
; 1-4 are superfluous
|
|
|
|
|
|
|
|
; ((f) 'x 'y)
|
|
|
|
; 1-4 are superfluous
|
|
|
|
; no need to save env because compound-apply without args does
|
|
|
|
; not change env
|
|
|
|
|
|
|
|
; (f (g 'x) y)
|
|
|
|
; 1 is superfluous
|
|
|
|
; we need 2 because (g 'x) changes the env for y
|
|
|
|
; we need 3 because (g 'x) changes argl
|
|
|
|
; we need 4 because (g 'x) changes proc
|
|
|
|
|
|
|
|
; (f (g 'x) 'y) ; 1 is superfluous
|
|
|
|
; 1-2 are superfluous
|
|
|
|
; (g 'x) changes the env but we don't need it later (better save it anyway)
|
|
|
|
; 3-4 are still needed
|
|
|
|
|
|
|
|
(display "[answered]\n")
|
|
|
|
|
2021-04-15 03:47:04 +02:00
|
|
|
(display "\nex-5.32 - optimize-eceval-application\n")
|
|
|
|
|
|
|
|
'(
|
|
|
|
ev-application
|
|
|
|
(save continue)
|
|
|
|
(assign unev (op operands) (reg exp))
|
|
|
|
(assign exp (op operator) (reg exp))
|
|
|
|
(assign continue (label ev-appl-did-operator-no-restore))
|
|
|
|
(test (op variable?) (reg exp))
|
|
|
|
(branch (label ev-variable))
|
|
|
|
(save env)
|
|
|
|
(save unev)
|
|
|
|
(assign continue (label ev-appl-did-operator))
|
|
|
|
(goto (label eval-dispatch))
|
|
|
|
ev-appl-did-operator
|
|
|
|
(restore unev)
|
|
|
|
(restore env)
|
|
|
|
ev-appl-did-operator-no-restore
|
|
|
|
(assign argl (op empty-arglist))
|
|
|
|
(assign proc (reg val))
|
|
|
|
(test (op no-operands?) (reg unev))
|
|
|
|
(branch (label apply-dispatch))
|
|
|
|
(save proc)
|
|
|
|
)
|
|
|
|
|
|
|
|
(display "[ok]\n")
|
|
|
|
|
|
|
|
; b. Applying all the optimizations make sense, but the compiled code will
|
|
|
|
; still run faster because the interpreter has to analyze the code every time
|
|
|
|
; it executes and the analysis itself adds overhead that the compiler can do
|
|
|
|
; before runtime
|
|
|
|
(display "[answered]\n")
|
2021-04-13 21:17:37 +02:00
|
|
|
|
|
|
|
|
2021-04-15 18:41:52 +02:00
|
|
|
(display "\nex-5.33 - compare-factorial-definitions\n")
|
|
|
|
|
|
|
|
(define (compile-to-file code target linkage file-name)
|
2021-04-17 01:23:29 +02:00
|
|
|
(set! label-counter 0)
|
2021-04-15 18:41:52 +02:00
|
|
|
(define (write-list-to-port xs port)
|
|
|
|
(if (null? xs)
|
|
|
|
'()
|
|
|
|
(begin
|
|
|
|
(display (car xs) port)
|
|
|
|
(display "\n" port)
|
|
|
|
(write-list-to-port (cdr xs) port))))
|
|
|
|
(let* ((compile-result (compile code target linkage))
|
|
|
|
(assembly-insts (statements compile-result))
|
|
|
|
(port (open-output-file file-name)))
|
|
|
|
(write-list-to-port assembly-insts port)
|
|
|
|
(display "[")
|
|
|
|
(display file-name)
|
|
|
|
(display "]\n")
|
|
|
|
(close-output-port port)))
|
|
|
|
|
|
|
|
; Uncomment the following lines to write the assembly code for the to methods
|
|
|
|
; into files.
|
|
|
|
|
2021-04-17 01:23:29 +02:00
|
|
|
(compile-to-file
|
|
|
|
'(define (factorial n)
|
|
|
|
(if (= n 1)
|
|
|
|
1
|
|
|
|
(* (factorial (- n 1)) n)))
|
|
|
|
'val 'next "factorial.sicp-asm")
|
|
|
|
|
|
|
|
;(define label-counter 0)
|
|
|
|
|
|
|
|
(compile-to-file
|
|
|
|
'(define (factorial-alt n)
|
|
|
|
(if (= n 1)
|
|
|
|
1
|
|
|
|
(* n (factorial-alt (- n 1)))))
|
|
|
|
'val 'next "factorial-alt.sicp-asm")
|
2021-04-15 18:41:52 +02:00
|
|
|
;(define label-counter 0)
|
|
|
|
|
|
|
|
; $ diff factorial.sicp-asm factorial-alt.sicp-asm
|
|
|
|
; 33,36c33,34
|
|
|
|
; < (assign val (op lookup-variable-value) (const n) (reg env))
|
|
|
|
; < (assign argl (op list) (reg val))
|
|
|
|
; < (save argl)
|
|
|
|
; ---
|
|
|
|
; > (save env)
|
|
|
|
; > (assign proc (op lookup-variable-value) (const factorial-alt) (reg env))
|
|
|
|
; 63c61,63
|
|
|
|
; < (restore argl)
|
|
|
|
; ---
|
|
|
|
; > (assign argl (op list) (reg val))
|
|
|
|
; > (restore env)
|
|
|
|
; > (assign val (op lookup-variable-value) (const n) (reg env))
|
|
|
|
|
2021-04-17 01:23:29 +02:00
|
|
|
; The regular factorial needs an additional save-and-restore for argl before
|
|
|
|
; the recursive call. Argl must be saved because it contains the value of n
|
|
|
|
; before the recursive call.
|
|
|
|
|
|
|
|
; The alternative factorial needs an additional save-and-restore for env before
|
|
|
|
; the recursive call. Env must be saved for other the evaluation of the
|
|
|
|
; remaining arguments. In this case, the look-up of n which comes second for
|
|
|
|
; the alternative implementation.
|
|
|
|
|
|
|
|
; Neither version executes more efficiently and they have the same number of
|
|
|
|
; instructions.
|
|
|
|
|
|
|
|
(display "[answered]\n")
|
|
|
|
|
|
|
|
(display "\nex-5.34 - factorial-iter\n")
|
|
|
|
(compile-to-file
|
|
|
|
'(define (factorial n)
|
|
|
|
(define (iter product counter)
|
|
|
|
(if (> counter n)
|
|
|
|
product
|
|
|
|
(iter (* counter product)
|
|
|
|
(+ counter 1))))
|
|
|
|
(iter 1 1))
|
|
|
|
'val 'next "factorial-iter.sicp-asm")
|
2021-04-15 03:47:04 +02:00
|
|
|
|
2021-04-15 18:41:52 +02:00
|
|
|
|
|
|
|
(display "\nex-5.35\n")
|
2021-04-15 03:47:04 +02:00
|
|
|
|