2016/02/07

SICP 問題 5.37

preservingを修正して常にsaveとrestoreをさせ,修正前と後を比較する.

修正前

(define (preserving regs seq1 seq2)
  (if (null? regs)
      (append-instruction-sequences seq1 seq2)
      (let ((first-reg (car regs)))     ;first-regが
        (if (and (needs-register? seq2 first-reg) ;seq2に必要なレジスタで
                 (modifies-register? seq1 first-reg)) ;seq1が変更するレジスタなら
            (preserving
             (cdr regs)
             (make-instruction-sequence
              ;; needs ここでsaveするのでfirst-regが必要になるのでlist-union
              (list-union (list first-reg)
                          (registers-needed seq1))
              ;; modify saveしてのseq2の前にrestoreするのでseq2から見ればfirst-reg変更無し
              (list-difference (registers-modified seq1)
                               (list first-reg))
              ;; statements 条件を満たすfirst-regの場合はseq1をsaveとrestoreで挟む
              (append `((save ,first-reg))
                      (statements seq1)
                      `((restore ,first-reg))))
             seq2)
            (preserving (cdr regs) seq1 seq2)))))

必要ないsaveやrestoreは一切されない,賢いpreserving.

gosh> (compile
       '(define (f a b)
          (+ a b))
       'val 'next)
((env)
 (val)
 ((assign val (op make-compiled-procedure) (label entry34) (reg env))
  (goto (label after-lambda35))
  entry34
  (assign env (op compiled-procedure-env) (reg proc))
  (assign env (op extend-environment) (const (a b)) (reg argl) (reg env))
  (assign proc (op lookup-variable-value) (const +) (reg env))
  (assign val (op lookup-variable-value) (const a) (reg env))
  (assign argl (op list) (reg val))
  (assign val (op lookup-variable-value) (const b) (reg env))
  (assign val (op list) (reg val))
  (assign argl (op append) (reg argl) (reg val))
  (test (op primitive-procedure?) (reg proc))
  (branch (label primitive-branch36))
  compiled-branch37
  (assign val (op compiled-procedure-entry) (reg proc))
  (goto (reg val))
  primitive-branch36
  (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
  (goto (reg continue))
  after-call38
  after-lambda35
  (perform (op define-variable!) (const f) (reg val) (reg env))
  (assign val (const ok))
  ))

修正後

(define (preserving regs seq1 seq2)
  (if (null? regs)
      (append-instruction-sequences seq1 seq2)
      (let ((first-reg (car regs)))
        (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))))
gosh> (compile
       '(define (f a b)
          (+ a b))
       'val 'next)
((continue env)                         ;まずcontinueを必要とするようになっている.
 (val)
 ((save continue)                       ;ここでsave continueするから
  (save env)
  (save continue)                       ;ここでさらにsave continueしている.
  (assign val (op make-compiled-procedure) (label entry41) (reg env))
  (restore continue)                    ;ここで復帰.
  (goto (label after-lambda42))         ;ここまでで無駄なsave 3. 無駄なrestore 1
  entry41
  (assign env (op compiled-procedure-env) (reg proc))
  (assign env (op extend-environment) (const (a b)) (reg argl) (reg env))
  (save continue)                       ;ここでまたsave continue
  (save env)                            ;env
  (save continue)                       ;continue
  (assign proc (op lookup-variable-value) (const +) (reg env))
  (restore continue)                    ;restore c
  (restore env)                         ;restore e
  (restore continue)                    ;restore c
  (save continue)                       ;save c
  (save proc)                           ;save p
  (save env)                            ;save e
  (save continue)                       ;save c
  (assign val (op lookup-variable-value) (const a) (reg env))
  (restore continue)                    ;restore c
  (assign argl (op list) (reg val))
  (restore env)                         ;restore e
  (save argl)                           ;save a
  (save continue)                       ;save c
  (assign val (op lookup-variable-value) (const b) (reg env))
  (restore continue)                    ;restore c
  (restore argl)                        ;restore a
  (assign val (op list) (reg val))
  (assign argl (op append) (reg argl) (reg val))
  (restore proc)                        ;restore p
  (restore continue)                    ;restore c
  (test (op primitive-procedure?) (reg proc))
  (branch (label primitive-branch43))
  compiled-branch44
  (assign val (op compiled-procedure-entry) (reg proc))
  (goto (reg val))
  primitive-branch43
  (save continue)                       ;save c
  (assign val (op apply-primitive-procedure) (reg proc) (reg argl))
  (restore continue)                    ;restore c
  (goto (reg continue))
  after-call45
  after-lambda42
  (restore env)                         ;restore e 最初のenv
  (perform (op define-variable!) (const f) (reg val) (reg env))
  (assign val (const ok))
  (restore continue)                    ;最初のcontinue
  ))

© 2022 wat-aro