~ chicken-core (chicken-5) /lfa2.scm


  1;;;; lfa2.scm - a lightweight "secondary" flow analysis
  2;
  3; Copyright (c) 2012-2022, The CHICKEN Team
  4; All rights reserved.
  5;
  6; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
  7; conditions are met:
  8;
  9;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 10;     disclaimer. 
 11;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
 12;     disclaimer in the documentation and/or other materials provided with the distribution. 
 13;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
 14;     products derived from this software without specific prior written permission. 
 15;
 16; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 17; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 18; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 19; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 20; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 21; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 22; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 23; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 24; POSSIBILITY OF SUCH DAMAGE.
 25
 26
 27;; This pass does a lightweight flow-analysis on value types, mostly
 28;; to handle the case where user code performs a type-check followed
 29;; by inlined accessors (for example when using record structures).
 30;; Specialization takes place before inlining, so even though we have
 31;; the type-information, later inlining will still keep the code for
 32;; checking argument types. Additionally, this pass detects unboxing
 33;; opportunities for floating point values and replaces uses of certain
 34;; fp operations with unboxed ones.
 35
 36
 37(declare
 38  (unit lfa2)
 39  (uses extras support))
 40
 41(module chicken.compiler.lfa2
 42    (perform-secondary-flow-analysis perform-unboxing)
 43
 44(import scheme
 45	chicken.base
 46	chicken.compiler.support
 47	chicken.fixnum
 48	chicken.format
 49	chicken.keyword)
 50
 51(include "tweaks")
 52(include "mini-srfi-1.scm")
 53
 54
 55;;; Maps checks to types
 56
 57(define +type-check-map+
 58  '(("C_i_check_closure" procedure)
 59    ("C_i_check_exact" fixnum bignum integer ratnum) ;; DEPRECATED
 60    ("C_i_check_inexact" float)	; Or an inexact cplxnum...
 61    ("C_i_check_number" fixnum integer bignum ratnum float cplxnum number)
 62    ("C_i_check_string" string)
 63    ("C_i_check_bytevector" blob)
 64    ("C_i_check_symbol" symbol)
 65    ("C_i_check_keyword" keyword)
 66    ("C_i_check_list" null pair list)
 67    ("C_i_check_pair" pair)
 68    ("C_i_check_locative" locative)
 69    ("C_i_check_boolean" boolean)
 70    ("C_i_check_vector" vector)
 71    ("C_i_check_structure" *struct*)	; special case
 72    ("C_i_check_char" char)
 73    ("C_i_check_closure_2" procedure)
 74    ("C_i_check_exact_2" fixnum bignum integer ratnum) ;; DEPRECATED
 75    ("C_i_check_inexact_2" float)	; Or an inexact cplxnum...
 76    ("C_i_check_number_2" fixnum integer bignum ratnum float cplxnum number)
 77    ("C_i_check_string_2" string)
 78    ("C_i_check_bytevector_2" blob)
 79    ("C_i_check_symbol_2" symbol)
 80    ("C_i_check_keyword_2" keyword)
 81    ("C_i_check_list_2" null pair list)
 82    ("C_i_check_pair_2" pair)
 83    ("C_i_check_locative_2" locative)
 84    ("C_i_check_boolean_2" boolean)
 85    ("C_i_check_vector_2" vector)
 86    ("C_i_check_structure_2" *struct*)	; special case
 87    ("C_i_check_char_2" char)))
 88
 89
 90;; Maps predicates to types
 91 
 92(define +predicate-map+
 93  '(("C_i_closurep" procedure)
 94    ("C_fixnump" fixnum)
 95    ("C_bignump" bignum)
 96    ("C_i_exact_integerp" integer fixnum bignum)
 97    ("C_i_flonump" float)
 98    ("C_i_numberp" number fixnum integer bignum ratnum float cplxnum)
 99    ("C_i_ratnump" ratnum)
100    ("C_i_cplxnump" cplxnum)
101    ("C_stringp" string)
102    ("C_bytevectorp" blob)
103    ("C_i_keywordp" keyword)
104    ("C_i_symbolp" symbol)
105    ("C_i_listp" list)
106    ("C_i_pairp" pair)
107    ("C_locativep" locative)
108    ("C_booleanp" boolean)
109    ("C_i_vectorp" vector)
110    ("C_structurep" struct)
111    ("C_i_structurep" *struct*)		; special case
112    ("C_charp" char)
113    ("C_i_portp" port)
114    ("C_i_nullp" null)))
115
116;; Maps foreign type checks to types
117
118(define +ffi-type-check-map+
119  '(("C_i_foreign_fixnum_argumentp" fixnum)
120    ("C_i_foreign_integer_argumentp" integer fixnum bignum)
121    ("C_i_foreign_char_argumentp" char)
122    ("C_i_foreign_flonum_argumentp" float)
123    ("C_i_foreign_string_argumentp" string)
124    ("C_i_foreign_symbol_argumentp" symbol)))
125
126;; Maps constructors to types
127
128(define +constructor-map+
129  '(("C_a_i_record1" *struct*)		; special case
130    ("C_a_i_record2" *struct*)
131    ("C_a_i_record3" *struct*)
132    ("C_a_i_record4" *struct*)
133    ("C_a_i_record5" *struct*)
134    ("C_a_i_record6" *struct*)
135    ("C_a_i_record7" *struct*)
136    ("C_a_i_record8" *struct*)
137    ("C_a_i_record" *struct*)
138    ("C_a_i_string" string)
139    ("C_a_i_port" port)
140    ("C_a_i_vector1" vector)
141    ("C_a_i_vector2" vector)
142    ("C_a_i_vector3" vector)
143    ("C_a_i_vector4" vector)
144    ("C_a_i_vector5" vector)
145    ("C_a_i_vector6" vector)
146    ("C_a_i_vector7" vector)
147    ("C_a_i_vector8" vector)
148    ("C_a_pair" pair)
149    ("C_a_i_bytevector" blob)
150    ("C_a_i_make_locative" locative)
151    ("C_a_i_vector" vector)
152    ("C_a_i_list1" pair)
153    ("C_a_i_list2" pair)
154    ("C_a_i_list3" pair)
155    ("C_a_i_list4" pair)
156    ("C_a_i_list5" pair)
157    ("C_a_i_list6" pair)
158    ("C_a_i_list7" pair)
159    ("C_a_i_list8" pair)
160    ("C_a_i_cons" pair)
161    ("C_a_i_flonum" float)
162    ("C_a_i_fix_to_flo" float)
163    ("C_a_i_big_to_flo" float)
164    ("C_a_i_fix_to_big" bignum)
165    ("C_a_i_bignum0" bignum)
166    ("C_a_i_bignum1" bignum)
167    ("C_a_i_bignum2" bignum)
168    ("C_a_i_flonum_abs" float)
169    ("C_a_i_flonum_acos" float)
170    ("C_a_i_flonum_acosh" float)
171    ("C_a_i_flonum_actual_quotient_checked" float)
172    ("C_a_i_flonum_asin" float)
173    ("C_a_i_flonum_asinh" float)
174    ("C_a_i_flonum_atan2" float)
175    ("C_a_i_flonum_atan" float)
176    ("C_a_i_flonum_atanh" float)
177    ("C_a_i_flonum_ceiling" float)
178    ("C_a_i_flonum_cos" float)
179    ("C_a_i_flonum_cosh" float)
180    ("C_a_i_flonum_difference" float)
181    ("C_a_i_flonum_exp" float)
182    ("C_a_i_flonum_expt" float)
183    ("C_a_i_flonum_floor" float)
184    ("C_a_i_flonum_gcd" float)
185    ("C_a_i_flonum_log" float)
186    ("C_a_i_flonum_modulo_checked" float)
187    ("C_a_i_flonum_negate" float)
188    ("C_a_i_flonum_plus" float)
189    ("C_a_i_flonum_quotient_checked" float)
190    ("C_a_i_flonum_quotient" float)
191    ("C_a_i_flonum_remainder_checked" float)
192    ("C_a_i_flonum_round" float)
193    ("C_a_i_flonum_round_proper" float)
194    ("C_a_i_flonum_sin" float)
195    ("C_a_i_flonum_sinh" float)
196    ("C_a_i_flonum_sqrt" float)
197    ("C_a_i_flonum_tan" float)
198    ("C_a_i_flonum_tanh" float)
199    ("C_a_i_flonum_times" float)
200    ("C_a_i_flonum_multiply_add" float)
201    ("C_a_i_flonum_truncate" float)
202    ("C_a_u_i_f64vector_ref" float)
203    ("C_a_u_i_f32vector_ref" float)
204    ;;XXX are there more?
205    ))
206
207(define +unboxed-map+
208  '(("C_a_i_flonum_plus" "C_ub_i_flonum_plus" op)
209    ("C_a_i_flonum_difference" "C_ub_i_flonum_difference" op)
210    ("C_a_i_flonum_times" "C_ub_i_flonum_times" op)
211    ("C_a_i_flonum_multiply_add" "C_ub_i_flonum_multiply_add" op)
212    ("C_a_i_flonum_quotient" "C_ub_i_flonum_quotient" op)
213    ("C_flonum_equalp" "C_ub_i_flonum_equalp" pred)
214    ("C_flonum_greaterp" "C_ub_i_flonum_greaterp" pred)
215    ("C_flonum_lessp" "C_ub_i_flonum_lessp" pred)
216    ("C_flonum_greater_or_equal_p" "C_ub_i_flonum_greater_or_equal_p" pred)
217    ("C_flonum_less_or_equal_p" "C_ub_i_flonum_less_or_equal_p" pred)
218    ("C_u_i_flonum_nanp" "C_ub_i_flonum_nanp" pred)
219    ("C_u_i_flonum_infinitep" "C_ub_i_flonum_infinitep" pred)
220    ("C_u_i_flonum_finitepp" "C_ub_i_flonum_finitep" pred)
221    ("C_a_i_flonum_sin" "C_sin" op)
222    ("C_a_i_flonum_cos" "C_cos" op)
223    ("C_a_i_flonum_tan" "C_tan" op)
224    ("C_a_i_flonum_asin" "C_asin" op)
225    ("C_a_i_flonum_acos" "C_acos" op)
226    ("C_a_i_flonum_atan" "C_atan" op)
227    ("C_a_i_flonum_atan2" "C_atan2" op)
228    ("C_a_i_flonum_sinh" "C_sinh" op)
229    ("C_a_i_flonum_cosh" "C_cosh" op)
230    ("C_a_i_flonum_tanh" "C_tanh" op)
231    ("C_a_i_flonum_asinh" "C_asinh" op)
232    ("C_a_i_flonum_acosh" "C_acosh" op)
233    ("C_a_i_flonum_atanh" "C_atanh" op)
234    ("C_a_i_flonum_exp" "C_exp" op)
235    ("C_a_i_flonum_expr" "C_pow" op)
236    ("C_a_i_flonum_log" "C_log" op)
237    ("C_a_i_flonum_sqrt" "C_sqrt" op)
238    ("C_a_i_flonum_truncate" "C_trunc" op)
239    ("C_a_i_flonum_ceiling" "C_ceil" op)
240    ("C_a_i_flonum_floor" "C_floor" op)
241    ("C_a_i_flonum_round" "C_round" op)
242    ("C_a_i_flonum_abs" "C_fabs" op)
243    ("C_a_u_i_f32vector_ref" "C_ub_i_f32vector_ref" acc)
244    ("C_a_u_i_f64vector_ref" "C_ub_i_f64vector_ref" acc)))
245
246
247;;; Walk nodes and perform simplified type-analysis
248
249(define (perform-secondary-flow-analysis node db)
250  (let ((stats '())
251        (floatvars '()))
252
253    (define (constant-result lit) 
254      ;; a simplified variant of the one in scrutinizer.scm
255      (cond ((string? lit) 'string)
256	    ((keyword? lit) 'keyword)
257	    ((symbol? lit) 'symbol)
258	    ;; Do not assume fixnum width matches target platforms!
259	    ((or (big-fixnum? lit) (small-bignum? lit)) 'integer)
260	    ((fixnum? lit) 'fixnum)
261	    ((bignum? lit) 'bignum)
262	    ((flonum? lit) 'float)
263	    ((ratnum? lit) 'ratnum)
264	    ((cplxnum? lit) 'cplxnum)
265	    ((boolean? lit) 'boolean)
266	    ((null? lit) 'null)
267	    ((list? lit) 'list)
268	    ((pair? lit) 'pair)
269	    ((eof-object? lit) 'eof)
270	    ;; TODO: Remove once we have a bootstrapping libchicken with bwp-object?
271	    ((##core#inline "C_bwpp" lit) #;(bwp-object? lit) 'bwp)
272	    ((vector? lit) 'vector)
273	    ((and (not (##sys#immediate? lit)) (##sys#generic-structure? lit))
274	     `(struct ,(##sys#slot lit 0)))
275	    ((char? lit) 'char)
276	    (else '*)))
277    
278    (define (merge t1 t2)
279      (cond ((eq? t1 t2) t1)
280            ((and (pair? t1) (pair? t2)
281                  (eq? (car t1) 'struct)
282                  (eq? (car t2) 'struct)
283                  (eq? (cadr t1) (cadr t2)))
284             t1)
285            (else '*)))
286
287    (define (report elim)
288      (cond ((assoc elim stats) =>
289	     (lambda (a) (set-cdr! a (add1 (cdr a)))))
290	    (else (set! stats (alist-cons elim 1 stats)))))
291 
292    (define (assigned? var)
293      (db-get db var 'assigned))
294
295    (define (droppable? n)
296      (or (memq (node-class n) 
297		'(quote ##core#undefined ##core#primitive ##core#lambda))
298	  (and (eq? '##core#variable (node-class n))
299	       (let ((var (first (node-parameters n))))
300		 (or (not (db-get db var 'global))
301		     (variable-mark var '##compiler#always-bound))))))
302
303    (define (drop! n)
304      (sub-boxed n)
305      (node-class-set! n '##core#undefined)
306      (node-parameters-set! n '())
307      (node-subexpressions-set! n '()))
308
309    (define (extinguish! node rpl)	; replace ##core#inline call
310      (report (first (node-parameters node)))
311      (let ((subs (node-subexpressions node))
312	    (alldropped #t))
313	(for-each
314	 (lambda (sn)
315	   (if (droppable? sn)
316	       (drop! sn)
317	       (set! alldropped #f)))
318	 subs)
319	(if alldropped
320	    (drop! node)
321	    (node-parameters-set!
322	     node
323	     (list
324	      (string-append
325	       rpl
326	       (case (length (node-subexpressions node))
327		 ((1) "1")
328		 ((2) "2")
329		 ((3) "3")
330		 (else (bomb "bad number of arguments to extinguished ##core#inline")))))))))
331
332    (define (vartype v te ae)
333      (cond ((assq v te) => cdr)
334	    (else
335	     (let loop ((ae ae))
336	       (cond ((null? ae) '*)
337		     ((and (eq? v (cdar ae)) 
338			   (assq (caar ae) te) )
339		      => cdr)
340		     (else (loop (cdr ae))))))))
341
342    (define (varnode? n)
343      (eq? '##core#variable (node-class n)))
344
345    (define (floatvar? var)
346      (assq var floatvars))
347
348    (define (eliminate-floatvar var)
349      (set! floatvars
350        (remove (lambda (a) (eq? var (car a))) floatvars)))
351
352    (define (count-floatvar node acc #!optional (n 1))
353      (cond ((and (varnode? node)
354                  (assq (first (node-parameters node)) floatvars))
355             =>
356             (lambda (a)
357               (set-car! (acc a) (+ n (car (acc a))))))))
358
359    (define (add-boxed node) (count-floatvar node cdr))
360    (define (add-unboxed node) (count-floatvar node cddr))
361    (define (sub-boxed node) (count-floatvar node cdr -1))
362
363    (define (walk n te ae)
364      (let ((class (node-class n))
365	    (params (node-parameters n))
366	    (subs (node-subexpressions n)))
367	(case class
368	  ((##core#variable)
369           (when (and (floatvar? (first params))
370                      (not (assq (first params) te)))
371             (eliminate-floatvar (first params)))
372           (add-boxed n)
373	   (vartype (first params) te ae))
374	  ((if ##core#cond) 
375	   (let ((tr (walk (first subs) te ae)))
376	     (if (and (pair? tr) (eq? 'boolean (car tr)))
377                 (merge (walk (second subs)
378                              (append (second tr) te)
379                              ae)
380                        (walk (third subs)
381                              (append (third tr) te)
382                              ae)))
383                 (merge (walk (second subs) te ae)
384                        (walk (third subs) te ae))))
385	  ((quote) (constant-result (first params)))
386	  ((let)
387	   (let* ((val (first subs))
388		  (var (first params))
389		  (r (walk val te ae))
390                  (avar (assigned? var)))
391             (cond ((and (not avar)
392                         (eq? 'float r)
393                         (not (floatvar? var)))
394                    (set! floatvars (cons (list var 0 0) floatvars))
395                    (add-unboxed val))
396                   (else (add-boxed val)))
397             (walk (second subs)
398		   (if avar
399		       te
400		       (alist-cons var r te))
401		   (if (and (varnode? val)
402			    (not avar)
403			    (not (assigned? (first (node-parameters val)))))
404		       (let ((var2 (first (node-parameters val))))
405			 (alist-cons var var2 (alist-cons var2 var ae)))
406		       ae))))
407	  ((##core#lambda ##core#direct_lambda)
408	   ;; fresh env and we don't bother to create entries in the environment
409	   ;; for the llist-bound variables (missing implies type '*)
410	   ;;XXX (but we could treat the first arg in non-CPS lambdas as procedure...)
411	   (walk (first subs) '() '())
412	   'procedure)
413	  ((set! ##core#set!)	       ;XXX is ##core#set! still used?
414           (let ((val (first subs)))
415             (when (and (varnode? val)
416                        (floatvar? (first (node-parameters val))))
417               (eliminate-floatvar (first (node-parameters val))))
418             (walk val te ae)
419             'undefined))
420	  ((##core#undefined) 'undefined)
421	  ((##core#primitive) 'procedure)
422	  ((##core#inline ##core#inline_allocate)
423           (let ((ubop (assoc (first params) +unboxed-map+)))
424             (for-each
425               (lambda (arg)
426                 (walk arg te ae)
427                 (when ubop (add-unboxed arg)))
428               subs))
429	   (cond ((assoc (first params) +type-check-map+) =>
430		  (lambda (a)
431		    (let ((r1 (walk (first subs) te ae)))
432		      (cond (unsafe
433			     (extinguish! n "C_i_noop"))
434			    ((eq? '*struct* (cadr a))
435			     ;; handle known structure type
436			     (when (and (pair? r1)
437					(eq? 'struct (first r1))
438					(eq? 'quote (node-class (second subs))))
439			       (let ((st (first (node-parameters (second subs)))))
440				 (when (and (symbol? st)
441					    (eq? st (second r1)))
442				   (extinguish! n "C_i_noop")))))
443			    ((and (pair? r1) (eq? 'boolean (car r1)))
444			     (when (memq 'boolean (cdr a))
445			       (extinguish! n "C_i_noop")))
446			    ;; handle other types
447			    ((member r1 (cdr a))
448			     (extinguish! n "C_i_noop")))
449		      '*)))
450		 ((assoc (first params) +ffi-type-check-map+) =>
451		  (lambda (a)
452		    (let* ((arg (first subs))
453                           (r1 (walk arg te ae)))
454		      (when (member r1 (cdr a))
455                        (node-class-set! n (node-class arg))
456                        (node-parameters-set! n (node-parameters arg))
457	       	        (node-subexpressions-set! n (node-subexpressions arg)))
458                      ;; the ffi checks are enforcing so we always end up with
459		      ;; the correct type
460		      r1)))
461		 ((assoc (first params) +predicate-map+) =>
462		  (lambda (a)
463		    (let ((arg (first subs)))
464		      (cond ((varnode? arg)
465			      `(boolean
466				((,(first (node-parameters arg))
467				  .
468				  ,(if (eq? '*struct* (cadr a))
469				       (if (eq? 'quote (node-class (second subs)))
470					   (let ((st (first
471						       (node-parameters
472							   (second subs)))))
473					     (if (symbol? st)
474						 `(struct ,st)
475						 'struct))
476					    'struct)
477					(cadr a))))
478				()))
479			    (else
480			      (let ((r1 (walk arg te ae)))
481				(cond ((eq? '*struct* (cadr a))
482				       ;; known structure type
483				       (when (and (pair? r1)
484						  (eq? 'struct (first r1))
485						  (eq? 'quote (node-class (second subs))))
486					 (let ((st (first
487						    (node-parameters (second subs)))))
488					   (when (and (symbol? st)
489						      (eq? st (second r1)))
490					     (extinguish! n "C_i_true")))))
491				      ((and (pair? r1) (eq? 'boolean (car r1)))
492				       (when (memq 'boolean (cdr a))
493					 (extinguish! n "C_i_true")))
494				      ;; other types
495				      ((member r1 (cdr a))
496					(extinguish! n "C_i_true")))
497				'boolean))))))
498		 ((assoc (first params) +constructor-map+) =>
499		  (lambda (a)
500		    (let ((arg1 (and (pair? subs) (first subs))))
501		      (if (and arg1
502			       (eq? '*struct* (cadr a))
503			       (eq? 'quote (node-class arg1)))
504			  (let ((tag (first (node-parameters arg1))))
505			    (if (symbol? tag)
506				`(struct ,tag)
507				'struct))
508			  (cadr a)))))))
509	  (else 
510	   (for-each (cut walk <> te ae) subs)
511	   '*))))
512
513    (walk node '() '())
514    (when (pair? stats)
515      (with-debugging-output
516       '(x o)
517       (lambda ()
518	 (print "eliminated type checks:")
519	 (for-each 
520	  (lambda (ss) (printf "  ~a:\t~a~%" (car ss) (cdr ss)))
521	  stats))))
522    floatvars))
523
524
525(define (perform-unboxing node floatvar-counts)
526  (let ((floatvars (filter-map
527		     (lambda (a)
528		       (and (= (cadr a) (caddr a))
529			    (car a)))
530		     floatvar-counts))
531	(count 0))
532
533    (define (walk/unbox n)
534      (let ((class (node-class n))
535	    (params (node-parameters n))
536	    (subs (node-subexpressions n)))
537	(case class
538	  ((quote)
539	   (let ((c (first params)))
540	     (if (##core#inline "C_i_flonump" c)
541		 (make-node '##core#float (list c) '())
542		 n)))
543	  ((##core#variable)
544	   (let ((i (posq (first params) floatvars)))
545	     (if i
546		 (make-node '##core#float-variable (cons i params) '())
547		 (make-node '##core#unbox_float '() (list n)))))
548	  ((##core#inline ##core#inline_allocate)
549	   (cond ((assoc (first params) +unboxed-map+) =>
550		  (lambda (a)
551		    (let ((ub (second a))
552			  (type (third a)))
553		      (set! count (add1 count))
554		      (make-node '##core#inline
555				 (list ub)
556				 (map (if (eq? type 'op)
557					  walk/unbox
558					  walk)
559				   subs)))))
560		 (else
561		   (make-node '##core#unbox_float '()
562			      (list (make-node class params
563					       (map walk subs)))))))
564	  (else (make-node '##core#unbox_float '() (list (walk n)))))))
565
566    (define (walk n)
567      (let ((class (node-class n))
568	    (params (node-parameters n))
569	    (subs (node-subexpressions n)))
570	(case class
571	  ((##core#variable)
572	   (let ((i (posq (first params) floatvars)))
573	     (if i
574		 (make-node '##core#box_float '()
575			    (list (make-node '##core#float-variable
576					     (cons i params) '())))
577		 n)))
578	  ((let)
579	   (let* ((val (first subs))
580		  (var (first params))
581		  (i (posq var floatvars)))
582	     (if i
583		 (make-node '##core#let_float (list i var)
584			    (list (walk/unbox val)
585				  (walk (second subs))))
586		 (make-node 'let params (map walk subs)))))
587	  ((##core#inline ##core#inline_allocate)
588	   (cond ((assoc (first params) +unboxed-map+) =>
589		  (lambda (a)
590		    (let ((ub (second a))
591			  (type (third a)))
592		      (set! count (add1 count))
593		      (let ((n (make-node '##core#inline
594					  (list ub)
595					  (map (if (eq? type 'acc)
596						   walk
597						   walk/unbox)
598					       subs))))
599			(case type
600			  ((pred) n)
601			  (else (make-node '##core#box_float '()
602					   (list n))))))))
603		 (else (make-node class params (map walk subs)))))
604	  (else (make-node class params (map walk subs))))))
605
606    (let ((node (walk node)))
607      (with-debugging-output
608       '(x o)
609       (lambda ()
610	 (printf "number of unboxed float variables: ~a\n"
611	  (length floatvars))
612	 (printf "number of inline operations replaced with unboxed ones: ~a\n"
613		 count)))
614      node)))
615
616)
Trap