Implement 5.38

main
Felix Martin 2021-04-20 09:27:08 -04:00
parent ce6ed4603b
commit 016d35bc87
2 changed files with 37 additions and 28 deletions

View File

@ -74,7 +74,7 @@ ev-appl-did-operator-no-restore
(display (car xs) port)
(display "\n" port)
(write-list-to-port (cdr xs) port))))
(if #f ; #t means write to file; #f means don't write to file
(if #t ; #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)))
@ -391,13 +391,6 @@ ev-appl-did-operator-no-restore
(display "\nex-5.38 - optimize-procedure-application\n")
; 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-list)
(define (compile-operands operand-list operand-number)
(cond
@ -414,33 +407,45 @@ ev-appl-did-operator-no-restore
(compile-operands (cdr operand-list) (+ operand-number 1))))
(else
(error "Only two arg registers supported -- SPREAD-ARGUMENTS"))))
(let ((operand-codes (compile-operands operand-list 1)))
operand-codes))
(define (display-lines xs)
(define (display-line x)
(display x) (newline))
(map display-line xs))
(define (primitive-procedure? exp)
(define primitive-procedures '(= * - +))
(and (pair? exp)
(= (length exp) 3) ;; only support two args for now
(memq (car exp) primitive-procedures)
))
(display-lines (third (spread-arguments '(1 1))))
(newline)
(define (compile-primitive-call op target linkage)
(end-with-linkage linkage
(make-instruction-sequence
'(arg1 arg2)
`(,target)
`((assign ,target (op ,op) (reg arg1) (reg arg2))))))
(display "b. CONTINUE HERE\n")
(define (compile-primitive exp target linkage)
(let ((proc-code (compile-primitive-call (operator exp) target linkage))
(operand-codes (spread-arguments (operands exp))))
(preserving '(env continue)
operand-codes
proc-code)))
; 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.
(compile-to-file
'(define (factorial n)
(if (= n 1)
1
(* (factorial (- n 1)) n)))
'val 'next "factorial-opt.sicp-asm")
; c. Try your new compiler on the factorial example. Compare the resulting
; code with the result produced without open coding.
; c. The optimization saves 39 instructions
; λ symposium sicp → λ git master* → wc -l factorial.sicp-asm factorial-opt.sicp-asm
; 79 factorial.sicp-asm
; 40 factorial-opt.sicp-asm
; 119 total
; 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 "[answered]\n")
(display "\nex-5.39\n")
(display "\nex-5.40\n")

View File

@ -34,6 +34,8 @@
target
linkage))
((cond? exp) (compile (cond->if exp) target linkage))
((primitive-procedure? exp)
(compile-primitive exp target linkage))
((application? exp)
(compile-application exp target linkage))
(else
@ -46,6 +48,8 @@
(define (empty-instruction-sequence)
(make-instruction-sequence '() '() '()))
;; Implemented in 5.38.
(define (primitive-procedure? exp) #f)
;;;SECTION 5.5.2