1 ;;;; File: "comp.scm", Time-stamp: <2009-08-21 23:41:38 feeley>
3 ;;;; Copyright (C) 2004-2009 by Marc Feeley and Vincent St-Amour
4 ;;;; All Rights Reserved.
6 (define gen-instruction
7 (lambda (instr nb-pop nb-push ctx)
15 (context-add-instr (context-change-env ctx (env-change-local env stk))
19 (lambda (nparams rest? ctx)
20 (gen-instruction (list 'entry nparams rest?) 0 0 ctx)))
22 (define gen-push-constant
24 (gen-instruction (list 'push-constant val) 0 1 ctx)))
26 (define gen-push-unspecified
28 (gen-push-constant #f ctx)))
30 (define gen-push-local-var
32 ; (pp (list var: var local: (stack-slots (env-local (context-env ctx))) (env-closed (context-env ctx))))
33 (let ((i (find-local-var var (context-env ctx))))
35 (gen-push-stack i ctx)
38 (length (stack-slots (env-local (context-env ctx))))) ctx)))))
40 (define gen-push-stack
42 (gen-instruction (list 'push-stack pos) 0 1 ctx)))
44 (define gen-push-global
46 (gen-instruction (list 'push-global var) 0 1 ctx)))
48 (define gen-set-global
50 (gen-instruction (list 'set-global var) 1 0 ctx)))
54 (gen-instruction (list 'call nargs) (+ nargs 1) 1 ctx)))
58 (gen-instruction (list 'jump nargs) (+ nargs 1) 1 ctx)))
60 (define gen-call-toplevel
61 (lambda (nargs id ctx)
62 (gen-instruction (list 'call-toplevel id) nargs 1 ctx)))
64 (define gen-jump-toplevel
65 (lambda (nargs id ctx)
66 (gen-instruction (list 'jump-toplevel id) nargs 1 ctx)))
70 (gen-instruction (list 'goto label) 0 0 ctx)))
72 (define gen-goto-if-false
73 (lambda (label-false label-true ctx)
74 (gen-instruction (list 'goto-if-false label-false label-true) 1 0 ctx)))
77 (lambda (label-entry ctx)
78 (gen-instruction (list 'closure label-entry) 1 1 ctx)))
81 (lambda (id nargs unspec-result? ctx)
85 (if unspec-result? 0 1)
91 (gen-instruction (list 'shift) 1 0 (gen-shift (- n 1) ctx))
96 (gen-instruction (list 'pop) 1 0 ctx)))
100 (let ((ss (stack-size (env-local (context-env ctx)))))
101 (gen-instruction (list 'return) ss 0 ctx))))
103 ;-----------------------------------------------------------------------------
107 (car (node-children node))))
111 (cadr (node-children node))))
115 (caddr (node-children node))))
120 (cond ((or (cst? node)
126 (let ((var (def-var node)))
127 (if (toplevel-prc-with-non-rest-correct-calls? var)
128 (comp-prc (child1 node) #f ctx)
129 (if (var-needed? var)
130 (let ((ctx2 (comp-push (child1 node) ctx)))
131 (gen-set-global (var-id var) ctx2))
132 (comp-none (child1 node) ctx)))))
135 (let ((var (set-var node)))
136 (if (var-needed? var)
137 (let ((ctx2 (comp-push (child1 node) ctx)))
138 (gen-set-global (var-id var) ctx2))
139 (comp-none (child1 node) ctx))))
143 (context-make-label ctx))
145 (context-last-label ctx2))
147 (context-make-label ctx2))
149 (context-last-label ctx3))
151 (context-make-label ctx3))
153 (context-last-label ctx4))
155 (context-make-label ctx4))
157 (context-last-label ctx5))
159 (context-make-label ctx5))
161 (context-last-label ctx6))
163 (comp-test (child1 node) label-then label-else ctx6))
167 (comp-none (child3 node)
169 (context-add-bb ctx7 label-else)
174 (comp-none (child2 node)
176 (context-add-bb ctx8 label-then)
177 (context-env2 ctx7)))))
181 (context-add-bb ctx9 label-else-join)))
185 (context-add-bb ctx10 label-then-join)))
187 (context-add-bb ctx11 label-join)))
191 (comp-call node 'none ctx))
194 (let ((children (node-children node)))
197 (let loop ((lst children)
199 (if (null? (cdr lst))
200 (comp-none (car lst) ctx)
202 (comp-none (car lst) ctx)))))))
205 (compiler-error "unknown expression type" node)))))
210 (cond ((or (cst? node)
217 (gen-return (comp-push node ctx)))
221 (context-make-label ctx))
223 (context-last-label ctx2))
225 (context-make-label ctx2))
227 (context-last-label ctx3))
229 (comp-test (child1 node) label-then label-else ctx3))
231 (comp-tail (child3 node)
233 (context-add-bb ctx4 label-else)
236 (comp-tail (child2 node)
238 (context-add-bb ctx5 label-then)
239 (context-env2 ctx4)))))
243 (comp-call node 'tail ctx))
246 (let ((children (node-children node)))
248 (gen-return (gen-push-unspecified ctx))
249 (let loop ((lst children)
251 (if (null? (cdr lst))
252 (comp-tail (car lst) ctx)
254 (comp-none (car lst) ctx)))))))
257 (compiler-error "unknown expression type" node)))))
263 (display "--------------\n")
264 (pp (node->expr node))
270 (let ((val (cst-val node)))
271 (gen-push-constant val ctx)))
274 (let ((var (ref-var node)))
275 (if (var-global? var)
276 (if (null? (var-defs var))
277 (compiler-error "undefined variable:" (var-id var))
278 (let ((val (child1 (car (var-defs var)))))
279 (if (and (not (mutable-var? var))
280 (cst? val)) ;; immutable global, counted as cst
281 (gen-push-constant (cst-val val) ctx)
282 (gen-push-global (var-id var) ctx))))
283 (gen-push-local-var (var-id var) ctx))))
287 (gen-push-unspecified (comp-none node ctx)))
291 (context-make-label ctx))
293 (context-last-label ctx2))
295 (context-make-label ctx2))
297 (context-last-label ctx3))
299 (context-make-label ctx3))
301 (context-last-label ctx4))
303 (context-make-label ctx4))
305 (context-last-label ctx5))
307 (context-make-label ctx5))
309 (context-last-label ctx6))
311 (comp-test (child1 node) label-then label-else ctx6))
315 (comp-push (child3 node)
317 (context-add-bb ctx7 label-else)
322 (comp-push (child2 node)
324 (context-add-bb ctx8 label-then)
325 (context-env2 ctx7)))))
329 (context-add-bb ctx9 label-else-join)))
333 (context-add-bb ctx10 label-then-join)))
335 (context-add-bb ctx11 label-join)))
339 (comp-prc node #t ctx))
342 (comp-call node 'push ctx))
345 (let ((children (node-children node)))
347 (gen-push-unspecified ctx)
348 (let loop ((lst children)
350 (if (null? (cdr lst))
351 (comp-push (car lst) ctx)
353 (comp-none (car lst) ctx)))))))
356 (compiler-error "unknown expression type" node)))))
358 (define (build-closure label-entry vars ctx)
360 (define (build vars ctx)
362 (gen-push-constant '() ctx)
367 (gen-push-local-var (car vars) ctx)))))
370 (gen-closure label-entry
371 (gen-push-constant '() ctx))
372 (gen-closure label-entry
376 (lambda (node closure? ctx)
378 (context-make-label ctx))
380 (context-last-label ctx2))
382 (context-make-label ctx2))
384 (context-last-label ctx3))
389 (build-closure label-entry (env-closed body-env) ctx3)
392 (gen-goto label-continue ctx4))
394 (gen-entry (length (prc-params node))
396 (context-add-bb (context-change-env ctx5
400 (comp-tail (child1 node) ctx6)))
401 (prc-entry-label-set! node label-entry)
402 (context-add-bb (context-change-env ctx7 (context-env ctx5))
406 (lambda (node reason ctx)
407 (let* ((op (child1 node))
408 (args (cdr (node-children node)))
409 (nargs (length args)))
410 (let loop ((lst args)
414 (let ((arg (car lst)))
416 (comp-push arg ctx)))
418 (cond ((and (ref? op)
419 (var-primitive (ref-var op)))
420 (let* ((var (ref-var op))
422 (primitive (var-primitive var))
423 (prim-nargs (primitive-nargs primitive)))
427 (cond ((eq? reason 'tail)
429 (if (primitive-unspecified-result? primitive)
430 (gen-push-unspecified ctx2)
433 (if (primitive-unspecified-result? primitive)
434 (gen-push-unspecified ctx2)
437 (if (primitive-unspecified-result? primitive)
442 (if (primitive-inliner primitive)
443 ((primitive-inliner primitive) ctx)
445 (not (= nargs prim-nargs))
447 "primitive called with wrong number of arguments"
452 (primitive-unspecified-result? primitive)
457 (toplevel-prc-with-non-rest-correct-calls?
461 (cond ((eq? reason 'tail)
462 (gen-jump-toplevel nargs prc ctx))
464 (gen-call-toplevel nargs prc ctx))
466 (gen-pop (gen-call-toplevel nargs prc ctx))))))
469 (let ((ctx2 (comp-push op ctx)))
470 (cond ((eq? reason 'tail)
471 (gen-jump nargs ctx2))
473 (gen-call nargs ctx2))
475 (gen-pop (gen-call nargs ctx2))))))))))))
478 (lambda (node label-true label-false ctx)
482 (let ((val (cst-val node)))
487 (context-change-env2 ctx2 (context-env ctx2))))
496 (comp-push node ctx))
498 (gen-goto-if-false label-false label-true ctx2)))
499 (context-change-env2 ctx3 (context-env ctx3))))
503 (gen-goto label-true ctx)))
504 (context-change-env2 ctx2 (context-env ctx2))))
507 (compiler-error "unknown expression type" node)))))
509 ;-----------------------------------------------------------------------------
511 (define toplevel-prc?
513 (and (not (mutable-var? var))
514 (let ((d (var-defs var)))
517 (let ((val (child1 (car d))))
521 (define toplevel-prc-with-non-rest-correct-calls?
523 (let ((prc (toplevel-prc? var)))
525 (not (prc-rest? prc))
527 (let ((parent (node-parent r)))
529 (eq? (child1 parent) r)
530 (= (length (prc-params prc))
531 (- (length (node-children parent)) 1)))))
537 (not (null? (var-sets var)))))
543 (varset->list (fv node))))))
545 (define non-global-fv
548 (keep (lambda (x) (not (var-global? x)))
549 (varset->list (fv node))))))
556 (let ((var (ref-var node)))
557 (varset-singleton var)))
559 (let ((var (def-var node))
562 (varset-singleton var)
565 (let ((var (set-var node))
568 (varset-singleton var)
571 (let ((a (list-ref (node-children node) 0))
572 (b (list-ref (node-children node) 1))
573 (c (list-ref (node-children node) 2)))
574 (varset-union-multi (list (fv a) (fv b) (fv c)))))
576 (let ((body (list-ref (node-children node) 0)))
579 (build-params-varset (prc-params node)))))
581 (varset-union-multi (map fv (node-children node))))
583 (varset-union-multi (map fv (node-children node))))
585 (compiler-error "unknown expression type" node)))))
587 (define build-params-varset
589 (list->varset params)))
591 (define mark-needed-global-vars!
592 (lambda (global-env node)
595 (env-lookup global-env '#%readyq))
599 (if (and (var-global? var)
600 (not (var-needed? var))
601 ;; globals that obey the following conditions are considered
603 (not (and (not (mutable-var? var))
604 ;; to weed out primitives, which have no definitions
605 (> (length (var-defs var)) 0)
606 (cst? (child1 (car (var-defs var)))))))
608 (var-needed?-set! var #t)
611 (let ((val (child1 def)))
612 (if (side-effect-less? val)
618 (env-lookup global-env '#%start-first-process))
620 (env-lookup global-env '#%exit))))))))
622 (define side-effect-less?
632 (let ((var (ref-var node)))
635 (let ((var (def-var node))
637 (if (not (side-effect-less? val))
640 (let ((var (set-var node))
644 (let ((a (list-ref (node-children node) 0))
645 (b (list-ref (node-children node) 1))
646 (c (list-ref (node-children node) 2)))
651 (let ((body (list-ref (node-children node) 0)))
654 (for-each mark! (node-children node)))
656 (for-each mark! (node-children node)))
658 (compiler-error "unknown expression type" node)))))
663 ;-----------------------------------------------------------------------------
667 (define (varset-empty) ; return the empty set
670 (define (varset-singleton x) ; create a set containing only 'x'
673 (define (list->varset lst) ; convert list to set
676 (define (varset->list set) ; convert set to list
679 (define (varset-size set) ; return cardinality of set
682 (define (varset-empty? set) ; is 'x' the empty set?
685 (define (varset-member? x set) ; is 'x' a member of the 'set'?
686 (and (not (null? set))
687 (or (eq? x (car set))
688 (varset-member? x (cdr set)))))
690 (define (varset-adjoin set x) ; add the element 'x' to the 'set'
691 (if (varset-member? x set) set (cons x set)))
693 (define (varset-remove set x) ; remove the element 'x' from 'set'
699 (cons (car set) (varset-remove (cdr set) x)))))
701 (define (varset-equal? s1 s2) ; are 's1' and 's2' equal sets?
702 (and (varset-subset? s1 s2)
703 (varset-subset? s2 s1)))
705 (define (varset-subset? s1 s2) ; is 's1' a subset of 's2'?
708 ((varset-member? (car s1) s2)
709 (varset-subset? (cdr s1) s2))
713 (define (varset-difference set1 set2) ; return difference of sets
716 ((varset-member? (car set1) set2)
717 (varset-difference (cdr set1) set2))
719 (cons (car set1) (varset-difference (cdr set1) set2)))))
721 (define (varset-union set1 set2) ; return union of sets
722 (define (union s1 s2)
725 ((varset-member? (car s1) s2)
728 (cons (car s1) (union (cdr s1) s2)))))
729 (if (varset-smaller? set1 set2)
733 (define (varset-intersection set1 set2) ; return intersection of sets
734 (define (intersection s1 s2)
737 ((varset-member? (car s1) s2)
738 (cons (car s1) (intersection (cdr s1) s2)))
740 (intersection (cdr s1) s2))))
741 (if (varset-smaller? set1 set2)
742 (intersection set1 set2)
743 (intersection set2 set1)))
745 (define (varset-intersects? set1 set2) ; do sets 'set1' and 'set2' intersect?
746 (not (varset-empty? (varset-intersection set1 set2))))
748 (define (varset-smaller? set1 set2)
753 (varset-smaller? (cdr set1) (cdr set2)))))
755 (define (varset-union-multi sets)
758 (n-ary varset-union (car sets) (cdr sets))))
760 (define (n-ary function first rest)
763 (n-ary function (function first (car rest)) (cdr rest))))
765 ;------------------------------------------------------------------------------
769 (let ((v (make-vector (+ (code-last-label code) 1))))
772 (vector-set! v (bb-label bb) bb))
776 (define bbs->ref-counts
778 (let ((ref-counts (make-vector (vector-length bbs) 0)))
782 (let ((ref-count (vector-ref ref-counts label)))
783 (vector-set! ref-counts label (+ ref-count 1))
785 (let* ((bb (vector-ref bbs label))
786 (rev-instrs (bb-rev-instrs bb)))
789 (let ((opcode (car instr)))
790 (cond ((eq? opcode 'goto)
791 (visit (cadr instr)))
792 ((eq? opcode 'goto-if-false)
794 (visit (caddr instr)))
795 ((or (eq? opcode 'closure)
796 (eq? opcode 'call-toplevel)
797 (eq? opcode 'jump-toplevel))
798 (visit (cadr instr))))))
805 (define resolve-toplevel-labels!
808 (if (< i (vector-length bbs))
809 (let* ((bb (vector-ref bbs i))
810 (rev-instrs (bb-rev-instrs bb)))
814 (let ((opcode (car instr)))
815 (cond ((eq? opcode 'call-toplevel)
817 (prc-entry-label (cadr instr))))
818 ((eq? opcode 'jump-toplevel)
820 (prc-entry-label (cadr instr))))
826 (define tighten-jump-cascades!
828 (let ((ref-counts (bbs->ref-counts bbs)))
832 (let* ((bb (vector-ref bbs label))
833 (rev-instrs (bb-rev-instrs bb)))
834 (and (or (null? (cdr rev-instrs))
835 (= (vector-ref ref-counts label) 1))
841 (if (< i (vector-length bbs))
842 (if (> (vector-ref ref-counts i) 0)
843 (let* ((bb (vector-ref bbs i))
844 (rev-instrs (bb-rev-instrs bb))
845 (jump (car rev-instrs))
847 (cond ((eq? opcode 'goto)
848 (let* ((label (cadr jump))
849 (jump-replacement (resolve label)))
855 (make-bb (bb-label bb)
856 (append jump-replacement
862 ((eq? opcode 'goto-if-false)
863 (let* ((label-then (cadr jump))
864 (label-else (caddr jump))
865 (jump-then-replacement (resolve label-then))
866 (jump-else-replacement (resolve label-else)))
867 (if (and jump-then-replacement
868 (null? (cdr jump-then-replacement))
869 jump-else-replacement
870 (null? (cdr jump-else-replacement))
871 (or (eq? (caar jump-then-replacement)
873 (eq? (caar jump-else-replacement)
884 (if (eq? (caar jump-then-replacement)
886 (cadar jump-then-replacement)
888 (if (eq? (caar jump-else-replacement)
890 (cadar jump-else-replacement)
905 (define remove-useless-bbs!
907 (let ((ref-counts (bbs->ref-counts bbs)))
908 (let loop1 ((label 0) (new-label 0))
909 (if (< label (vector-length bbs))
910 (if (> (vector-ref ref-counts label) 0)
911 (let ((bb (vector-ref bbs label)))
915 (make-bb new-label (bb-rev-instrs bb)))
916 (loop1 (+ label 1) (+ new-label 1)))
917 (loop1 (+ label 1) new-label))
918 (renumber-labels bbs ref-counts new-label))))))
920 (define renumber-labels
921 (lambda (bbs ref-counts n)
922 (let ((new-bbs (make-vector n)))
923 (let loop2 ((label 0))
924 (if (< label (vector-length bbs))
925 (if (> (vector-ref ref-counts label) 0)
926 (let* ((bb (vector-ref bbs label))
927 (new-label (bb-label bb))
928 (rev-instrs (bb-rev-instrs bb)))
935 (bb-label (vector-ref bbs label))))
937 (let ((opcode (car instr)))
938 (cond ((eq? opcode 'closure)
940 (new-label (cadr instr))))
941 ((eq? opcode 'call-toplevel)
943 (new-label (cadr instr))))
944 ((eq? opcode 'jump-toplevel)
946 (new-label (cadr instr))))
949 (new-label (cadr instr))))
950 ((eq? opcode 'goto-if-false)
952 (new-label (cadr instr))
953 (new-label (caddr instr))))
960 (make-bb new-label (map fix rev-instrs)))
967 (let* ((done (make-vector (vector-length bbs) #f)))
971 (not (vector-ref done label))))
974 (lambda (instrs todo)
976 (let* ((instr (car instrs))
977 (opcode (car instr)))
978 (cond ((or (eq? opcode 'closure)
979 (eq? opcode 'call-toplevel)
980 (eq? opcode 'jump-toplevel))
981 (label-refs (cdr instrs) (cons (cadr instr) todo)))
983 (label-refs (cdr instrs) todo))))
986 (define schedule-here
987 (lambda (label new-label todo cont)
988 (let* ((bb (vector-ref bbs label))
989 (rev-instrs (bb-rev-instrs bb))
990 (jump (car rev-instrs))
992 (new-todo (label-refs rev-instrs todo)))
993 (vector-set! bbs label (make-bb new-label rev-instrs))
994 (vector-set! done label #t)
995 (cond ((eq? opcode 'goto)
996 (let ((label (cadr jump)))
997 (if (unscheduled? label)
1002 (cont (+ new-label 1)
1004 ((eq? opcode 'goto-if-false)
1005 (let ((label-then (cadr jump))
1006 (label-else (caddr jump)))
1007 (cond ((unscheduled? label-else)
1008 (schedule-here label-else
1010 (cons label-then new-todo)
1012 ((unscheduled? label-then)
1013 (schedule-here label-then
1018 (cont (+ new-label 1)
1021 (cont (+ new-label 1)
1024 (define schedule-somewhere
1025 (lambda (label new-label todo cont)
1026 (schedule-here label new-label todo cont)))
1028 (define schedule-todo
1029 (lambda (new-label todo)
1031 (let ((label (car todo)))
1032 (if (unscheduled? label)
1033 (schedule-somewhere label
1037 (schedule-todo new-label
1041 (schedule-here 0 0 '() schedule-todo)
1043 (renumber-labels bbs
1044 (make-vector (vector-length bbs) 1)
1045 (vector-length bbs)))))
1047 (define linearize-old
1049 (let loop ((label (- (vector-length bbs) 1))
1052 (let* ((bb (vector-ref bbs label))
1053 (rev-instrs (bb-rev-instrs bb))
1054 (jump (car rev-instrs))
1055 (opcode (car jump)))
1060 (cond ((eq? opcode 'goto)
1061 (if (= (cadr jump) (+ label 1))
1064 ((eq? opcode 'goto-if-false)
1065 (cond ((= (caddr jump) (+ label 1))
1066 (cons (list 'goto-if-false (cadr jump))
1068 ((= (cadr jump) (+ label 1))
1069 (cons (list 'goto-if-not-false (caddr jump))
1072 (cons (list 'goto (caddr jump))
1073 (cons (list 'goto-if-false (cadr jump))
1074 (cdr rev-instrs))))))
1083 (define rev-code '())
1088 (set! pos (+ pos 1))
1089 (set! rev-code (cons x rev-code)))
1091 (define todo (cons '() '()))
1093 (define dumped (make-vector (vector-length bbs) #f))
1095 (define (get fallthrough-to-next?)
1096 (if (pair? (cdr todo))
1097 (if fallthrough-to-next?
1098 (let* ((label-pos (cadr todo))
1099 (label (car label-pos))
1101 (if (not (pair? rest))
1102 (set-car! todo todo))
1103 (set-cdr! todo rest)
1105 (let loop ((x (cdr todo)) (best-label-pos #f))
1108 (if (not (vector-ref dumped (car (car x))))
1112 (if (vector-ref dumped (car (car x)))
1114 (if (or (not best-label-pos)
1115 (> (cdr (car x)) (cdr best-label-pos)))
1118 (if (pair? best-label-pos)
1119 (car best-label-pos)
1124 (let loop ((x (cdr todo)))
1126 (let* ((label-pos (car x))
1127 (label (car label-pos)))
1128 (if (not (vector-ref dumped label))
1133 (define (schedule! label tail?)
1134 (let ((label-pos (cons label pos)))
1136 (let ((cell (cons label-pos '())))
1137 (set-cdr! (car todo) cell)
1138 (set-car! todo cell))
1139 (let ((cell (cons label-pos (cdr todo))))
1140 (set-cdr! todo cell)
1141 (if (eq? (car todo) todo)
1142 (set-car! todo cell))))))
1145 (let loop ((fallthrough-to-next? #t))
1146 (let ((label (get fallthrough-to-next?)))
1148 (if (not (vector-ref dumped label))
1150 (vector-set! dumped label #t)
1151 (loop (dump-bb label)))
1152 (loop fallthrough-to-next?))))))
1154 (define (dump-bb label)
1155 (let* ((bb (vector-ref bbs label))
1156 (rev-instrs (bb-rev-instrs bb))
1157 (jump (car rev-instrs))
1158 (opcode (car jump)))
1163 ((closure call-toplevel)
1164 (schedule! (cadr instr) #t)))
1166 (reverse (cdr rev-instrs)))
1167 (cond ((eq? opcode 'goto)
1168 (schedule! (cadr jump) #f)
1169 (if (not (equal? (cadr jump) (next)))
1174 ((eq? opcode 'goto-if-false)
1175 (schedule! (cadr jump) #f)
1176 (schedule! (caddr jump) #f)
1177 (cond ((equal? (caddr jump) (next))
1178 (emit (list 'goto-if-false (cadr jump)))
1180 ((equal? (cadr jump) (next))
1181 (emit (list 'prim '#%not))
1182 (emit (list 'goto-if-false (caddr jump)))
1185 (emit (list 'goto-if-false (cadr jump)))
1186 (emit (list 'goto (caddr jump)))
1191 (schedule! (cadr jump) #f)
1192 ;; it is not correct to remove jump-toplevel when label is next
1193 (if #t ;; (not (equal? (cadr jump) (next)))
1202 (set-car! todo todo) ;; make fifo
1208 (reverse rev-code)))
1210 (define optimize-code
1212 (let ((bbs (code->vector code)))
1213 (resolve-toplevel-labels! bbs)
1214 (tighten-jump-cascades! bbs)
1215 (let ((bbs (remove-useless-bbs! bbs)))