Answer 5.37

This commit is contained in:
2021-04-18 20:42:04 -04:00
parent e75eb75df4
commit 1bf5859f17

View File

@@ -74,14 +74,19 @@ ev-appl-did-operator-no-restore
(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)))
(if #f ; #t means write to file; #f means don't write to file
(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))
(begin
(display "[")
(display file-name)
(display "]\n"))))
; Uncomment the following lines to write the assembly code for the to methods
; into files.
@@ -320,31 +325,104 @@ ev-appl-did-operator-no-restore
(display "\nex-5.37 - preserving-mechanism-evaluation\n")
(display "CONTINUE HERE!\n")
; Uncomment the following code to compile a version with optimized and
; unoptimzed stack usage for a simple program.
(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)))))
(compile-to-file
'(+ 1 1)
'val 'next "f-add.scm")
; 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.
;(define (preserving regs seq1 seq2)
; (if (null? regs)
; (append-instruction-sequences seq1 seq2)
; (let ((first-reg (car regs)))
; (if #t ; preserve all registers no matter what
; ; (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)))))
(display "\nex-5.38\n")
(compile-to-file
'(+ 1 1)
'val 'next "f-add-unoptimized-stack-usage.scm")
; $ diff f-add.scm f-add-unoptimized-stack-usage.scm
; 0a1,3
; > (save continue)
; > (save env)
; > (save continue)
; 1a5,11
; > (restore continue)
; > (restore env)
; > (restore continue)
; > (save continue)
; > (save proc)
; > (save env)
; > (save continue)
; 2a13
; > (restore continue)
; 3a15,17
; > (restore env)
; > (save argl)
; > (save continue)
; 4a19,20
; > (restore continue)
; > (restore argl)
; 5a22,23
; > (restore proc)
; > (restore continue)
; 12a31
; > (save continue)
; 13a33
; > (restore continue)
; Even for the simple program (+ 1 1) the stack-preserving-mechanism saves 20
; stack operations. Pretty impressive.
(display "[answered]\n")
(display "\nex-5.38 - optimize-procedure-application\n")
; The expression (+ a 1) might be compiled into something as simple as:
; (assign val (op lookup-variable-value) (const a) (reg env))
; (assign val (op +) (reg val) (const 1))
; a. The open-coded primitives, unlike the special forms, all need their
; operands evaluated. Write a code generator spread-arguments for use by all
; the open-coding code generators. Spread-arguments should take an operand list
; and compile the given operands targeted to successive argument registers.
; Note that an operand may contain a call to an open-coded primitive, so
; argument registers will have to be preserved during operand evaluation.
(define (spread-arguments operand-codes)
(assert (length operand-codes) 2)
(make-instruction-sequence
'()
'()
'((assign ))))
; b. For each of the primitive procedures =, *, -, and +, write a code
; generator that takes a combination with that operator, together with a target
; and a linkage descriptor, and produces code to spread the arguments into the
; registers and then perform the operation targeted to the given target with
; the given linkage. You need only handle expressions with two operands. Make
; compile dispatch to these code generators.
; c. Try your new compiler on the factorial example. Compare the resulting
; code with the result produced without open coding.
; d. Extend your code generators for + and * so that they can handle
; expressions with arbitrary numbers of operands. An expression with more than
; two operands will have to be compiled into a sequence of operations, each
; with only two inputs.
(display "\nex-5.39\n")