Remove $void CPS expression type
[bpt/guile.git] / module / language / cps / slot-allocation.scm
index 85f69b5..f9a8695 100644 (file)
@@ -1,6 +1,6 @@
 ;;; Continuation-passing style (CPS) intermediate language (IL)
 
-;; Copyright (C) 2013, 2014 Free Software Foundation, Inc.
+;; Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc.
 
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,7 @@
   #:use-module (srfi srfi-26)
   #:use-module (language cps)
   #:use-module (language cps dfg)
+  #:use-module (language cps intset)
   #:export (allocate-slots
             lookup-slot
             lookup-maybe-slot
@@ -223,13 +224,11 @@ are comparable with eqv?.  A tmp slot may be used."
                             tmp)
                       (loop to-move b (cons s+d moved) last-source))))))))))
 
-(define (dead-after-def? def-k v-idx dfa)
-  (let ((l (dfa-k-idx dfa def-k)))
-    (not (bitvector-ref (dfa-k-in dfa l) v-idx))))
+(define (dead-after-def? k-idx v-idx dfa)
+  (not (intset-ref (dfa-k-in dfa k-idx) v-idx)))
 
-(define (dead-after-use? use-k v-idx dfa)
-  (let ((l (dfa-k-idx dfa use-k)))
-    (not (bitvector-ref (dfa-k-out dfa l) v-idx))))
+(define (dead-after-use? k-idx v-idx dfa)
+  (not (intset-ref (dfa-k-out dfa k-idx) v-idx)))
 
 (define (allocate-slots fun dfg)
   (let* ((dfa (compute-live-variables fun dfg))
@@ -264,20 +263,28 @@ are comparable with eqv?.  A tmp slot may be used."
       (logand live-slots (lognot (ash 1 slot))))
 
     (define (compute-slot live-slots hint)
-      (if (and hint (not (logbit? hint live-slots)))
+      ;; Slots 253-255 are reserved for shuffling; see comments in
+      ;; assembler.scm.
+      (if (and hint (not (logbit? hint live-slots))
+               (or (< hint 253) (> hint 255)))
           hint
-          (find-first-zero live-slots)))
+          (let ((slot (find-first-zero live-slots)))
+            (if (or (< slot 253) (> slot 255))
+                slot
+                (+ 256 (find-first-zero (ash live-slots -256)))))))
 
     (define (compute-call-proc-slot live-slots)
       (+ 2 (find-first-trailing-zero live-slots)))
 
     (define (compute-prompt-handler-proc-slot live-slots)
-      (1- (find-first-trailing-zero live-slots)))
+      (if (zero? live-slots)
+          0
+          (1- (find-first-trailing-zero live-slots))))
 
     (define (recompute-live-slots k nargs)
-      (let ((in (dfa-k-in dfa (dfa-k-idx dfa k))))
-        (let lp ((v 0) (live-slots (1- (ash 1 (1+ nargs)))))
-          (let ((v (bit-position #t in v)))
+      (let ((in (dfa-k-in dfa (label->idx k))))
+        (let lp ((v 0) (live-slots 0))
+          (let ((v (intset-next in v)))
             (if v
                 (let ((slot (vector-ref slots v)))
                   (lp (1+ v)
@@ -307,6 +314,12 @@ are comparable with eqv?.  A tmp slot may be used."
     ;; or to function return values -- it could be that they are out of
     ;; the computed live set.  In that case they need to be adjoined to
     ;; the live set, used when choosing a temporary slot.
+    ;;
+    ;; Note that although we reserve slots 253-255 for shuffling
+    ;; operands that address less than the full 24-bit range of locals,
+    ;; that reservation doesn't apply here, because this temporary
+    ;; itself is used while doing parallel assignment via "mov", and
+    ;; "mov" does not need shuffling.
     (define (compute-tmp-slot live stack-slots)
       (find-first-zero (fold add-live-slot live stack-slots)))
 
@@ -337,7 +350,7 @@ are comparable with eqv?.  A tmp slot may be used."
       (let lp ((n 0))
         (when (< n (vector-length usev))
           (match (lookup-cont (idx->label n) dfg)
-            (($ $kentry src meta self)
+            (($ $kfun src meta self)
              (vector-set! defv n (list (dfa-var-idx dfa self))))
             (($ $kargs names syms body)
              (vector-set! defv n (map (cut dfa-var-idx dfa <>) syms))
@@ -350,6 +363,10 @@ are comparable with eqv?.  A tmp slot may be used."
                                   (cons proc args))
                                  (($ $primcall name args)
                                   args)
+                                 (($ $branch kt ($ $primcall name args))
+                                  args)
+                                 (($ $branch kt ($ $values args))
+                                  args)
                                  (($ $values args)
                                   args)
                                  (($ $prompt escape? tag handler)
@@ -384,7 +401,7 @@ are comparable with eqv?.  A tmp slot may be used."
                 ;; predecessor.
                 ((or (_) ((? kreceive-get-kargs) ...))
                  (for-each (lambda (var)
-                             (when (dead-after-def? (idx->label n) var dfa)
+                             (when (dead-after-def? n var dfa)
                                (bitvector-set! needs-slotv var #f)))
                            (vector-ref defv n)))
                 (_ #f))
@@ -399,17 +416,12 @@ are comparable with eqv?.  A tmp slot may be used."
     ;; frames as soon as it's known that a call will happen.  It would
     ;; be nice to recast this as a proper data-flow problem.
     (define (compute-needs-hint!)
-      ;; We traverse the graph using reverse-post-order on a forward
-      ;; control-flow graph, but we did the live variable analysis in
-      ;; the opposite direction -- so the continuation numbers don't
-      ;; correspond.  This helper adapts them.
-      (define (label-idx->dfa-k-idx n)
-        (dfa-k-idx dfa (idx->label n)))
-
       (define (live-before n)
-        (dfa-k-in dfa (label-idx->dfa-k-idx n)))
+        (dfa-k-in dfa n))
       (define (live-after n)
-        (dfa-k-out dfa (label-idx->dfa-k-idx n)))
+        (dfa-k-out dfa n))
+      (define needs-slot
+        (bitvector->intset needs-slotv))
 
       ;; Walk backwards.  At a call, compute the set of variables that
       ;; have allocated slots and are live before but not after.  This
@@ -420,12 +432,10 @@ are comparable with eqv?.  A tmp slot may be used."
             (($ $kargs names syms body)
              (match (find-expression body)
                ((or ($ $call) ($ $callk))
-                (let ((args (make-bitvector (bitvector-length needs-slotv) #f)))
-                  (bit-set*! args (live-before n) #t)
-                  (bit-set*! args (live-after n) #f)
-                  (bit-set*! args no-slot-needed #f)
-                  (if (bit-position #t args 0)
-                      (scan-for-hints (1- n) args)
+                (let* ((args (intset-subtract (live-before n) (live-after n)))
+                       (args-needing-slots (intset-intersect args needs-slot)))
+                  (if (intset-next args-needing-slots #f)
+                      (scan-for-hints (1- n) args-needing-slots)
                       (scan-for-call (1- n)))))
                (_ (scan-for-call (1- n)))))
             (_ (scan-for-call (1- n))))))
@@ -442,21 +452,18 @@ are comparable with eqv?.  A tmp slot may be used."
                 ;; are finished with the scan, we kill uses of the
                 ;; terminator, but leave its definitions.
                 (match (find-expression body)
-                  ((or ($ $void) ($ $const) ($ $prim) ($ $fun)
+                  ((or ($ $const) ($ $prim) ($ $closure)
                        ($ $primcall) ($ $prompt)
                        ;; If $values has more than one argument, it may
                        ;; use a temporary, which would invalidate our
                        ;; assumptions that slots not allocated are not
                        ;; used.
                        ($ $values (or () (_))))
-                   (let ((dead (make-bitvector (bitvector-length args) #f)))
-                     (bit-set*! dead (live-before n) #t)
-                     (bit-set*! dead (live-after n) #f)
-                     (bit-set*! dead no-slot-needed #f)
-                     (if (bit-position #t dead 0)
+                   (let ((killed (intset-subtract (live-before n) (live-after n))))
+                     (if (intset-next (intset-intersect killed needs-slot) #f)
                          (finish-hints n (live-before n) args)
                          (scan-for-hints (1- n) args))))
-                  ((or ($ $call) ($ $callk) ($ $values))
+                  ((or ($ $call) ($ $callk) ($ $values) ($ $branch))
                    (finish-hints n (live-before n) args))))
                ;; Otherwise we kill uses of the block entry.
                (_ (finish-hints n (live-before (1+ n)) args))))
@@ -465,17 +472,14 @@ are comparable with eqv?.  A tmp slot may be used."
       ;; Add definitions ARGS minus KILL to NEED-HINTS, and go back to
       ;; looking for calls.
       (define (finish-hints n kill args)
-        (bit-invert! args)
-        (bit-set*! args kill #t)
-        (bit-invert! args)
-        (bit-set*! needs-hintv args #t)
+        (let ((new-hints (intset-subtract args kill)))
+          (let lp ((n 0))
+            (let ((n (intset-next new-hints n)))
+              (when n
+                (bitvector-set! needs-hintv n #t)
+                (lp (1+ n))))))
         (scan-for-call n))
 
-      (define no-slot-needed
-        (make-bitvector (bitvector-length needs-slotv) #f))
-
-      (bit-set*! no-slot-needed needs-slotv #t)
-      (bit-invert! no-slot-needed)
       (scan-for-call (1- label-count)))
 
     (define (allocate-call label k uses pre-live post-live)
@@ -572,8 +576,7 @@ are comparable with eqv?.  A tmp slot may be used."
                                       (compute-tmp-slot (logior pre-live result-live)
                                                         '()))))
            (hashq-set! call-allocations label
-                       (make-call-allocation #f moves #f))))
-        (($ $kif) #f)))
+                       (make-call-allocation #f moves #f))))))
 
     (define (allocate-prompt label k handler nargs)
       (match (lookup-cont handler dfg)
@@ -605,13 +608,11 @@ are comparable with eqv?.  A tmp slot may be used."
     ;; definitions dominate uses and a block's dominator will appear
     ;; before it, in reverse post-order.
     (define (visit-clause n nargs live)
-      (let lp ((n n) (live live))
+      (let lp ((n n) (live (recompute-live-slots (idx->label n) nargs)))
         (define (kill-dead live vars-by-label-idx pred)
           (fold (lambda (v live)
                   (let ((slot (vector-ref slots v)))
-                    (if (and slot
-                             (> slot nargs)
-                             (pred (idx->label n) v dfa))
+                    (if (and slot (pred n v dfa))
                         (kill-dead-slot slot live)
                         live)))
                 live
@@ -634,18 +635,22 @@ are comparable with eqv?.  A tmp slot may be used."
               (match (lookup-cont (idx->label n) dfg)
                 (($ $kclause) n)
                 (($ $kargs names syms body)
+                 (define (compute-k-live k)
+                   (match (lookup-predecessors k dfg)
+                     ((_) post-live)
+                     (_ (recompute-live-slots k nargs))))
                  (let ((uses (vector-ref usev n)))
                    (match (find-call body)
                      (($ $continue k src (or ($ $call) ($ $callk)))
-                      (allocate-call label k uses live post-live))
+                      (allocate-call label k uses live (compute-k-live k)))
                      (($ $continue k src ($ $primcall)) #t)
                      (($ $continue k src ($ $values))
-                      (allocate-values label k uses live post-live))
+                      (allocate-values label k uses live (compute-k-live k)))
                      (($ $continue k src ($ $prompt escape? tag handler))
                       (allocate-prompt label k handler nargs))
                      (_ #f)))
                  (lp (1+ n) post-live))
-                ((or ($ $kreceive) ($ $kif) ($ $ktail))
+                ((or ($ $kreceive) ($ $ktail))
                  (lp (1+ n) post-live)))))))
 
     (define (visit-entry)
@@ -671,7 +676,7 @@ are comparable with eqv?.  A tmp slot may be used."
                     (error "Unexpected clause order"))))
                (visit-clauses next live))))))
       (match (lookup-cont (idx->label 0) dfg)
-        (($ $kentry src meta self)
+        (($ $kfun src meta self)
          (visit-clauses 1 (allocate-defs! 0 (empty-live-slots))))))
 
     (compute-constants!)