~ chicken-core (chicken-5) c6cc7ac650734fdcca3d3d68e84d577558fad018


commit c6cc7ac650734fdcca3d3d68e84d577558fad018
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Sat Dec 5 21:31:44 2009 +0100
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Sat Dec 5 21:31:44 2009 +0100

    added missing file

diff --git a/unboxing.scm b/unboxing.scm
new file mode 100644
index 00000000..76b992eb
--- /dev/null
+++ b/unboxing.scm
@@ -0,0 +1,332 @@
+;;;; unboxing.scm - The CHICKEN Scheme compiler (local flow-analysis with number boxing/unboxing)
+;
+; Copyright (c) 2009, The Chicken Team
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+; conditions are met:
+;
+;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+;     disclaimer. 
+;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+;     disclaimer in the documentation and/or other materials provided with the distribution. 
+;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
+;     products derived from this software without specific prior written permission. 
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; POSSIBILITY OF SUCH DAMAGE.
+
+
+(declare (unit unboxing))
+
+
+(include "compiler-namespace")
+(include "tweaks")
+
+
+(define (d fstr . args)
+  (when (##sys#fudge 13)
+    (printf "[debug] ~?~%" fstr args)) )
+
+;(define-syntax d (syntax-rules () ((_ . _) (void))))
+
+
+(define (perform-unboxing! node)
+  (let ((stats (make-vector 301 '())))
+
+    ;; walk nodes in lambda and mark unboxed variables
+    (define (walk-lambda id e body)
+      (let ((ae '()))
+
+	(define (boxed! v)		; 'boxed is sticky
+	  (cond ((assq v e) =>
+		 (lambda (a)
+		   (set-cdr! a #f) ) )
+		(else (set! e (alist-cons v #f e)))))
+
+	(define (unboxed! v t)
+	  (cond ((assq v e) =>
+		 (lambda (a)
+		   (if (cdr a)
+		       (let ((t2 (and (eq? (cdr a) t) t)))
+			 (if t2
+			     (set-cdr! a t2)
+			     (set! e (alist-cons v #f e))))
+		       (set-cdr! e (alist-cons v #f e)))))
+		(else
+		 (set! ae (alist-cons v (gensym "tu") ae))
+		 (set! e (alist-cons v t e)))))
+
+	(define (unboxed? v)
+	  (and-let* ((a (assq v e)))
+	    (cdr a)))
+
+	(define (unboxed-value? x)
+	  (and x (cdr x)))
+
+	(define (invalidate r) ; if result is variable, mark it 'boxed
+	  (when (and (pair? r) (car r))
+	    (boxed! (car r))))
+
+	(define (alias v)
+	  (alist-ref v ae eq? v) )
+
+	(define (merge r1 r2)
+	  (cond ((or (not r1) (not (cdr r1)))
+		 (invalidate r2)
+		 #f)
+		((or (not r2) (not (cdr r2)))
+		 (invalidate r1)
+		 #f)
+		((equal? r1 r2) r1)
+		((eq? (cdr r1) (cdr r2))
+		 (cons #f (cdr r1)))
+		(else #f)))
+
+	(define (rewrite! n alt anodes avals atypes0 rtype dest)
+	  (d "rewrite: ~a -> ~a" (first (node-parameters n)) alt)
+	  (let ((s (symbolify alt)))
+	    (##sys#hash-table-set! 
+	     stats s (add1 (or (##sys#hash-table-ref stats s) 0))))
+	  (copy-node!
+	   (let loop ((args avals) (anodes anodes) (atypes atypes0) (iargs '()))
+	     (cond ((null? args) 
+		    (let ((n2 (make-node
+			       '##core#inline_unboxed (list alt)
+			       (reverse iargs))))
+		      (if (and dest (cdr dest))
+			  n2
+			  (let ((tmp (gensym "tu")))
+			    (make-node
+			     '##core#let_unboxed (list tmp rtype)
+			     (list
+			      n2
+			      (case rtype
+				((flo)
+				 (make-node
+				  '##core#inline_allocate (list "C_a_i_flonum" 4) ; hardcoded size
+				  (list (make-node '##core#unboxed_ref (list tmp rtype) '()))))
+				((ptr)
+				 (make-node
+				  '##core#inline_allocate (list "C_a_i_mpointer" 2) ; hardcoded size
+				  (list (make-node '##core#unboxed_ref (list tmp rtype) '()))))
+				((chr)
+				 (make-node
+				   '##core#inline
+				   (list (if (eq? rtype 'chr) "C_make_character" "C_fix"))
+				   (list (make-node
+					  '##core#unboxed_ref
+					  (list tmp rtype) '()))))
+				(else (bomb "invalid unboxed type" rtype))))))))) 
+		   ((unboxed-value? (car args))
+		    (loop (cdr args)
+			  (cdr anodes)
+			  (cdr atypes)
+			  (cons (car anodes) iargs)))
+		   (else
+		    ;; introduce unboxed temporary
+		    (let ((tmp (gensym "tu")))
+		      (make-node
+		       '##core#let_unboxed (list tmp (car atypes))
+		       (list (make-node
+			      '##core#inline 
+			      (list (case (car atypes)
+				      ((chr) "C_character_code")
+				      ((fix) "C_unfix")
+				      ((flo) "C_flonum_magnitude")
+				      ((ptr) "C_pointer_address")
+				      (else (bomb "invalid unboxed type" (car atypes)))))
+			      (list (car anodes)))
+			     (loop (cdr args)
+				   (cdr anodes)
+				   (cdr atypes)
+				   (cons (make-node '##core#unboxed_ref (list tmp) '())
+					 iargs))))))))
+	   n)
+	  (straighten-binding! n))
+
+	(define (rebind-unboxed! n t)
+	  (let ((var (alias (first (node-parameters n)))))
+	    (node-class-set! n '##core#let_unboxed)
+	    (node-parameters-set! n (list var t))
+	    (straighten-binding! n) ))
+
+	(define (straighten-binding! n)
+	  ;; change `(let ((v (let (b) x2))) x)' into `(let (b) (let ((v x2)) x))'
+	  (let* ((subs (node-subexpressions n))
+		 (bnode (first subs))
+		 (bcl (node-class bnode)))
+	    (when (memq bcl '(let ##core#let_unboxed))
+	      (d "straighten: ~a -> ~a" (node-parameters n) (node-parameters bnode))
+	      (copy-node!
+	       (make-node
+		bcl
+		(node-parameters bnode)
+		(let ((bsubs (node-subexpressions bnode)))
+		  (list (first bsubs)
+			(make-node
+			 (node-class n)
+			 (node-parameters n)
+			 (list (second bsubs)
+			       (second subs))))))
+	       n)
+	      ;;(pp (build-expression-tree n))
+	      (straighten-binding! n)
+	      (straighten-binding! (second (node-subexpressions n))))))
+
+	(define (walk n dest udest pass2?)
+	  (let ((subs (node-subexpressions n))
+		(params (node-parameters n))
+		(class (node-class n)) )
+	    ;;(d "walk: (~a) ~a ~a" pass2? class params)
+	    (case class
+
+	      ((##core#undefined
+		##core#proc
+		##core#global-ref
+		##core#inline_ref
+		##core#inline_loc_ref) #f)
+
+	      ((##core#lambda
+		##core#direct_lambda)
+	       (decompose-lambda-list
+		(third params)
+		(lambda (vars argc rest)
+		  (unless pass2?
+		    (walk-lambda
+		     (first params) 
+		     (map (cut cons <> #f) vars)
+		     (first subs)) )
+		  #f)))
+
+	      ((##core#variable)
+	       (let* ((v (first params))
+		      (a (assq v e)))
+		 (if pass2?
+		     (when (and a (cdr a))
+		       (copy-node!
+			(make-node '##core#unboxed_ref (list (alias v) (cdr a)) '())
+			n))
+		     (unless udest (boxed! v)))
+		 a))
+
+	      ((##core#inline ##core#inline_allocate)
+	       (let* ((rw (##sys#get (symbolify (first params)) '##compiler#unboxed-op))
+		      (args (map (cut walk <> #f rw pass2?) subs)))
+		 (cond ((not rw) #f)
+		       ((or (not pass2?)
+			    (and dest (unboxed? dest))
+			    (any unboxed-value? args))
+			(let ((alt (first rw))
+			      (atypes (second rw))
+			      (rtype (third rw)))
+			  ;; if result or arguments are unboxed, rewrite node to alternative
+			  (when pass2?
+			    (rewrite! 
+			     n alt subs args atypes rtype 
+			     (and dest (assq dest e))))
+			  (cons #f rtype)) )
+		       (else
+			(let ((rtype (third rw)))
+			  ;; mark argument-vars and dest as unboxed if alternative exists
+			  (unless pass2?
+			    (for-each
+			     (lambda (a)
+			       (when (and a (car a) (cdr a))
+				 (unboxed! (car a) (cdr a))))
+			     args)
+			    (when dest (unboxed! dest rtype)))
+			  (cons #f rtype))))))
+
+	      ((let)
+	       (let* ((v (first params))
+		      (r1 (walk (first subs) v #t pass2?)))
+		 (when (and (not pass2?) r1 (cdr r1))
+		   (unboxed! (first params) (cdr r1)))
+		 (let ((r (walk (second subs) dest udest pass2?)))
+		   (when pass2?
+		     (let ((a (assq v e)))
+		       (if (and a (cdr a))
+			   (rebind-unboxed! n (cdr a))
+			   (straighten-binding! n))) )
+		   r)))
+
+	      ((set!)
+	       (let* ((var (first params))
+		      (a (assq var e))
+		      (val (walk (first subs) var (and a (cdr a)) pass2?)))
+		 (cond (pass2?
+			(when (and a (cdr a)) ; may have mutated
+			  (copy-node!
+			   (make-node
+			    '##core#unboxed_set! (list (alias var) (cdr a)) subs)
+			   n)))
+		       ((and val (cdr val))
+			(unboxed! var (cdr val)))
+		       (else 
+			(boxed! var)
+			(invalidate val) ) )
+		 #f))
+
+	      ((quote)
+	       (let ((val (first params)))
+		 (cond ((flonum? val) '(#f . flo))
+		       ((fixnum? val) '(#f . fix))
+		       ((char? val) '(#f . chr))
+		       (else #f))))
+
+	      ((if ##core#cond)
+	       (invalidate (walk (first subs) #f #f pass2?))
+	       (let ((r1 (walk (second subs) dest udest pass2?))
+		     (r2 (walk (third subs) dest udest pass2?)))
+		 (merge r1 r2)))
+
+	      ((##core#switch)
+	       (invalidate (walk (first subs) #f #f pass2?))
+	       (do ((clauses (cdr subs) (cddr clauses))
+		    (r 'none 
+		       (if (eq? r 'none)
+			   (walk (second clauses) dest udest pass2?)
+			   (merge r (walk (second clauses) dest udest pass2?)))))
+		   ((null? (cddr clauses)) 
+		    (merge r (walk (car clauses) dest udest pass2?))) ) )
+
+	      (else
+	       (for-each (o invalidate (cut walk <> #f #f pass2?)) subs)
+	       #f))))
+
+	;(d "walk lambda: ~a" id)
+	(walk body #f #f #f)
+	(walk body #f #f #t)))
+    
+    (walk-lambda #f '() node)
+    (when (debugging 'x #;'o "unboxed rewrites:") ;XXX
+      (##sys#hash-table-for-each
+       (lambda (k v)
+	 (printf "  ~a\t~a~%" k v) )
+       stats))))
+
+(define-syntax define-unboxed-ops
+  (syntax-rules ()
+    ((_ (name atypes rtype alt) ...)
+     (begin
+       (register-op 'name 'atypes 'rtype 'alt) ...))))
+
+(define (register-op name atypes rtype alt)
+  (##sys#put! (symbolify name) '##compiler#unboxed-op (list alt atypes rtype)))
+
+
+;; unboxed rewrites
+
+(define-unboxed-ops 
+  (C_a_i_flonum_plus (flo flo) flo "C_ub_i_flonum_plus")
+  (C_a_i_flonum_times (flo flo) flo "C_ub_i_flonum_times") 
+  ;...
+  )
Trap