From 1bf5859f17a1ee5fdc471ca98004dd0f6e13ba51 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sun, 18 Apr 2021 20:42:04 -0400 Subject: [PATCH] Answer 5.37 --- ex-5_31-xx.scm | 144 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 33 deletions(-) diff --git a/ex-5_31-xx.scm b/ex-5_31-xx.scm index 29b7d5a..acad072 100644 --- a/ex-5_31-xx.scm +++ b/ex-5_31-xx.scm @@ -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")