1 ;;;============================================================================
3 ;;; File: "_gvm.scm", Time-stamp: <2007-04-04 11:36:18 feeley>
5 ;;; Copyright (c) 1994-2007 by Marc Feeley, All Rights Reserved.
9 (include-adt "_envadt.scm")
10 (include "_gvmadt.scm")
11 (include-adt "_ptreeadt.scm")
12 (include-adt "_sourceadt.scm")
14 ;;;----------------------------------------------------------------------------
16 ;; Gambit virtual machine abstraction module:
17 ;; -----------------------------------------
19 ;; (See file 'doc/gvm' for details on the virtual machine)
24 (define *opnd-table* #f)
25 (define *opnd-table-alloc* #f)
27 (define (extend-opnd-table!)
28 (let* ((n (vector-length *opnd-table*))
29 (new-table (make-vector (+ (quotient (* 3 n) 2) 1) #f)))
33 (vector-set! new-table i (vector-ref *opnd-table* i))
35 (set! *opnd-table* new-table)))))
37 (define (enter-opnd arg1 arg2)
39 (if (< i *opnd-table-alloc*)
40 (let ((x (vector-ref *opnd-table* i)))
41 (if (and (eqv? (car x) arg1) (eqv? (cdr x) arg2))
45 (set! *opnd-table-alloc* (+ *opnd-table-alloc* 1))
46 (if (> *opnd-table-alloc* (vector-length *opnd-table*))
48 (vector-set! *opnd-table* i (cons arg1 arg2))
51 (define (contains-opnd? opnd1 opnd2) ; does opnd2 contain opnd1?
52 (cond ((eqv? opnd1 opnd2)
55 (contains-opnd? opnd1 (clo-base opnd2)))
59 (define (any-contains-opnd? opnd opnds)
62 (or (contains-opnd? opnd (car opnds))
63 (any-contains-opnd? opnd (cdr opnds)))))
65 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
67 ;; Processor context descriptions:
68 ;; ------------------------------
70 (define (make-pcontext fs map)
73 (define (pcontext-fs x) (vector-ref x 0))
74 (define (pcontext-map x) (vector-ref x 1))
76 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81 (define (make-frame size slots regs closed live)
82 (vector size slots regs closed live))
84 (define (frame-size x) (vector-ref x 0))
85 (define (frame-slots x) (vector-ref x 1))
86 (define (frame-regs x) (vector-ref x 2))
87 (define (frame-closed x) (vector-ref x 3))
88 (define (frame-live x) (vector-ref x 4))
90 (define (frame-eq? frame1 frame2)
92 ; two frames are "equal" if they have the same number of slots and
93 ; for all slots and registers in a frame the corresponding slot or
94 ; register in the other frame has the same liveness and the return
95 ; address is in the same place.
97 (define (same-liveness? var1 var2)
98 (eq? (varset-member? var1 (frame-live frame1))
99 (varset-member? var2 (frame-live frame2))))
101 (define (same-liveness-list? lst1 lst2)
103 (let ((var1 (car lst1)))
105 (let ((var2 (car lst2)))
106 (and (eq? (eq? var1 ret-var) (eq? var2 ret-var))
107 (same-liveness? var1 var2)
108 (same-liveness-list? (cdr lst1) (cdr lst2))))
109 (and (same-liveness? var1 empty-var)
110 (same-liveness-list? (cdr lst1) lst2))))
112 (let ((var2 (car lst2)))
113 (and (same-liveness? empty-var var2)
114 (same-liveness-list? lst1 (cdr lst2))))
117 (and (= (frame-size frame1) (frame-size frame2))
118 (let ((slots1 (frame-slots frame1))
119 (slots2 (frame-slots frame2)))
120 (same-liveness-list? slots1 slots2))
121 (let ((regs1 (frame-regs frame1))
122 (regs2 (frame-regs frame2)))
123 (same-liveness-list? regs1 regs2))))
125 (define (frame-truncate frame nb-slots)
126 (let ((fs (frame-size frame)))
128 (drop (frame-slots frame) (- fs nb-slots))
131 (frame-live frame))))
133 (define (frame-live? var frame)
134 (let ((live (frame-live frame)))
135 (if (eq? var closure-env-var)
136 (let ((closed (frame-closed frame)))
137 (if (or (varset-member? var live)
138 (varset-intersects? live (list->varset closed)))
141 (if (varset-member? var live)
145 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147 ;; Procedure objects:
150 (define (make-proc-obj
169 (lambda (env) #f) ; testable?
171 (lambda (env) #f) ; expandable?
173 (lambda (env) #f) ; inlinable?
175 (lambda (env) #f) ; jump-inlinable?
184 (proc-obj-specialize-set! proc-obj (lambda (env args) proc-obj))
187 (define proc-obj-tag (list 'proc-obj))
189 (define (proc-obj? x)
191 (> (vector-length x) 0)
192 (eq? (vector-ref x 0) proc-obj-tag)))
194 (define (proc-obj-name obj) (vector-ref obj 1))
195 (define (proc-obj-c-name obj) (vector-ref obj 2))
196 (define (proc-obj-primitive? obj) (vector-ref obj 3))
197 (define (proc-obj-code obj) (vector-ref obj 4))
198 (define (proc-obj-call-pat obj) (vector-ref obj 5))
199 (define (proc-obj-testable? obj) (vector-ref obj 6))
200 (define (proc-obj-test obj) (vector-ref obj 7))
201 (define (proc-obj-expandable? obj) (vector-ref obj 8))
202 (define (proc-obj-expand obj) (vector-ref obj 9))
203 (define (proc-obj-inlinable? obj) (vector-ref obj 10))
204 (define (proc-obj-inline obj) (vector-ref obj 11))
205 (define (proc-obj-jump-inlinable? obj) (vector-ref obj 12))
206 (define (proc-obj-jump-inline obj) (vector-ref obj 13))
207 (define (proc-obj-specialize obj) (vector-ref obj 14))
208 (define (proc-obj-simplify obj) (vector-ref obj 15))
209 (define (proc-obj-side-effects? obj) (vector-ref obj 16))
210 (define (proc-obj-strict-pat obj) (vector-ref obj 17))
211 (define (proc-obj-lift-pat obj) (vector-ref obj 18))
212 (define (proc-obj-type obj) (vector-ref obj 19))
213 (define (proc-obj-standard obj) (vector-ref obj 20))
215 (define (proc-obj-code-set! obj x) (vector-set! obj 4 x))
216 (define (proc-obj-testable?-set! obj x) (vector-set! obj 6 x))
217 (define (proc-obj-test-set! obj x) (vector-set! obj 7 x))
218 (define (proc-obj-expandable?-set! obj x) (vector-set! obj 8 x))
219 (define (proc-obj-expand-set! obj x) (vector-set! obj 9 x))
220 (define (proc-obj-inlinable?-set! obj x) (vector-set! obj 10 x))
221 (define (proc-obj-inline-set! obj x) (vector-set! obj 11 x))
222 (define (proc-obj-jump-inlinable?-set! obj x) (vector-set! obj 12 x))
223 (define (proc-obj-jump-inline-set! obj x) (vector-set! obj 13 x))
224 (define (proc-obj-specialize-set! obj x) (vector-set! obj 14 x))
225 (define (proc-obj-simplify-set! obj x) (vector-set! obj 15 x))
227 (define (make-pattern nb-parms nb-opts nb-keys rest?)
228 (let* ((max-pos-args (- nb-parms nb-keys (if rest? 1 0)))
229 (min-args (- max-pos-args nb-opts)))
233 (if (or (> nb-keys 0) rest?)
235 (list max-pos-args))))
237 (loop (- i 1) (cons i pattern))
240 (define (pattern-member? n pat) ; tests if 'n' is a member of pattern 'pat'
242 (if (= (car pat) n) #t (pattern-member? n (cdr pat))))
248 (define (type-name type)
249 (if (pair? type) (car type) type))
251 (define (type-pot-fut? type)
254 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
256 ;; Basic block set manipulation:
257 ;; ----------------------------
259 ;; Virtual instructions have a linear structure. However, this is not
260 ;; how they are put together to form a piece of code. Rather, virtual
261 ;; instructions are grouped into 'basic blocks' which are 'linked'
262 ;; together. A basic block is a 'label' instruction followed by a
263 ;; sequence of non-branching instructions (i.e. 'apply', 'copy' or
264 ;; 'close') terminated by a single branch instruction (i.e. 'ifjump',
265 ;; 'jump' or 'switch'). Links between basic blocks are denoted using
266 ;; label references. When a basic block ends with an 'ifjump'
267 ;; instruction, the block is linked to the two basic blocks
268 ;; corresponding to the two possible control paths out of the 'ifjump'
269 ;; instruction. When a basic block ends with a 'switch' instruction, the
270 ;; block is linked to as many basic blocks as there are cases and the
271 ;; default. When a basic block ends with a 'jump' instruction, there
272 ;; is either zero or one link.
274 ;; Basic blocks naturally group together to form 'basic block sets'. A
275 ;; basic block set describes all the code of a procedure.
279 1 ; 1 - next assignable label number
280 (make-stretchable-vector #f) ; 2 - vector of basic blocks
281 #f)) ; 3 - entry label number
283 (define bbs-tag (list 'bbs))
287 (> (vector-length x) 0)
288 (eq? (vector-ref x 0) bbs-tag)))
290 (define (bbs-next-lbl-num bbs) (vector-ref bbs 1))
291 (define (bbs-next-lbl-num-set! bbs lbl-num) (vector-set! bbs 1 lbl-num))
292 (define (bbs-basic-blocks bbs) (vector-ref bbs 2))
293 (define (bbs-basic-blocks-set! bbs blocks) (vector-set! bbs 2 blocks))
294 (define (bbs-entry-lbl-num bbs) (vector-ref bbs 3))
295 (define (bbs-entry-lbl-num-set! bbs lbl-num) (vector-set! bbs 3 lbl-num))
297 (define (bbs-for-each-bb proc bbs)
298 (stretchable-vector-for-each
299 (lambda (bb i) (if bb (proc bb)))
300 (bbs-basic-blocks bbs)))
302 (define (bbs-bb-remove! bbs lbl)
303 (stretchable-vector-set! (bbs-basic-blocks bbs) lbl #f))
305 (define (bbs-new-lbl! bbs)
306 (let ((n (bbs-next-lbl-num bbs)))
307 (bbs-next-lbl-num-set! bbs (+ n 1))
310 (define (lbl-num->bb lbl-num bbs)
311 (stretchable-vector-ref (bbs-basic-blocks bbs) lbl-num))
313 ;; Basic block manipulation procedures:
315 (define (make-bb label-instr bbs)
317 label-instr ; 0 - 'label' instr
318 (queue-empty) ; 1 - sequence of non-branching instrs
319 '() ; 2 - branch instruction
320 '() ; 3 - basic blocks referenced by this block
321 '()))) ; 4 - basic blocks which jump to this block
322 ; (both filled in by 'bbs-purify!')
323 (stretchable-vector-set!
324 (bbs-basic-blocks bbs)
325 (label-lbl-num label-instr)
329 (define (bb-lbl-num bb) (label-lbl-num (vector-ref bb 0)))
330 (define (bb-label-type bb) (label-type (vector-ref bb 0)))
331 (define (bb-label-instr bb) (vector-ref bb 0))
332 (define (bb-label-instr-set! bb l) (vector-set! bb 0 l))
333 (define (bb-non-branch-instrs bb) (queue->list (vector-ref bb 1)))
334 (define (bb-non-branch-instrs-set! bb l) (vector-set! bb 1 (list->queue l)))
335 (define (bb-branch-instr bb) (vector-ref bb 2))
336 (define (bb-branch-instr-set! bb b) (vector-set! bb 2 b))
337 (define (bb-references bb) (vector-ref bb 3))
338 (define (bb-references-set! bb l) (vector-set! bb 3 l))
339 (define (bb-precedents bb) (vector-ref bb 4))
340 (define (bb-precedents-set! bb l) (vector-set! bb 4 l))
342 (define (bb-entry-frame-size bb)
343 (frame-size (gvm-instr-frame (bb-label-instr bb))))
345 (define (bb-exit-frame-size bb)
346 (frame-size (gvm-instr-frame (bb-branch-instr bb))))
348 (define (bb-slots-gained bb)
349 (- (bb-exit-frame-size bb) (bb-entry-frame-size bb)))
351 (define (bb-put-non-branch! bb gvm-instr)
352 (queue-put! (vector-ref bb 1) gvm-instr))
354 (define (bb-put-branch! bb gvm-instr)
355 (vector-set! bb 2 gvm-instr))
357 (define (bb-add-reference! bb ref)
358 (if (not (memq ref (vector-ref bb 3)))
359 (vector-set! bb 3 (cons ref (vector-ref bb 3)))))
361 (define (bb-add-precedent! bb prec)
362 (if (not (memq prec (vector-ref bb 4)))
363 (vector-set! bb 4 (cons prec (vector-ref bb 4)))))
365 (define (bb-last-non-branch-instr bb)
366 (let ((non-branch-instrs (bb-non-branch-instrs bb)))
367 (if (null? non-branch-instrs)
369 (let loop ((l non-branch-instrs))
374 ;; Virtual machine instruction representation:
376 (define (gvm-instr-type gvm-instr) (vector-ref gvm-instr 0))
377 (define (gvm-instr-frame gvm-instr) (vector-ref gvm-instr 1))
378 (define (gvm-instr-comment gvm-instr) (vector-ref gvm-instr 2))
380 (define (make-label-simple lbl-num frame comment)
381 (vector 'label frame comment lbl-num 'simple))
383 (define (make-label-entry lbl-num nb-parms opts keys rest? closed? frame comment)
384 (vector 'label frame comment lbl-num 'entry nb-parms opts keys rest? closed?))
386 (define (make-label-return lbl-num frame comment)
387 (vector 'label frame comment lbl-num 'return))
389 (define (make-label-task-entry lbl-num frame comment)
390 (vector 'label frame comment lbl-num 'task-entry))
392 (define (make-label-task-return lbl-num frame comment)
393 (vector 'label frame comment lbl-num 'task-return))
395 (define (label-lbl-num gvm-instr) (vector-ref gvm-instr 3))
396 (define (label-lbl-num-set! gvm-instr n) (vector-set! gvm-instr 3 n))
397 (define (label-type gvm-instr) (vector-ref gvm-instr 4))
399 (define (label-entry-nb-parms gvm-instr) (vector-ref gvm-instr 5))
400 (define (label-entry-opts gvm-instr) (vector-ref gvm-instr 6))
401 (define (label-entry-keys gvm-instr) (vector-ref gvm-instr 7))
402 (define (label-entry-rest? gvm-instr) (vector-ref gvm-instr 8))
403 (define (label-entry-closed? gvm-instr) (vector-ref gvm-instr 9))
405 (define (make-apply prim opnds loc frame comment)
406 (vector 'apply frame comment prim opnds loc))
407 (define (apply-prim gvm-instr) (vector-ref gvm-instr 3))
408 (define (apply-opnds gvm-instr) (vector-ref gvm-instr 4))
409 (define (apply-loc gvm-instr) (vector-ref gvm-instr 5))
411 (define (make-copy opnd loc frame comment)
412 (vector 'copy frame comment opnd loc))
414 (define (copy-opnd gvm-instr) (vector-ref gvm-instr 3))
415 (define (copy-loc gvm-instr) (vector-ref gvm-instr 4))
417 (define (make-close parms frame comment)
418 (vector 'close frame comment parms))
419 (define (close-parms gvm-instr) (vector-ref gvm-instr 3))
421 (define (make-closure-parms loc lbl opnds)
422 (vector loc lbl opnds))
423 (define (closure-parms-loc x) (vector-ref x 0))
424 (define (closure-parms-lbl x) (vector-ref x 1))
425 (define (closure-parms-opnds x) (vector-ref x 2))
427 (define (make-ifjump test opnds true false poll? frame comment)
428 (vector 'ifjump frame comment test opnds true false poll?))
429 (define (ifjump-test gvm-instr) (vector-ref gvm-instr 3))
430 (define (ifjump-opnds gvm-instr) (vector-ref gvm-instr 4))
431 (define (ifjump-true gvm-instr) (vector-ref gvm-instr 5))
432 (define (ifjump-false gvm-instr) (vector-ref gvm-instr 6))
433 (define (ifjump-poll? gvm-instr) (vector-ref gvm-instr 7))
435 (define (make-switch opnd cases default poll? frame comment)
436 (vector 'switch frame comment opnd cases default poll?))
437 (define (switch-opnd gvm-instr) (vector-ref gvm-instr 3))
438 (define (switch-cases gvm-instr) (vector-ref gvm-instr 4))
439 (define (switch-default gvm-instr) (vector-ref gvm-instr 5))
440 (define (switch-poll? gvm-instr) (vector-ref gvm-instr 6))
442 (define (make-switch-case obj lbl) (cons obj lbl))
443 (define (switch-case-obj switch-case) (car switch-case))
444 (define (switch-case-lbl switch-case) (cdr switch-case))
446 (define (make-jump opnd nb-args poll? safe? frame comment)
447 (vector 'jump frame comment opnd nb-args poll? safe?))
448 (define (jump-opnd gvm-instr) (vector-ref gvm-instr 3))
449 (define (jump-nb-args gvm-instr) (vector-ref gvm-instr 4))
450 (define (jump-poll? gvm-instr) (vector-ref gvm-instr 5))
451 (define (jump-safe? gvm-instr) (vector-ref gvm-instr 6))
452 (define (first-class-jump? gvm-instr) (jump-nb-args gvm-instr))
454 (define (make-comment)
457 (define (comment-put! comment name val)
458 (set-cdr! comment (cons (cons name val) (cdr comment))))
460 (define (comment-get comment name)
462 (let ((x (assq name (cdr comment))))
465 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
467 ;; 'Purification' of basic block sets:
468 ;; ----------------------------------
470 ;; This step removes unreachable basic blocks (i.e. dead code), duplicate
471 ;; basic blocks (i.e. common code), useless jumps and jump cascades from
472 ;; a basic block set. It also orders the basic blocks so that the destination
473 ;; of a branch is put (if possible) right after the branch instruction. The
474 ;; 'references' and 'precedents' fields of each basic block are also filled in
475 ;; through the process. The first basic block of a 'purified' basic block set
476 ;; is always the entry point.
478 (define (bbs-purify! bbs)
479 (let loop () ; iterate until code does not change
480 (bbs-remove-jump-cascades! bbs)
481 (bbs-remove-dead-code! bbs)
482 (let* ((changed1? (bbs-remove-common-code! bbs))
483 (changed2? (bbs-remove-useless-jumps! bbs)))
484 (if (or changed1? changed2?) (loop) (bbs-order! bbs)))))
486 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
488 ;; Step 1, Jump cascade removal:
490 (define (bbs-remove-jump-cascades! bbs)
492 (define (empty-bb? bb)
493 (and (eq? (bb-label-type bb) 'simple) ; simple label and
494 (null? (bb-non-branch-instrs bb)))) ; no non-branching instrs
496 (define (jump-to-non-entry-lbl? branch)
497 (and (eq? (gvm-instr-type branch) 'jump)
498 (not (first-class-jump? branch)) ; not a jump to an entry label
501 (define (jump-cascade-to lbl-num fs poll? seen thunk)
502 (if (memq lbl-num seen) ; infinite loop?
503 (thunk lbl-num fs poll?)
504 (let ((bb (lbl-num->bb lbl-num bbs)))
505 (if (and (empty-bb? bb) (<= (bb-slots-gained bb) 0))
507 (jump-to-non-entry-lbl? (bb-branch-instr bb))))
511 (+ fs (bb-slots-gained bb))
512 (or poll? (jump-poll? (bb-branch-instr bb)))
515 (thunk lbl-num fs poll?)))
516 (thunk lbl-num fs poll?)))))
518 (define (equiv-lbl lbl-num seen)
519 (if (memq lbl-num seen) ; infinite loop?
521 (let ((bb (lbl-num->bb lbl-num bbs)))
524 (jump-to-non-entry-lbl? (bb-branch-instr bb))))
525 (if (and jump-lbl-num
526 (not (jump-poll? (bb-branch-instr bb)))
527 (= (bb-slots-gained bb) 0))
528 (equiv-lbl jump-lbl-num (cons lbl-num seen))
532 (define (remove-cascade! bb)
533 (let ((branch (bb-branch-instr bb)))
535 (case (gvm-instr-type branch)
537 ((ifjump) ; branch is an 'ifjump'
539 (make-ifjump (ifjump-test branch)
540 (ifjump-opnds branch)
541 (equiv-lbl (ifjump-true branch) '())
542 (equiv-lbl (ifjump-false branch) '())
543 (ifjump-poll? branch)
544 (gvm-instr-frame branch)
545 (gvm-instr-comment branch))))
547 ((switch) ; branch is a 'switch'
549 (make-switch (switch-opnd branch)
553 (equiv-lbl (switch-case-lbl c) '())))
554 (switch-cases branch))
555 (equiv-lbl (switch-default branch) '())
556 (switch-poll? branch)
557 (gvm-instr-frame branch)
558 (gvm-instr-comment branch))))
560 ((jump) ; branch is a 'jump'
561 (if (not (first-class-jump? branch)) ; but not to an entry label
562 (let ((dest-lbl-num (jump-lbl? branch)))
567 (frame-size (gvm-instr-frame branch))
570 (lambda (lbl-num fs poll?)
571 (let* ((dest-bb (lbl-num->bb lbl-num bbs))
572 (last-branch (bb-branch-instr dest-bb)))
573 (if (and (empty-bb? dest-bb)
575 (case (gvm-instr-type last-branch)
577 (ifjump-poll? last-branch))
579 (switch-poll? last-branch))
581 (jump-poll? last-branch))
584 (let* ((new-fs (+ fs (bb-slots-gained dest-bb)))
585 (new-frame (frame-truncate
586 (gvm-instr-frame branch)
589 (define (adjust-opnd opnd)
592 (+ (- fs (bb-entry-frame-size dest-bb))
595 (make-clo (adjust-opnd (clo-base opnd))
600 (case (gvm-instr-type last-branch)
604 (make-ifjump (ifjump-test last-branch)
606 (ifjump-opnds last-branch))
608 (ifjump-true last-branch)
611 (ifjump-false last-branch)
614 (ifjump-poll? last-branch))
616 (gvm-instr-comment last-branch))))
620 (make-switch (adjust-opnd (switch-opnd last-branch))
624 (equiv-lbl (switch-case-lbl c) '())))
625 (switch-cases last-branch))
626 (equiv-lbl (switch-default last-branch) '())
628 (switch-poll? last-branch))
630 (gvm-instr-comment last-branch))))
634 (make-jump (adjust-opnd (jump-opnd last-branch))
635 (jump-nb-args last-branch)
637 (jump-poll? last-branch))
638 (jump-safe? last-branch)
640 (gvm-instr-comment last-branch))))
643 (compiler-internal-error
644 "bbs-remove-jump-cascades!, unknown branch type"))))
647 (make-jump (make-lbl lbl-num)
648 (jump-nb-args branch)
653 (gvm-instr-frame branch)
655 (gvm-instr-comment branch)))))))))))
658 (compiler-internal-error
659 "bbs-remove-jump-cascades!, unknown branch type")))))
661 (bbs-for-each-bb remove-cascade! bbs))
663 (define (jump-lbl? branch)
664 (let ((opnd (jump-opnd branch)))
665 (if (lbl? opnd) (lbl-num opnd) #f)))
667 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
669 ;; Step 2, Dead code removal:
671 (define (bbs-remove-dead-code! bbs)
673 (let ((new-basic-blocks (make-stretchable-vector #f))
674 (left-to-examine (queue-empty)))
676 (define (reachable ref bb)
677 (let ((ref-lbl-num (bb-lbl-num ref)))
678 (if bb (bb-add-reference! bb ref))
679 (if (not (stretchable-vector-ref new-basic-blocks ref-lbl-num))
681 (bb-references-set! ref '())
682 (bb-precedents-set! ref '())
683 (stretchable-vector-set! new-basic-blocks ref-lbl-num ref)
684 (queue-put! left-to-examine ref)))))
686 (define (direct-jump to-bb from-bb)
687 (reachable to-bb from-bb)
688 (bb-add-precedent! to-bb from-bb))
690 (define (scan-instr gvm-instr bb)
692 (define (scan-opnd gvm-opnd)
693 (cond ((not gvm-opnd))
695 (reachable (lbl-num->bb (lbl-num gvm-opnd) bbs) bb))
697 (scan-opnd (clo-base gvm-opnd)))))
699 (case (gvm-instr-type gvm-instr)
705 (for-each scan-opnd (apply-opnds gvm-instr))
706 (if (apply-loc gvm-instr)
707 (scan-opnd (apply-loc gvm-instr))))
710 (scan-opnd (copy-opnd gvm-instr))
711 (scan-opnd (copy-loc gvm-instr)))
714 (for-each (lambda (parm)
715 (reachable (lbl-num->bb (closure-parms-lbl parm) bbs) bb)
716 (scan-opnd (closure-parms-loc parm))
717 (for-each scan-opnd (closure-parms-opnds parm)))
718 (close-parms gvm-instr)))
721 (for-each scan-opnd (ifjump-opnds gvm-instr))
722 (direct-jump (lbl-num->bb (ifjump-true gvm-instr) bbs) bb)
723 (direct-jump (lbl-num->bb (ifjump-false gvm-instr) bbs) bb))
726 (scan-opnd (switch-opnd gvm-instr))
727 (for-each (lambda (c)
728 (direct-jump (lbl-num->bb (switch-case-lbl c) bbs) bb))
729 (switch-cases gvm-instr))
730 (direct-jump (lbl-num->bb (switch-default gvm-instr) bbs) bb))
733 (let ((opnd (jump-opnd gvm-instr)))
735 (direct-jump (lbl-num->bb (lbl-num opnd) bbs) bb)
736 (scan-opnd (jump-opnd gvm-instr)))))
739 (compiler-internal-error
740 "bbs-remove-dead-code!, unknown GVM instruction type"))))
742 (reachable (lbl-num->bb (bbs-entry-lbl-num bbs) bbs) #f)
745 (if (not (queue-empty? left-to-examine))
746 (let ((bb (queue-get! left-to-examine)))
748 (scan-instr (bb-label-instr bb) bb)
749 (for-each (lambda (gvm-instr) (scan-instr gvm-instr bb))
750 (bb-non-branch-instrs bb))
751 (scan-instr (bb-branch-instr bb) bb)
754 (bbs-basic-blocks-set! bbs new-basic-blocks)))
756 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
758 ;; Step 3, Useless jump removal:
760 (define (bbs-remove-useless-jumps! bbs)
763 (define (remove-useless-jump bb)
764 (let ((branch (bb-branch-instr bb)))
766 ; is it a non-polling 'jump' to a label?
768 (if (and (eq? (gvm-instr-type branch) 'jump)
769 (not (first-class-jump? branch))
770 (not (jump-poll? branch))
772 (let* ((dest-bb (lbl-num->bb (jump-lbl? branch) bbs))
773 (frame1 (gvm-instr-frame (bb-last-non-branch-instr bb)))
774 (frame2 (gvm-instr-frame (bb-label-instr dest-bb))))
776 ; is it a 'simple' label with the same frame as the last
777 ; non-branch instruction?
779 (if (and (eq? (bb-label-type dest-bb) 'simple)
780 (frame-eq? frame1 frame2)
781 (= (length (bb-precedents dest-bb)) 1))
785 (bb-non-branch-instrs-set! bb
786 (append (bb-non-branch-instrs bb)
787 (bb-non-branch-instrs dest-bb)
789 (bb-branch-instr-set! bb
790 (bb-branch-instr dest-bb))
791 (remove-useless-jump bb)))))))
793 (bbs-for-each-bb remove-useless-jump bbs)
797 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
799 ;; Step 4, Common code removal:
801 (define (bbs-remove-common-code! bbs)
802 (let ((n (bbs-next-lbl-num bbs)))
803 (if (> n 300) ; if code is too large, don't optimize
807 (let* ((hash-table-length (if (< n 50) 43 403))
808 (hash-table (make-vector hash-table-length '()))
810 (lbl-map (make-stretchable-vector #f))
813 (define (hash-prim prim)
814 (let ((n (length prim-table))
815 (i (pos-in-list prim prim-table)))
819 (set! prim-table (cons prim prim-table))
822 (define (hash-opnds l) ; this assumes that operands are encoded with nbs
823 (let loop ((l l) (n 0))
829 (modulo (+ (* n 10000) x) hash-table-length))))
832 (define (hash-bb bb) ; compute hash address for a basic block
833 (let ((branch (bb-branch-instr bb)))
835 (case (gvm-instr-type branch)
837 (+ (hash-opnds (ifjump-opnds branch))
838 (* 10 (hash-prim (ifjump-test branch)))
839 (* 100 (frame-size (gvm-instr-frame branch)))))
841 (+ (hash-opnds (list (switch-opnd branch)))
842 (* 10 (length (switch-cases branch)))
843 (* 100 (frame-size (gvm-instr-frame branch)))))
845 (+ (hash-opnds (list (jump-opnd branch)))
846 (* 10 (or (jump-nb-args branch) -1))
847 (* 100 (frame-size (gvm-instr-frame branch)))))
852 (define (replacement-lbl-num lbl)
853 (or (stretchable-vector-ref lbl-map lbl) lbl))
855 (define (add-map! bb1 bb2) ; bb1 should be replaced by bb2
856 (stretchable-vector-set!
861 (define (remove-map! bb)
862 (stretchable-vector-set!
867 (define (enter-bb! bb) ; enter a basic block in the hash table
868 (let ((h (hash-bb bb)))
869 (vector-set! hash-table h
870 (add-bb bb (vector-ref hash-table h)))))
872 (define (add-bb bb l) ; add basic block 'bb' to list of basic blocks
874 (let ((bb* (car l))) ; pick next basic block in list
876 (add-map! bb bb*) ; for now, assume that 'bb' = 'bb*'
878 (if (eqv-bb? bb bb*) ; are they the same?
885 (remove-map! bb) ; they are not the same!
886 (if (eqv-gvm-instr? (bb-branch-instr bb) (bb-branch-instr bb*))
888 (extract-common-tail bb bb* ; check if tail is the same
889 (lambda (head head* tail)
890 (if (<= (length tail) 10) ; common tail long enough?
892 ; no, so try rest of list
893 (cons bb* (add-bb bb (cdr l)))
895 ; create bb for common tail
899 (bb-branch-instr bb))
901 (need-gvm-instrs tail branch))
910 (gvm-instr-comment (car tail)))
912 (make-bb (make-label-simple lbl frame comment)
914 (bb-non-branch-instrs-set! bb** tail)
915 (bb-branch-instr-set! bb** branch)
916 (bb-non-branch-instrs-set! bb* (reverse head*))
917 (bb-branch-instr-set! bb*
918 (make-jump (make-lbl lbl) #f #f #f frame comment))
919 (bb-non-branch-instrs-set! bb (reverse head))
920 (bb-branch-instr-set! bb
921 (make-jump (make-lbl lbl) #f #f #f frame comment))
923 (cons bb (cons bb* (add-bb bb** (cdr l))))))))
924 ;********** bb and bb* should not be put in this list!!!!
925 (cons bb* (add-bb bb (cdr l)))))))
929 (define (extract-common-tail bb1 bb2 cont)
930 (let loop ((l1 (reverse (bb-non-branch-instrs bb1)))
931 (l2 (reverse (bb-non-branch-instrs bb2)))
933 (if (and (pair? l1) (pair? l2))
936 (if (eqv-gvm-instr? i1 i2)
937 (loop (cdr l1) (cdr l2) (cons i1 tail))
941 (define (eqv-bb? bb1 bb2)
942 (let ((bb1-non-branch (bb-non-branch-instrs bb1))
943 (bb2-non-branch (bb-non-branch-instrs bb2)))
944 (and (= (length bb1-non-branch) (length bb2-non-branch))
945 (eqv-gvm-instr? (bb-label-instr bb1) (bb-label-instr bb2))
946 (eqv-gvm-instr? (bb-branch-instr bb1) (bb-branch-instr bb2))
947 (eqv-list? eqv-gvm-instr? bb1-non-branch bb2-non-branch))))
949 (define (eqv-list? pred? l1 l2)
952 (pred? (car l1) (car l2))
953 (eqv-list? pred? (cdr l1) (cdr l2)))
956 (define (eqv-lbl-num? lbl1 lbl2)
957 (= (replacement-lbl-num lbl1)
958 (replacement-lbl-num lbl2)))
960 (define (eqv-gvm-opnd? opnd1 opnd2)
966 (eqv-lbl-num? (lbl-num opnd1) (lbl-num opnd2))))
969 (= (clo-index opnd1) (clo-index opnd2))
970 (eqv-gvm-opnd? (clo-base opnd1)
973 (eqv? opnd1 opnd2))))))
975 (define (eqv-key-pair? key-pair1 key-pair2)
976 (and (eq? (car key-pair1) (car key-pair2))
977 (eqv-gvm-opnd? (cdr key-pair1) (cdr key-pair2))))
979 (define (eqv-gvm-instr? instr1 instr2)
981 (define (eqv-closure-parms? p1 p2)
982 (and (eqv-gvm-opnd? (closure-parms-loc p1)
983 (closure-parms-loc p2))
984 (eqv-lbl-num? (closure-parms-lbl p1)
985 (closure-parms-lbl p2))
986 (eqv-list? eqv-gvm-opnd?
987 (closure-parms-opnds p1)
988 (closure-parms-opnds p2))))
990 (let ((type1 (gvm-instr-type instr1))
991 (type2 (gvm-instr-type instr2)))
992 (and (eq? type1 type2)
993 (frame-eq? (gvm-instr-frame instr1) (gvm-instr-frame instr2))
997 (let ((ltype1 (label-type instr1))
998 (ltype2 (label-type instr2)))
999 (and (eq? ltype1 ltype2)
1001 ((simple return task-entry task-return)
1004 (and (= (label-entry-nb-parms instr1)
1005 (label-entry-nb-parms instr2))
1006 (eqv-list? eqv-gvm-opnd?
1007 (label-entry-opts instr1)
1008 (label-entry-opts instr2))
1009 (if (label-entry-keys instr1)
1010 (and (label-entry-keys instr2)
1011 (eqv-list? eqv-key-pair?
1012 (label-entry-keys instr1)
1013 (label-entry-keys instr2)))
1014 (not (label-entry-keys instr2)))
1015 (eq? (label-entry-rest? instr1)
1016 (label-entry-rest? instr2))
1017 (eq? (label-entry-closed? instr1)
1018 (label-entry-closed? instr2))))
1020 (compiler-internal-error
1021 "eqv-gvm-instr?, unknown label type"))))))
1024 (and (eq? (apply-prim instr1) (apply-prim instr2))
1025 (eqv-list? eqv-gvm-opnd?
1026 (apply-opnds instr1)
1027 (apply-opnds instr2))
1028 (eqv-gvm-opnd? (apply-loc instr1)
1029 (apply-loc instr2))))
1032 (and (eqv-gvm-opnd? (copy-opnd instr1)
1034 (eqv-gvm-opnd? (copy-loc instr1)
1035 (copy-loc instr2))))
1038 (eqv-list? eqv-closure-parms?
1039 (close-parms instr1)
1040 (close-parms instr2)))
1043 (and (eq? (ifjump-test instr1)
1044 (ifjump-test instr2))
1045 (eqv-list? eqv-gvm-opnd?
1046 (ifjump-opnds instr1)
1047 (ifjump-opnds instr2))
1048 (eqv-lbl-num? (ifjump-true instr1)
1049 (ifjump-true instr2))
1050 (eqv-lbl-num? (ifjump-false instr1)
1051 (ifjump-false instr2))
1052 (eq? (ifjump-poll? instr1)
1053 (ifjump-poll? instr2))))
1056 (and (eqv-gvm-opnd? (switch-opnd instr1)
1057 (switch-opnd instr2))
1059 (and (eqv? (switch-case-obj (car x))
1060 (switch-case-obj (cdr x)))
1061 (eqv-lbl-num? (switch-case-lbl (car x))
1062 (switch-case-lbl (cdr x)))))
1064 (switch-cases instr1)
1065 (switch-cases instr2)))
1066 (eqv-lbl-num? (switch-default instr1)
1067 (switch-default instr2))
1068 (eq? (switch-poll? instr1)
1069 (switch-poll? instr2))))
1072 (and (eqv-gvm-opnd? (jump-opnd instr1)
1074 (eqv? (jump-nb-args instr1)
1075 (jump-nb-args instr2))
1076 (eq? (jump-poll? instr1)
1077 (jump-poll? instr2))
1078 (eq? (jump-safe? instr1)
1079 (jump-safe? instr2))))
1082 (compiler-internal-error
1083 "eqv-gvm-instr?, unknown 'gvm-instr':" instr1))))))
1085 ; Fill hash table, remove equivalent basic blocks and common tails
1087 (bbs-for-each-bb enter-bb! bbs)
1091 (bbs-entry-lbl-num-set! bbs
1092 (replacement-lbl-num (bbs-entry-lbl-num bbs)))
1097 (replace-label-references! bb replacement-lbl-num)))
1102 (define (replace-label-references! bb replacement-lbl-num)
1104 (define (update-gvm-opnd opnd)
1107 (make-lbl (replacement-lbl-num (lbl-num opnd))))
1109 (make-clo (update-gvm-opnd (clo-base opnd)) (clo-index opnd)))
1114 (define (update-gvm-instr instr)
1116 (define (update-closure-parms p)
1118 (update-gvm-opnd (closure-parms-loc p))
1119 (replacement-lbl-num (closure-parms-lbl p))
1120 (map update-gvm-opnd (closure-parms-opnds p))))
1122 (case (gvm-instr-type instr)
1125 (make-apply (apply-prim instr)
1126 (map update-gvm-opnd (apply-opnds instr))
1127 (update-gvm-opnd (apply-loc instr))
1128 (gvm-instr-frame instr)
1129 (gvm-instr-comment instr)))
1132 (make-copy (update-gvm-opnd (copy-opnd instr))
1133 (update-gvm-opnd (copy-loc instr))
1134 (gvm-instr-frame instr)
1135 (gvm-instr-comment instr)))
1139 (map update-closure-parms (close-parms instr))
1140 (gvm-instr-frame instr)
1141 (gvm-instr-comment instr)))
1144 (make-ifjump (ifjump-test instr)
1145 (map update-gvm-opnd (ifjump-opnds instr))
1146 (replacement-lbl-num (ifjump-true instr))
1147 (replacement-lbl-num (ifjump-false instr))
1148 (ifjump-poll? instr)
1149 (gvm-instr-frame instr)
1150 (gvm-instr-comment instr)))
1153 (make-switch (update-gvm-opnd (switch-opnd instr))
1155 (make-switch-case (switch-case-obj c)
1156 (replacement-lbl-num
1157 (switch-case-lbl c))))
1158 (switch-cases instr))
1159 (replacement-lbl-num (switch-default instr))
1160 (switch-poll? instr)
1161 (gvm-instr-frame instr)
1162 (gvm-instr-comment instr)))
1165 (make-jump (update-gvm-opnd (jump-opnd instr))
1166 (jump-nb-args instr)
1169 (gvm-instr-frame instr)
1170 (gvm-instr-comment instr)))
1173 (compiler-internal-error
1174 "update-gvm-instr, unknown 'instr':" instr))))
1176 (bb-non-branch-instrs-set! bb
1177 (map update-gvm-instr (bb-non-branch-instrs bb)))
1178 (bb-branch-instr-set! bb
1179 (update-gvm-instr (bb-branch-instr bb))))
1181 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1183 ;; Step 5, Basic block set ordering:
1185 (define (bbs-order! bbs)
1187 (let ((ordered-blocks (queue-empty))
1188 (left-to-schedule (stretchable-vector-copy (bbs-basic-blocks bbs))))
1190 ; test if a basic block is in 'left-to-schedule' and return the
1191 ; basic block if it is
1193 (define (left-to-schedule? bb)
1194 (stretchable-vector-ref left-to-schedule (bb-lbl-num bb)))
1196 ; remove basic block from 'left-to-schedule'
1198 (define (remove-bb! bb)
1199 (stretchable-vector-set! left-to-schedule (bb-lbl-num bb) #f)
1202 ; return a basic block which ends with a branch to 'bb' (and that is
1203 ; still in 'left-to-schedule') or #f if there aren't any
1205 (define (prec-bb bb)
1206 (let loop ((lst (bb-precedents bb)) (best #f) (best-fs #f))
1209 (let* ((x (car lst))
1210 (x-fs (bb-exit-frame-size x)))
1211 (if (and (left-to-schedule? x)
1212 (or (not best) (< x-fs best-fs)))
1213 (loop (cdr lst) x x-fs)
1214 (loop (cdr lst) best best-fs))))))
1216 ; return the basic block which 'bb' jumps to (and that is still in
1217 ; bbs) or #f if there aren't any
1219 (define (succ-bb bb)
1221 (define (branches-to-lbl? bb)
1222 (let ((branch (bb-branch-instr bb)))
1223 (case (gvm-instr-type branch)
1226 ((jump) (lbl? (jump-opnd branch)))
1228 (compiler-internal-error
1229 "bbs-order!, unknown branch type")))))
1231 (define (best-succ bb1 bb2) ; heuristic that determines which
1232 (if (branches-to-lbl? bb1) ; bb is most frequently executed
1234 (if (branches-to-lbl? bb2)
1236 (if (< (bb-exit-frame-size bb1)
1237 (bb-exit-frame-size bb2))
1241 (let ((branch (bb-branch-instr bb)))
1242 (case (gvm-instr-type branch)
1247 (lbl-num->bb (ifjump-true branch) bbs)))
1250 (lbl-num->bb (ifjump-false branch) bbs))))
1251 (if (and true-bb false-bb)
1252 (best-succ true-bb false-bb)
1253 (or true-bb false-bb))))
1257 (lbl-num->bb (switch-default branch) bbs)))
1260 (let ((opnd (jump-opnd branch)))
1263 (lbl-num->bb (lbl-num opnd) bbs)))))
1266 (compiler-internal-error
1267 "bbs-order!, unknown branch type")))))
1269 ; schedule a given basic block 'bb' with it's predecessors and
1272 (define (schedule-from bb)
1273 (queue-put! ordered-blocks bb)
1274 (let ((x (succ-bb bb)))
1277 (schedule-around (remove-bb! x))
1278 (let ((y (succ-bb bb)))
1280 (schedule-around (remove-bb! y)))))))
1283 (define (schedule-around bb)
1284 (let ((x (prec-bb bb)))
1286 (let ((bb-list (schedule-back (remove-bb! x) '())))
1287 (queue-put! ordered-blocks x)
1289 (for-each schedule-refs bb-list))
1290 (schedule-from bb))))
1292 (define (schedule-back bb bb-list)
1293 (let ((bb-list* (cons bb bb-list))
1296 (let ((bb-list (schedule-back (remove-bb! x) bb-list*)))
1297 (queue-put! ordered-blocks x)
1301 (define (schedule-forw bb)
1302 (queue-put! ordered-blocks bb)
1303 (let ((x (succ-bb bb)))
1306 (schedule-forw (remove-bb! x))
1307 (let ((y (succ-bb bb)))
1309 (schedule-around (remove-bb! y)))))))
1312 (define (schedule-refs bb)
1315 (if (left-to-schedule? x)
1316 (schedule-around (remove-bb! x))))
1317 (bb-references bb)))
1319 (schedule-from (remove-bb! (lbl-num->bb (bbs-entry-lbl-num bbs) bbs)))
1321 (let ((basic-blocks (make-stretchable-vector #f))
1322 (lbl-map (make-stretchable-vector #f)))
1324 (define (replacement-lbl-num lbl)
1325 (or (stretchable-vector-ref lbl-map lbl) lbl))
1327 (let loop ((lst (queue->list ordered-blocks)) (i 1))
1330 (let* ((bb (car lst))
1331 (label-instr (bb-label-instr bb)))
1332 (stretchable-vector-set! basic-blocks i bb)
1333 (stretchable-vector-set! lbl-map (label-lbl-num label-instr) i)
1334 (label-lbl-num-set! label-instr i)
1335 (loop (cdr lst) (+ i 1)))
1341 (bbs-next-lbl-num-set! bbs i)
1343 (bbs-basic-blocks-set! bbs basic-blocks)
1345 (bbs-entry-lbl-num-set! bbs
1346 (replacement-lbl-num (bbs-entry-lbl-num bbs)))
1350 (replace-label-references!
1352 replacement-lbl-num))
1355 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1357 ;; Sequentialization of a basic block set:
1358 ;; --------------------------------------
1360 ;; The procedure 'bbs->code-list' transforms a 'purified' basic block set
1361 ;; into a sequence of virtual machine instructions. Each element of the
1362 ;; resulting list is a 'code' object that contains a GVM instruction,
1363 ;; a pointer to the basic block it came from and a `slots needed' index
1364 ;; that specifies the minimum number of slots that have to be kept (relative
1365 ;; to the start of the frame) after the instruction is executed.
1366 ;; The first element of the code list is the entry label for the piece of code.
1368 (define (make-code bb gvm-instr sn) (vector bb gvm-instr sn))
1369 (define (code-bb code) (vector-ref code 0))
1370 (define (code-gvm-instr code) (vector-ref code 1))
1371 (define (code-slots-needed code) (vector-ref code 2))
1372 (define (code-slots-needed-set! code n) (vector-set! code 2 n))
1374 (define (bbs->code-list bbs)
1375 (let ((code-list (linearize bbs)))
1376 (setup-slots-needed! code-list)
1379 (define (linearize bbs) ; convert bbs into list of GVM instructions
1380 (let ((code-queue (queue-empty)))
1384 (define (put-instr gvm-instr)
1385 (queue-put! code-queue (make-code bb gvm-instr #f)))
1387 (put-instr (bb-label-instr bb))
1388 (for-each put-instr (bb-non-branch-instrs bb))
1389 (put-instr (bb-branch-instr bb)))
1391 (bbs-for-each-bb put-bb bbs)
1392 (queue->list code-queue)))
1394 (define (setup-slots-needed! code-list) ; setup slots-needed field
1396 ; Backward pass to set slots-needed field
1398 (let loop1 ((lst (reverse code-list)) (sn-rest #f))
1400 (let* ((code (car lst))
1401 (gvm-instr (code-gvm-instr code)))
1404 (case (gvm-instr-type gvm-instr)
1407 (if (> sn-rest (frame-size (gvm-instr-frame gvm-instr)))
1408 (compiler-internal-error
1409 "setup-slots-needed!, incoherent slots needed for label"))
1410 (code-slots-needed-set! code sn-rest)
1413 ((ifjump switch jump)
1414 (let ((sn (frame-size (gvm-instr-frame gvm-instr))))
1415 (code-slots-needed-set! code sn)
1416 (need-gvm-instr gvm-instr sn)))
1419 (code-slots-needed-set! code sn-rest)
1420 (need-gvm-instr gvm-instr sn-rest))))))))
1422 (define (need-gvm-instrs non-branch branch)
1423 (if (pair? non-branch)
1424 (need-gvm-instr (car non-branch)
1425 (need-gvm-instrs (cdr non-branch) branch))
1426 (need-gvm-instr branch
1427 (frame-size (gvm-instr-frame branch)))))
1429 (define (need-gvm-instr gvm-instr sn-rest)
1430 (case (gvm-instr-type gvm-instr)
1436 (let ((loc (apply-loc gvm-instr)))
1437 (need-gvm-opnds (apply-opnds gvm-instr)
1438 (need-gvm-loc-opnd loc
1439 (need-gvm-loc loc sn-rest)))))
1442 (let ((loc (copy-loc gvm-instr)))
1443 (need-gvm-opnd (copy-opnd gvm-instr)
1444 (need-gvm-loc-opnd loc
1445 (need-gvm-loc loc sn-rest)))))
1448 (let ((parms (close-parms gvm-instr)))
1450 (define (need-parms-opnds p)
1453 (need-gvm-opnds (closure-parms-opnds (car p))
1454 (need-parms-opnds (cdr p)))))
1456 (define (need-parms-loc p)
1458 (need-parms-opnds parms)
1459 (let ((loc (closure-parms-loc (car p))))
1460 (need-gvm-loc-opnd loc
1461 (need-gvm-loc loc (need-parms-loc (cdr p)))))))
1463 (need-parms-loc parms)))
1466 (need-gvm-opnds (ifjump-opnds gvm-instr) sn-rest))
1469 (need-gvm-opnd (switch-opnd gvm-instr) sn-rest))
1472 (need-gvm-opnd (jump-opnd gvm-instr) sn-rest))
1475 (compiler-internal-error
1476 "need-gvm-instr, unknown 'gvm-instr':" gvm-instr))))
1478 (define (need-gvm-loc loc sn-rest)
1479 (if (and loc (stk? loc) (>= (stk-num loc) sn-rest))
1483 (define (need-gvm-loc-opnd gvm-loc slots-needed)
1484 (if (and gvm-loc (clo? gvm-loc))
1485 (need-gvm-opnd (clo-base gvm-loc) slots-needed)
1488 (define (need-gvm-opnd gvm-opnd slots-needed)
1490 (cond ((stk? gvm-opnd)
1491 (max (stk-num gvm-opnd) slots-needed))
1493 (need-gvm-opnd (clo-base gvm-opnd) slots-needed))
1498 (define (need-gvm-opnds gvm-opnds slots-needed)
1499 (if (null? gvm-opnds)
1501 (need-gvm-opnd (car gvm-opnds)
1502 (need-gvm-opnds (cdr gvm-opnds) slots-needed))))
1504 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1506 ;; Basic block writing:
1507 ;; -------------------
1509 (define (write-bb bb port)
1510 (write-gvm-instr (bb-label-instr bb) port)
1511 (display " [precedents=" port)
1512 (write (map bb-lbl-num (bb-precedents bb)) port)
1516 (for-each (lambda (x) (write-gvm-instr x port) (newline port))
1517 (bb-non-branch-instrs bb))
1519 (write-gvm-instr (bb-branch-instr bb) port))
1521 (define (write-bbs bbs port)
1524 (if (= (bb-lbl-num bb) (bbs-entry-lbl-num bbs))
1525 (begin (display "**** Entry block:" port) (newline port)))
1530 (define show-slots-needed? #f)
1531 (set! show-slots-needed? #f)
1533 (define (virtual.dump procs port)
1535 (let ((proc-seen (queue-empty))
1536 (proc-left (queue-empty)))
1538 (define (scan-obj obj)
1539 (if (and (proc-obj? obj)
1541 (not (memq obj (queue->list proc-seen))))
1543 (queue-put! proc-seen obj)
1544 (queue-put! proc-left obj))))
1546 (define (scan-opnd gvm-opnd)
1547 (cond ((not gvm-opnd))
1549 (scan-obj (obj-val gvm-opnd)))
1551 (scan-opnd (clo-base gvm-opnd)))))
1553 (define (dump-proc p)
1555 (define (scan-code code)
1556 (let ((gvm-instr (code-gvm-instr code)))
1558 (if show-slots-needed?
1560 (display "sn=" port)
1561 (display (code-slots-needed code) port)
1562 (display " | " port)))
1564 (write-gvm-instr gvm-instr port)
1566 (case (gvm-instr-type gvm-instr)
1569 (for-each scan-opnd (apply-opnds gvm-instr))
1570 (if (apply-loc gvm-instr)
1571 (scan-opnd (apply-loc gvm-instr))))
1574 (scan-opnd (copy-opnd gvm-instr))
1575 (scan-opnd (copy-loc gvm-instr)))
1578 (for-each (lambda (parms)
1579 (scan-opnd (closure-parms-loc parms))
1580 (for-each scan-opnd (closure-parms-opnds parms)))
1581 (close-parms gvm-instr)))
1584 (for-each scan-opnd (ifjump-opnds gvm-instr)))
1587 (scan-opnd (switch-opnd gvm-instr))
1588 (for-each (lambda (c) (scan-obj (switch-case-obj c)))
1589 (switch-cases gvm-instr)))
1592 (scan-opnd (jump-opnd gvm-instr)))
1597 (if (proc-obj-primitive? p)
1598 (display "**** #<primitive " port)
1599 (display "**** #<procedure " port))
1600 (write (string->canonical-symbol (proc-obj-name p)) port)
1601 (display "> =" port)
1604 (let ((x (proc-obj-code p)))
1607 (let loop ((l (bbs->code-list x))
1611 (let* ((code (car l))
1612 (instr (code-gvm-instr code))
1613 (node (comment-get (gvm-instr-comment instr) 'node))
1614 (src (node-source node))
1615 (loc (and src (source-locat src)))
1617 (if (and loc (string? (vector-ref loc 0)));;;;;;;;;;;;;
1621 (if (and loc (string? (vector-ref loc 0)))
1622 (+ (**filepos-line (vector-ref loc 1)) 1)
1624 (if (or (not (string=? filename prev-filename))
1625 (not (= line prev-line)))
1627 (display "#line " port)
1629 (if (not (string=? filename prev-filename))
1632 (write filename port)))
1636 (loop (cdr l) filename line))
1640 (display "C procedure of arity " port)
1641 (display (c-proc-arity x) port)
1642 (display " and body:" port)
1644 (display (c-proc-body x) port)
1647 (for-each (lambda (proc) (scan-opnd (make-obj proc))) procs)
1650 (if (not (queue-empty? proc-left))
1652 (dump-proc (queue-get! proc-left))
1655 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1657 ;; Virtual instruction writing:
1658 ;; ---------------------------
1660 (define (write-gvm-instr gvm-instr port)
1662 (define (write-closure-parms parms)
1664 (let ((len (+ 1 (write-gvm-opnd (closure-parms-loc parms) port))))
1665 (display " = (" port)
1666 (let ((len (+ len (+ 4 (write-gvm-lbl (closure-parms-lbl parms) port)))))
1667 (+ len (write-spaced-opnd-list (closure-parms-opnds parms) port)))))
1669 (define (write-spaced-opnd-list l port)
1670 (let loop ((l l) (len 0))
1672 (let ((opnd (car l)))
1674 (loop (cdr l) (+ len (+ 1 (write-gvm-opnd opnd port)))))
1679 (define (write-opnd-list l port)
1681 (let ((len (write-gvm-opnd (car l) port)))
1682 (+ len (write-spaced-opnd-list (cdr l) port)))
1687 (define (write-key-pair-list keys port)
1692 (let loop ((l keys))
1693 (let* ((key-pair (car l))
1694 (key (car key-pair))
1695 (opnd (cdr key-pair))
1698 (let ((len (+ 1 (write-returning-len key port))))
1700 (let ((len (+ len (+ 1 (write-gvm-opnd opnd port)))))
1705 (+ len (+ 2 (loop rest))))
1714 (define (write-param-pattern gvm-instr port)
1715 (let ((len (write-returning-len
1716 (label-entry-nb-parms gvm-instr)
1722 (label-entry-opts gvm-instr)
1725 (write-key-pair-list
1726 (label-entry-keys gvm-instr)
1728 (if (label-entry-rest? gvm-instr)
1729 (begin (display " +" port) (+ len 2))
1732 (define (write-prim-applic prim opnds port)
1734 (let ((len (+ 1 (display-returning-len (proc-obj-name prim) port))))
1735 (+ len (write-spaced-opnd-list opnds port))))
1737 (define (write-instr gvm-instr)
1738 (case (gvm-instr-type gvm-instr)
1741 (let ((len (write-gvm-lbl (label-lbl-num gvm-instr) port)))
1744 (+ 1 (write-returning-len
1745 (frame-size (gvm-instr-frame gvm-instr))
1747 (case (label-type gvm-instr)
1751 (if (label-entry-closed? gvm-instr)
1753 (display " closure-entry-point " port)
1754 (+ len (+ 21 (write-param-pattern gvm-instr port))))
1756 (display " entry-point " port)
1757 (+ len (+ 13 (write-param-pattern gvm-instr port))))))
1759 (display " return-point" port)
1762 (display " task-entry-point" port)
1765 (display " task-return-point" port)
1768 (compiler-internal-error
1769 "write-gvm-instr, unknown label type"))))))
1773 (let ((len (+ 2 (write-gvm-opnd (apply-loc gvm-instr) port))))
1774 (display " = " port)
1777 (write-prim-applic (apply-prim gvm-instr)
1778 (apply-opnds gvm-instr)
1783 (let ((len (+ 2 (write-gvm-opnd (copy-loc gvm-instr) port))))
1784 (display " = " port)
1785 (+ len (+ 3 (write-gvm-opnd (copy-opnd gvm-instr) port)))))
1788 (display " close" port)
1789 (let ((len (+ 7 (write-closure-parms (car (close-parms gvm-instr))))))
1790 (let loop ((l (cdr (close-parms gvm-instr))) (len len))
1794 (loop (cdr l) (+ len (+ 1 (write-closure-parms x)))))
1798 (display " if " port)
1800 (write-prim-applic (ifjump-test gvm-instr)
1801 (ifjump-opnds gvm-instr)
1804 (if (ifjump-poll? gvm-instr)
1805 (begin (display " jump* " port) 7)
1806 (begin (display " jump " port) 6)))))
1808 (write-returning-len
1809 (frame-size (gvm-instr-frame gvm-instr))
1814 (ifjump-true gvm-instr)
1816 (display " else " port)
1817 (+ len (+ 6 (write-gvm-lbl
1818 (ifjump-false gvm-instr)
1824 (if (switch-poll? gvm-instr)
1825 (begin (display "switch* " port) 8)
1826 (begin (display "switch " port) 7)))))
1828 (write-returning-len
1829 (frame-size (gvm-instr-frame gvm-instr))
1833 (+ 1 (write-gvm-opnd (switch-opnd gvm-instr) port)))))
1836 (let loop ((cases (switch-cases gvm-instr))
1839 (let ((c (car cases)))
1841 (write-gvm-obj (switch-case-obj c)
1843 (display " => " port)
1845 (+ 4 (write-gvm-lbl (switch-case-lbl c)
1847 (let ((next (cdr cases)))
1852 (loop next (+ len 2))))))))
1857 (switch-default gvm-instr)
1863 (if (jump-poll? gvm-instr)
1864 (begin (display "jump*" port) 5)
1865 (begin (display "jump" port) 4)))))
1867 (if (jump-safe? gvm-instr)
1868 (begin (display "$ " port) 2)
1869 (begin (display " " port) 1)))))
1871 (write-returning-len
1872 (frame-size (gvm-instr-frame gvm-instr))
1876 (+ 1 (write-gvm-opnd (jump-opnd gvm-instr) port)))))
1878 (if (jump-nb-args gvm-instr)
1881 (+ 1 (write-returning-len
1882 (jump-nb-args gvm-instr)
1887 (compiler-internal-error
1888 "write-gvm-instr, unknown 'gvm-instr':"
1894 (begin (display " " port) (spaces (- n 8)))
1895 (begin (display " " port) (spaces (- n 1))))))
1897 (let ((len (write-instr gvm-instr)))
1900 (write-frame (gvm-instr-frame gvm-instr) port))
1902 (let ((x (gvm-instr-comment gvm-instr)))
1904 (let ((y (comment-get x 'text)))
1907 (display " ; " port)
1908 (display y port)))))))
1910 (define (write-frame frame port)
1912 (define (write-var var opnd sep)
1914 (write-gvm-opnd opnd port)
1918 (cond ((eq? var closure-env-var)
1919 (write (map (lambda (var) (var-name var)) (frame-closed frame))
1926 (write (var-name var) port))))))
1929 (let ((live (frame-live frame)))
1930 (or (varset-member? var live)
1931 (and (eq? var closure-env-var)
1934 (list->varset (frame-closed frame)))))))
1936 (let loop1 ((i 1) (l (reverse (frame-slots frame))) (sep "; "))
1938 (let ((var (car l)))
1939 (write-var (if (live? var) var #f) (make-stk i) sep)
1940 (loop1 (+ i 1) (cdr l) " "))
1941 (let loop2 ((i 0) (l (frame-regs frame)) (sep sep))
1943 (let ((var (car l)))
1946 (write-var var (make-reg i) sep)
1947 (loop2 (+ i 1) (cdr l) " "))
1948 (loop2 (+ i 1) (cdr l) sep))))))))
1950 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1955 (define (write-gvm-opnd gvm-opnd port)
1956 (cond ((not gvm-opnd)
1961 (+ 1 (write-returning-len (reg-num gvm-opnd) port)))
1964 (+ 1 (write-returning-len (stk-num gvm-opnd) port)))
1966 (write-returning-len (glo-name gvm-opnd) port))
1968 (let ((len (write-gvm-opnd (clo-base gvm-opnd) port)))
1971 (+ 1 (write-returning-len
1972 (clo-index gvm-opnd)
1977 (write-gvm-lbl (lbl-num gvm-opnd) port))
1980 (+ (write-gvm-obj (obj-val gvm-opnd) port) 1))
1982 (compiler-internal-error
1983 "write-gvm-opnd, unknown 'gvm-opnd':"
1986 (define (write-gvm-lbl lbl port)
1988 (+ (write-returning-len lbl port) 1))
1990 (define (write-gvm-obj val port)
1991 (cond ((proc-obj? val)
1992 (if (proc-obj-primitive? val)
1993 (display "#<primitive " port)
1994 (display "#<procedure " port))
1996 (write-returning-len
1997 (string->canonical-symbol (proc-obj-name val))
2002 (write-returning-len val port))))
2004 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2006 (define (virtual.begin!) ; initialize module
2007 (set! *opnd-table* '#())
2008 (set! *opnd-table-alloc* 0)
2011 (define (virtual.end!) ; finalize module
2012 (set! *opnd-table* '())
2015 ;;;============================================================================