guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 03/03: Better unboxing


From: Andy Wingo
Subject: [Guile-commits] 03/03: Better unboxing
Date: Thu, 1 Sep 2016 09:15:34 +0000 (UTC)

wingo pushed a commit to branch master
in repository guile.

commit 0f2f5949a21572fad8355473200c7adc6d74f882
Author: Andy Wingo <address@hidden>
Date:   Thu Sep 1 10:55:45 2016 +0200

    Better unboxing
    
    * module/language/cps/specialize-numbers.scm (truncate-u64): New helper,
      truncates a SCM value.
      (specialize-u64-binop): Add ulogxor case.
      (sigbits-union, sigbits-intersect, sigbits-intersect3)
      (next-power-of-two, range->sigbits, inferred-sigbits)
      (significant-bits-handlers, define-significant-bits-handler):
      (significant-bits-handler, compute-significant-bits): Add facility to
      compute the bits in a value that are significant.
      (specialize-operations): Unbox in more cases, when only u64 bits are
      significant.  Unbox logxor.  Elide logand where it has no effect.
---
 module/language/cps/specialize-numbers.scm |  280 +++++++++++++++++++++-------
 1 file changed, 211 insertions(+), 69 deletions(-)

diff --git a/module/language/cps/specialize-numbers.scm 
b/module/language/cps/specialize-numbers.scm
index 24ce209..d9fe76c 100644
--- a/module/language/cps/specialize-numbers.scm
+++ b/module/language/cps/specialize-numbers.scm
@@ -90,6 +90,7 @@
                ('mul 'umul)
                ('logand 'ulogand)
                ('logior 'ulogior)
+               ('logxor 'ulogxor)
                ('logsub 'ulogsub)
                ('rsh 'ursh)
                ('lsh 'ulsh))))
@@ -108,6 +109,16 @@
         ($continue kunbox-b src
           ($primcall unbox-a (a)))))))
 
+(define (truncate-u64 cps k src scm)
+  (with-cps cps
+    (letv u64)
+    (letk kbox ($kargs ('u64) (u64)
+                 ($continue k src
+                   ($primcall 'u64->scm (u64)))))
+    (build-term
+      ($continue kbox src
+        ($primcall 'scm->u64/truncate (scm))))))
+
 (define (specialize-u64-comparison cps kf kt src op a b)
   (let ((op (symbol-append 'u64- op)))
     (with-cps cps
@@ -133,8 +144,123 @@
         ($continue kop src
           ($primcall 'scm->u64 (a-u64)))))))
 
+(define (sigbits-union x y)
+  (and x y (logior x y)))
+
+(define (sigbits-intersect x y)
+  (cond
+   ((not x) y)
+   ((not y) x)
+   (else (logand x y))))
+
+(define (sigbits-intersect3 a b c)
+  (sigbits-intersect a (sigbits-intersect b c)))
+
+(define (next-power-of-two n)
+  (let lp ((out 1))
+    (if (< n out)
+        out
+        (lp (ash out 1)))))
+
+(define (range->sigbits min max)
+  (cond
+   ((or (< min 0) (> max #xffffFFFFffffFFFF)) #f)
+   ((eqv? min max) min)
+   (else (1- (next-power-of-two max)))))
+
+(define (inferred-sigbits types label var)
+  (call-with-values (lambda () (lookup-pre-type types label var))
+    (lambda (type min max)
+      (and (or (eqv? type &exact-integer) (eqv? type &u64))
+           (range->sigbits min max)))))
+
+(define significant-bits-handlers (make-hash-table))
+(define-syntax-rule (define-significant-bits-handler
+                      ((primop label types out def ...) arg ...)
+                      body ...)
+  (hashq-set! significant-bits-handlers 'primop
+              (lambda (label types out args defs)
+                (match args ((arg ...) (match defs ((def ...) body ...)))))))
+
+(define-significant-bits-handler ((logand label types out res) a b)
+  (let ((sigbits (sigbits-intersect3 (inferred-sigbits types label a)
+                                     (inferred-sigbits types label b)
+                                     (intmap-ref out res (lambda (_) 0)))))
+    (intmap-add (intmap-add out a sigbits sigbits-union)
+                b sigbits sigbits-union)))
+
+(define (significant-bits-handler primop)
+  (hashq-ref significant-bits-handlers primop))
+
+(define (compute-significant-bits cps types kfun)
+  "Given the locally inferred types @var{types}, compute a map of VAR ->
+BITS indicating the significant bits needed for a variable.  BITS may be
+#f to indicate all bits, or a non-negative integer indicating a bitmask."
+  (let ((preds (invert-graph (compute-successors cps kfun))))
+    (let lp ((worklist (intmap-keys preds)) (out empty-intmap))
+      (match (intset-prev worklist)
+        (#f out)
+        (label
+         (let ((worklist (intset-remove worklist label)))
+           (define (continue out*)
+             (if (eq? out out*)
+                 (lp worklist out)
+                 (lp (intset-union worklist (intmap-ref preds label)) out*)))
+           (define (add-def out var)
+             (intmap-add out var 0 sigbits-union))
+           (define (add-defs out vars)
+             (match vars
+               (() out)
+               ((var . vars) (add-defs (add-def out var) vars))))
+           (define (add-unknown-use out var)
+             (intmap-add out var (inferred-sigbits types label var)
+                         sigbits-union))
+           (define (add-unknown-uses out vars)
+             (match vars
+               (() out)
+               ((var . vars)
+                (add-unknown-uses (add-unknown-use out var) vars))))
+           (continue
+            (match (intmap-ref cps label)
+              (($ $kfun src meta self)
+               (add-def out self))
+              (($ $kargs names vars ($ $continue k src exp))
+               (let ((out (add-defs out vars)))
+                 (match exp
+                   ((or ($ $const) ($ $prim) ($ $fun) ($ $closure) ($ $rec))
+                    ;; No uses, so no info added to sigbits.
+                    out)
+                   (($ $values args)
+                    (match (intmap-ref cps k)
+                      (($ $kargs _ vars)
+                       (fold (lambda (arg var out)
+                               (intmap-add out arg (intmap-ref out var
+                                                               (lambda (_) 0))
+                                           sigbits-union))
+                             out args vars))
+                      (($ $ktail)
+                       (add-unknown-uses out args))))
+                   (($ $call proc args)
+                    (add-unknown-use (add-unknown-uses out args) proc))
+                   (($ $callk label proc args)
+                    (add-unknown-use (add-unknown-uses out args) proc))
+                   (($ $branch kt ($ $values (arg)))
+                    (add-unknown-use out arg))
+                   (($ $branch kt ($ $primcall name args))
+                    (add-unknown-uses out args))
+                   (($ $primcall name args)
+                    (let ((h (significant-bits-handler name)))
+                      (if h
+                          (match (intmap-ref cps k)
+                            (($ $kargs _ defs)
+                             (h label types out args defs)))
+                          (add-unknown-uses out args))))
+                   (($ $prompt escape? tag handler)
+                    (add-unknown-use out tag)))))
+              (_ out)))))))))
+
 (define (specialize-operations cps)
-  (define (visit-cont label cont cps types)
+  (define (visit-cont label cont cps types sigbits)
     (define (operand-in-range? var &type &min &max)
       (call-with-values (lambda ()
                           (lookup-pre-type types label var))
@@ -142,9 +268,25 @@
           (and (eqv? type &type) (<= &min min max &max)))))
     (define (u64-operand? var)
       (operand-in-range? var &exact-integer 0 #xffffffffffffffff))
+    (define (all-u64-bits-set? var)
+      (operand-in-range? var &exact-integer
+                         #xffffffffffffffff
+                         #xffffffffffffffff))
+    (define (only-u64-bits-used? var)
+      (let ((bits (intmap-ref sigbits var)))
+        (and bits (= bits (logand bits #xffffFFFFffffFFFF)))))
+    (define (u64-result? result)
+      (or (only-u64-bits-used? result)
+          (call-with-values
+              (lambda ()
+                (lookup-post-type types label result 0))
+            (lambda (type min max)
+              (and (eqv? type &exact-integer)
+                   (<= 0 min max #xffffffffffffffff))))))
     (match cont
       (($ $kfun)
-       (values cps (infer-types cps label)))
+       (let ((types (infer-types cps label)))
+         (values cps types (compute-significant-bits cps types label))))
       (($ $kargs names vars
           ($ $continue k src
              ($ $primcall (and op (or 'add 'sub 'mul 'div)) (a b))))
@@ -160,7 +302,8 @@
                    (let$ body (specialize-f64-binop k src op a b))
                    (setk label ($kargs names vars ,body))))
                 ((and (eqv? type &exact-integer)
-                      (<= 0 min max #xffffffffffffffff)
+                      (or (<= 0 min max #xffffffffffffffff)
+                          (only-u64-bits-used? result))
                       (u64-operand? a) (u64-operand? b)
                       (not (eq? op 'div)))
                  (with-cps cps
@@ -168,80 +311,78 @@
                    (setk label ($kargs names vars ,body))))
                 (else
                  cps))
-               types))))))
+               types
+               sigbits))))))
       (($ $kargs names vars
           ($ $continue k src ($ $primcall 'ash (a b))))
        (match (intmap-ref cps k)
          (($ $kargs (_) (result))
           (call-with-values (lambda ()
-                              (lookup-post-type types label result 0))
-            (lambda (type min max)
-              (call-with-values (lambda ()
-                                  (lookup-pre-type types label b))
-                (lambda (b-type b-min b-max)
-                  (values
-                   (cond
-                    ((or (not (eqv? type &exact-integer))
-                         (not (<= 0 min max #xffffffffffffffff))
-                         (not (u64-operand? a))
-                         (not (eqv? b-type &exact-integer))
-                         (< b-min 0 b-max)
-                         (<= b-min -64)
-                         (<= 64 b-max))
-                     cps)
-                    ((and (< b-min 0) (= b-min b-max))
-                     (with-cps cps
-                       (let$ body
-                             (with-cps-constants ((bits (- b-min)))
-                               ($ (specialize-u64-binop k src 'rsh a bits))))
-                       (setk label ($kargs names vars ,body))))
-                    ((< b-min 0)
-                     (with-cps cps
-                       (let$ body
-                             (with-cps-constants ((zero 0))
-                               (letv bits)
-                               (let$ body
-                                     (specialize-u64-binop k src 'rsh a bits))
-                               (letk kneg ($kargs ('bits) (bits) ,body))
-                               (build-term
-                                 ($continue kneg src
-                                   ($primcall 'sub (zero b))))))
-                       (setk label ($kargs names vars ,body))))
-                    (else
-                     (with-cps cps
-                       (let$ body (specialize-u64-binop k src 'lsh a b))
-                       (setk label ($kargs names vars ,body)))))
-                   types))))))))
-      (($ $kargs names vars
-          ($ $continue k src
-             ($ $primcall (and op (or 'logand 'logior 'logsub)) (a b))))
-       (match (intmap-ref cps k)
-         (($ $kargs (_) (result))
-          (call-with-values (lambda ()
-                              (lookup-post-type types label result 0))
-            (lambda (type min max)
+                              (lookup-pre-type types label b))
+            (lambda (b-type b-min b-max)
               (values
                (cond
-                ((and (eqv? type &exact-integer)
-                      (<= 0 min max #xffffffffffffffff))
-                 ;; If we know the result is a u64, then any
-                 ;; out-of-range bits won't affect the result and so we
-                 ;; can project the operands onto u64.
+                ((or (not (u64-result? result))
+                     (not (u64-operand? a))
+                     (not (eqv? b-type &exact-integer))
+                     (< b-min 0 b-max)
+                     (<= b-min -64)
+                     (<= 64 b-max))
+                 cps)
+                ((and (< b-min 0) (= b-min b-max))
                  (with-cps cps
                    (let$ body
-                         (specialize-u64-binop k src op a b
-                                               #:unbox-a
-                                               (if (u64-operand? a)
-                                                   'scm->u64
-                                                   'scm->u64/truncate)
-                                               #:unbox-b
-                                               (if (u64-operand? b)
-                                                   'scm->u64
-                                                   'scm->u64/truncate)))
+                         (with-cps-constants ((bits (- b-min)))
+                           ($ (specialize-u64-binop k src 'rsh a bits))))
+                   (setk label ($kargs names vars ,body))))
+                ((< b-min 0)
+                 (with-cps cps
+                   (let$ body
+                         (with-cps-constants ((zero 0))
+                           (letv bits)
+                           (let$ body
+                                 (specialize-u64-binop k src 'rsh a bits))
+                           (letk kneg ($kargs ('bits) (bits) ,body))
+                           (build-term
+                             ($continue kneg src
+                               ($primcall 'sub (zero b))))))
                    (setk label ($kargs names vars ,body))))
                 (else
-                 cps))
-               types))))))
+                 (with-cps cps
+                   (let$ body (specialize-u64-binop k src 'lsh a b))
+                   (setk label ($kargs names vars ,body)))))
+               types
+               sigbits))))))
+      (($ $kargs names vars
+          ($ $continue k src
+             ($ $primcall (and op (or 'logand 'logior 'logsub 'logxor)) (a 
b))))
+       (match (intmap-ref cps k)
+         (($ $kargs (_) (result))
+          (values
+           (cond
+            ((u64-result? result)
+             ;; Given that we know the result can be unboxed to a u64,
+             ;; any out-of-range bits won't affect the result and so we
+             ;; can unconditionally project the operands onto u64.
+             (cond
+              ((and (eq? op 'logand) (all-u64-bits-set? a))
+               (with-cps cps
+                 (let$ body (truncate-u64 k src b))
+                 (setk label ($kargs names vars ,body))))
+              ((and (eq? op 'logand) (all-u64-bits-set? b))
+               (with-cps cps
+                 (let$ body (truncate-u64 k src a))
+                 (setk label ($kargs names vars ,body))))
+              (else
+               (with-cps cps
+                 (let$ body (specialize-u64-binop k src op a b
+                                                  #:unbox-a
+                                                  'scm->u64/truncate
+                                                  #:unbox-b
+                                                  'scm->u64/truncate))
+                 (setk label ($kargs names vars ,body))))))
+            (else cps))
+           types sigbits))))
       (($ $kargs names vars
           ($ $continue k src
              ($ $branch kt ($ $primcall (and op (or '< '<= '= '>= '>)) (a 
b)))))
@@ -260,10 +401,11 @@
                     (let$ body (specialize-u64-scm-comparison k kt src op b a))
                     (setk label ($kargs names vars ,body))))
                 cps))
-        types))
-      (_ (values cps types))))
+        types
+        sigbits))
+      (_ (values cps types sigbits))))
 
-  (values (intmap-fold visit-cont cps cps #f)))
+  (values (intmap-fold visit-cont cps cps #f #f)))
 
 ;; Compute a map from VAR -> LABEL, where LABEL indicates the cont that
 ;; binds VAR.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]