Answer till 5.36

This commit is contained in:
2021-04-17 10:01:16 -04:00
parent 3d832af911
commit e75eb75df4

View File

@@ -93,15 +93,12 @@ ev-appl-did-operator-no-restore
(* (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")
;(define label-counter 0)
; $ diff factorial.sicp-asm factorial-alt.sicp-asm
; 33,36c33,34
@@ -133,6 +130,7 @@ ev-appl-did-operator-no-restore
(display "[answered]\n")
(display "\nex-5.34 - factorial-iter\n")
(compile-to-file
'(define (factorial n)
(define (iter product counter)
@@ -143,6 +141,210 @@ ev-appl-did-operator-no-restore
(iter 1 1))
'val 'next "factorial-iter.sicp-asm")
; ;; construct code for factorial
; (assign val (op make-compiled-procedure) (label entry2) (reg env))
; (goto (label after-lambda1))
;
; ;; entry to factorial
; entry2
; (assign env (op compiled-procedure-env) (reg proc))
; (assign env (op extend-environment) (const (n)) (reg argl) (reg env))
;
; ;; construct the iter procedure within factorial
; (assign val (op make-compiled-procedure) (label entry7) (reg env))
; (goto (label after-lambda6))
;
; ;; entry to iter
; entry7
; (assign env (op compiled-procedure-env) (reg proc))
; (assign env (op extend-environment) (const (product counter)) (reg argl) (reg env))
; (save continue)
; (save env)
; (assign proc (op lookup-variable-value) (const >) (reg env))
; (assign val (op lookup-variable-value) (const n) (reg env))
; (assign argl (op list) (reg val))
; (assign val (op lookup-variable-value) (const counter) (reg env))
; (assign argl (op cons) (reg val) (reg argl))
; (test (op primitive-procedure?) (reg proc))
; (branch (label primitive-branch22))
;
; ;; dead code
; compiled-branch21
; (assign continue (label after-call20))
; (assign val (op compiled-procedure-entry) (reg proc))
; (goto (reg val))
; ;; dead code end
;
; primitive-branch22
; (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
; after-call20
; (restore env)
; (restore continue)
; (test (op false?) (reg val))
; (branch (label false-branch9))
;
; true-branch10
; ;; load end result into val and return
; (assign val (op lookup-variable-value) (const product) (reg env))
; (goto (reg continue))
;
; false-branch9
; ;; setup for next iteration
; (assign proc (op lookup-variable-value) (const iter) (reg env))
; (save continue)
; (save proc)
; (save env)
;
; ;; compute first argument for iter call
; (assign proc (op lookup-variable-value) (const +) (reg env))
; (assign val (const 1))
; (assign argl (op list) (reg val))
; (assign val (op lookup-variable-value) (const counter) (reg env))
; (assign argl (op cons) (reg val) (reg argl))
; (test (op primitive-procedure?) (reg proc))
; (branch (label primitive-branch16))
; compiled-branch15
; (assign continue (label after-call14))
; (assign val (op compiled-procedure-entry) (reg proc))
; (goto (reg val))
; primitive-branch16
; (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
; after-call14
; (assign argl (op list) (reg val))
;
; ;; compute second argument for iter call
; (restore env)
; (save argl)
; (assign proc (op lookup-variable-value) (const *) (reg env))
; (assign val (op lookup-variable-value) (const product) (reg env))
; (assign argl (op list) (reg val))
; (assign val (op lookup-variable-value) (const counter) (reg env))
; (assign argl (op cons) (reg val) (reg argl))
; (test (op primitive-procedure?) (reg proc))
; (branch (label primitive-branch13))
; compiled-branch12
; (assign continue (label after-call11))
; (assign val (op compiled-procedure-entry) (reg proc))
; (goto (reg val))
; primitive-branch13
; (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
;
; after-call11
; (restore argl)
; (assign argl (op cons) (reg val) (reg argl))
;
; ;; prepare for tail-recursive call to iter
; (restore proc)
; ;; restore the original continue label
; (restore continue)
; (test (op primitive-procedure?) (reg proc))
; (branch (label primitive-branch19))
; compiled-branch18
; (assign val (op compiled-procedure-entry) (reg proc))
; ;; jump to entry of iter
; (goto (reg val))
; primitive-branch19
; (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
; (goto (reg continue))
; after-call17
; after-if8
; after-lambda6
; ;; after definition of iter
; (perform (op define-variable!) (const iter) (reg val) (reg env))
; (assign val (const ok))
;
; ;; call iter with the initial arguments
; (assign proc (op lookup-variable-value) (const iter) (reg env))
; (assign val (const 1))
; (assign argl (op list) (reg val))
; (assign val (const 1))
; (assign argl (op cons) (reg val) (reg argl))
; (test (op primitive-procedure?) (reg proc))
; (branch (label primitive-branch5))
; compiled-branch4
; (assign val (op compiled-procedure-entry) (reg proc))
; (goto (reg val)) ;; jump to entry of iter
; ;; primitive branch not taken
; primitive-branch5
; (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
; (goto (reg continue))
; after-call3
; after-lambda1
; ;; after definition of factorial
; (perform (op define-variable!) (const factorial) (reg val) (reg env))
; (assign val (const ok))
(display "\nex-5.35\n")
; The iterative procedure restores the continue register before the next
; recursive call to iter. This allows the based case to return directly to the
; original caller of factorial. The recursive implementation requires each call
; to return to the original to the previous caller which builds up the stack.
(display "[answered]\n")
(display "\nex-5.35 - reverse-engineer-compiled-procedure\n")
(compile-to-file
'(define (f x)
(+ x (g (+ x 2))))
'val 'next "f-reversed.sicp-asm")
(display "[ok]\n")
(display "\nex-5.36 - order-of-evaluation\n")
; The compiler produces code the evaluates in right-to-left order.
; To change the order to left-to-right we can remove the reverse from
; construct-arglist. We then have to construct the arglist with append instead
; of cons. That means we have to put the current arg val into a list and then
; call the append procedure. Consequently, the performance is worse because of
; the additional list instruction and because append is more expensive than
; cons.
; (define (code-to-get-rest-args operand-codes)
; (let ((code-for-next-arg
; (preserving '(argl)
; (car operand-codes)
; (make-instruction-sequence '(val argl) '(argl)
; '((assign val (op list) (reg val)) ;; ** left-to-right evaluation
; (assign argl (op append) (reg val) (reg argl)))))))
; (if (null? (cdr operand-codes))
; code-for-next-arg
; (preserving '(env)
; code-for-next-arg
; (code-to-get-rest-args (cdr operand-codes))))))
(display "[answered]\n")
(display "\nex-5.37 - preserving-mechanism-evaluation\n")
(display "CONTINUE HERE!\n")
(define (preserving regs seq1 seq2)
(if (null? regs)
(append-instruction-sequences seq1 seq2)
(let ((first-reg (car regs)))
(if (and (needs-register? seq2 first-reg)
(modifies-register? seq1 first-reg))
(preserving (cdr regs)
(make-instruction-sequence
(list-union (list first-reg)
(registers-needed seq1))
(list-difference (registers-modified seq1)
(list first-reg))
(append `((save ,first-reg))
(statements seq1)
`((restore ,first-reg))))
seq2)
(preserving (cdr regs) seq1 seq2)))))
; Exercise 5.37. One way to understand the compiler's preserving mechanism for
; optimizing stack usage is to see what extra operations would be generated if
; we did not use this idea. Modify preserving so that it always generates the
; save and restore operations. Compile some simple expressions and identify the
; unnecessary stack operations that are generated. Compare the code to that
; generated with the preserving mechanism intact.
(display "\nex-5.38\n")