~ chicken-core (master) /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_inexact" float)	; Or an inexact cplxnum...
 60    ("C_i_check_number" fixnum integer bignum ratnum float cplxnum number)
 61    ("C_i_check_string" string)
 62    ("C_i_check_bytevector" bytevector)
 63    ("C_i_check_symbol" symbol)
 64    ("C_i_check_keyword" keyword)
 65    ("C_i_check_list" null pair list)
 66    ("C_i_check_pair" pair)
 67    ("C_i_check_locative" locative)
 68    ("C_i_check_boolean" boolean)
 69    ("C_i_check_vector" vector)
 70    ("C_i_check_structure" *struct*)	; special case
 71    ("C_i_check_char" char)
 72    ("C_i_check_closure_2" procedure)
 73    ("C_i_check_inexact_2" float)	; Or an inexact cplxnum...
 74    ("C_i_check_number_2" fixnum integer bignum ratnum float cplxnum number)
 75    ("C_i_check_string_2" string)
 76    ("C_i_check_bytevector_2" bytevector)
 77    ("C_i_check_symbol_2" symbol)
 78    ("C_i_check_keyword_2" keyword)
 79    ("C_i_check_list_2" null pair list)
 80    ("C_i_check_pair_2" pair)
 81    ("C_i_check_locative_2" locative)
 82    ("C_i_check_boolean_2" boolean)
 83    ("C_i_check_vector_2" vector)
 84    ("C_i_check_structure_2" *struct*)	; special case
 85    ("C_i_check_char_2" char)))
 86
 87
 88;; Maps predicates to types
 89 
 90(define +predicate-map+
 91  '(("C_i_closurep" procedure)
 92    ("C_fixnump" fixnum)
 93    ("C_bignump" bignum)
 94    ("C_i_exact_integerp" integer fixnum bignum)
 95    ("C_i_flonump" float)
 96    ("C_i_numberp" number fixnum integer bignum ratnum float cplxnum)
 97    ("C_i_ratnump" ratnum)
 98    ("C_i_cplxnump" cplxnum)
 99    ("C_stringp" string)
100    ("C_bytevectorp" bytevector)
101    ("C_i_keywordp" keyword)
102    ("C_i_symbolp" symbol)
103    ("C_i_listp" list)
104    ("C_i_pairp" pair)
105    ("C_locativep" locative)
106    ("C_booleanp" boolean)
107    ("C_i_vectorp" vector)
108    ("C_structurep" struct)
109    ("C_i_structurep" *struct*)		; special case
110    ("C_charp" char)
111    ("C_i_portp" port)
112    ("C_i_nullp" null)))
113
114;; Maps foreign type checks to types
115
116(define +ffi-type-check-map+
117  '(("C_i_foreign_fixnum_argumentp" fixnum)
118    ("C_i_foreign_integer_argumentp" integer fixnum bignum)
119    ("C_i_foreign_char_argumentp" char)
120    ("C_i_foreign_flonum_argumentp" float)
121    ("C_i_foreign_string_argumentp" string)
122    ("C_i_foreign_symbol_argumentp" symbol)))
123
124;; Maps constructors to types
125
126(define +constructor-map+
127  '(("C_a_i_record1" *struct*)		; special case
128    ("C_a_i_record2" *struct*)
129    ("C_a_i_record3" *struct*)
130    ("C_a_i_record4" *struct*)
131    ("C_a_i_record5" *struct*)
132    ("C_a_i_record6" *struct*)
133    ("C_a_i_record7" *struct*)
134    ("C_a_i_record8" *struct*)
135    ("C_a_i_record" *struct*)
136    ("C_a_i_string" string)
137    ("C_a_i_port" port)
138    ("C_a_i_vector1" vector)
139    ("C_a_i_vector2" vector)
140    ("C_a_i_vector3" vector)
141    ("C_a_i_vector4" vector)
142    ("C_a_i_vector5" vector)
143    ("C_a_i_vector6" vector)
144    ("C_a_i_vector7" vector)
145    ("C_a_i_vector8" vector)
146    ("C_a_pair" pair)
147    ("C_a_i_bytevector" bytevector)
148    ("C_a_i_make_locative" locative)
149    ("C_a_i_vector" vector)
150    ("C_a_i_list1" pair)
151    ("C_a_i_list2" pair)
152    ("C_a_i_list3" pair)
153    ("C_a_i_list4" pair)
154    ("C_a_i_list5" pair)
155    ("C_a_i_list6" pair)
156    ("C_a_i_list7" pair)
157    ("C_a_i_list8" pair)
158    ("C_a_i_cons" pair)
159    ("C_a_i_flonum" float)
160    ("C_a_i_fix_to_flo" float)
161    ("C_a_i_big_to_flo" float)
162    ("C_a_i_fix_to_big" bignum)
163    ("C_a_i_bignum0" bignum)
164    ("C_a_i_bignum1" bignum)
165    ("C_a_i_bignum2" bignum)
166    ("C_a_i_flonum_abs" float)
167    ("C_a_i_flonum_acos" float)
168    ("C_a_i_flonum_acosh" float)
169    ("C_a_i_flonum_actual_quotient_checked" float)
170    ("C_a_i_flonum_asin" float)
171    ("C_a_i_flonum_asinh" float)
172    ("C_a_i_flonum_atan2" float)
173    ("C_a_i_flonum_atan" float)
174    ("C_a_i_flonum_atanh" float)
175    ("C_a_i_flonum_ceiling" float)
176    ("C_a_i_flonum_cos" float)
177    ("C_a_i_flonum_cosh" float)
178    ("C_a_i_flonum_difference" float)
179    ("C_a_i_flonum_exp" float)
180    ("C_a_i_flonum_expt" float)
181    ("C_a_i_flonum_floor" float)
182    ("C_a_i_flonum_gcd" float)
183    ("C_a_i_flonum_log" float)
184    ("C_a_i_flonum_modulo_checked" float)
185    ("C_a_i_flonum_negate" float)
186    ("C_a_i_flonum_plus" float)
187    ("C_a_i_flonum_quotient_checked" float)
188    ("C_a_i_flonum_quotient" float)
189    ("C_a_i_flonum_remainder_checked" float)
190    ("C_a_i_flonum_round" float)
191    ("C_a_i_flonum_round_proper" float)
192    ("C_a_i_flonum_sin" float)
193    ("C_a_i_flonum_sinh" float)
194    ("C_a_i_flonum_sqrt" float)
195    ("C_a_i_flonum_tan" float)
196    ("C_a_i_flonum_tanh" float)
197    ("C_a_i_flonum_times" float)
198    ("C_a_i_flonum_multiply_add" float)
199    ("C_a_i_flonum_truncate" float)
200    ("C_a_u_i_f64vector_ref" float)
201    ("C_a_u_i_f32vector_ref" float)
202    ;;XXX are there more?
203    ))
204
205(define +unboxed-map+
206  '(("C_a_i_flonum_plus" "C_ub_i_flonum_plus" op)
207    ("C_a_i_flonum_difference" "C_ub_i_flonum_difference" op)
208    ("C_a_i_flonum_times" "C_ub_i_flonum_times" op)
209    ("C_a_i_flonum_multiply_add" "C_ub_i_flonum_multiply_add" op)
210    ("C_a_i_flonum_quotient" "C_ub_i_flonum_quotient" op)
211    ("C_flonum_equalp" "C_ub_i_flonum_equalp" pred)
212    ("C_flonum_greaterp" "C_ub_i_flonum_greaterp" pred)
213    ("C_flonum_lessp" "C_ub_i_flonum_lessp" pred)
214    ("C_flonum_greater_or_equal_p" "C_ub_i_flonum_greater_or_equal_p" pred)
215    ("C_flonum_less_or_equal_p" "C_ub_i_flonum_less_or_equal_p" pred)
216    ("C_u_i_flonum_nanp" "C_ub_i_flonum_nanp" pred)
217    ("C_u_i_flonum_infinitep" "C_ub_i_flonum_infinitep" pred)
218    ("C_u_i_flonum_finitepp" "C_ub_i_flonum_finitep" pred)
219    ("C_a_i_flonum_sin" "C_sin" op)
220    ("C_a_i_flonum_cos" "C_cos" op)
221    ("C_a_i_flonum_tan" "C_tan" op)
222    ("C_a_i_flonum_asin" "C_asin" op)
223    ("C_a_i_flonum_acos" "C_acos" op)
224    ("C_a_i_flonum_atan" "C_atan" op)
225    ("C_a_i_flonum_atan2" "C_atan2" op)
226    ("C_a_i_flonum_sinh" "C_sinh" op)
227    ("C_a_i_flonum_cosh" "C_cosh" op)
228    ("C_a_i_flonum_tanh" "C_tanh" op)
229    ("C_a_i_flonum_asinh" "C_asinh" op)
230    ("C_a_i_flonum_acosh" "C_acosh" op)
231    ("C_a_i_flonum_atanh" "C_atanh" op)
232    ("C_a_i_flonum_exp" "C_exp" op)
233    ("C_a_i_flonum_expr" "C_pow" op)
234    ("C_a_i_flonum_log" "C_log" op)
235    ("C_a_i_flonum_sqrt" "C_sqrt" op)
236    ("C_a_i_flonum_truncate" "C_trunc" op)
237    ("C_a_i_flonum_ceiling" "C_ceil" op)
238    ("C_a_i_flonum_floor" "C_floor" op)
239    ("C_a_i_flonum_round" "C_round" op)
240    ("C_a_i_flonum_abs" "C_fabs" op)
241    ("C_a_u_i_f32vector_ref" "C_ub_i_f32vector_ref" acc)
242    ("C_a_u_i_f64vector_ref" "C_ub_i_f64vector_ref" acc)))
243
244
245;;; Walk nodes and perform simplified type-analysis
246
247(define (perform-secondary-flow-analysis node db)
248  (let ((stats '())
249        (floatvars '()))
250
251    (define (constant-result lit) 
252      ;; a simplified variant of the one in scrutinizer.scm
253      (cond ((string? lit) 'string)
254	    ((keyword? lit) 'keyword)
255	    ((symbol? lit) 'symbol)
256	    ;; Do not assume fixnum width matches target platforms!
257	    ((or (big-fixnum? lit) (small-bignum? lit)) 'integer)
258	    ((fixnum? lit) 'fixnum)
259	    ((bignum? lit) 'bignum)
260	    ((flonum? lit) 'float)
261	    ((ratnum? lit) 'ratnum)
262	    ((cplxnum? lit) 'cplxnum)
263	    ((boolean? lit) 'boolean)
264	    ((null? lit) 'null)
265	    ((list? lit) 'list)
266	    ((pair? lit) 'pair)
267	    ((eof-object? lit) 'eof)
268	    ((bwp-object? lit) 'bwp)
269	    ((vector? lit) 'vector)
270	    ((and (not (##sys#immediate? lit)) (##sys#generic-structure? lit))
271	     `(struct ,(##sys#slot lit 0)))
272	    ((char? lit) 'char)
273	    (else '*)))
274    
275    (define (merge t1 t2)
276      (cond ((eq? t1 t2) t1)
277            ((and (pair? t1) (pair? t2)
278                  (eq? (car t1) 'struct)
279                  (eq? (car t2) 'struct)
280                  (eq? (cadr t1) (cadr t2)))
281             t1)
282            (else '*)))
283
284    (define (report elim)
285      (cond ((assoc elim stats) =>
286	     (lambda (a) (set-cdr! a (add1 (cdr a)))))
287	    (else (set! stats (alist-cons elim 1 stats)))))
288 
289    (define (assigned? var)
290      (db-get db var 'assigned))
291
292    (define (droppable? n)
293      (or (memq (node-class n) 
294		'(quote ##core#undefined ##core#primitive ##core#lambda))
295	  (and (eq? '##core#variable (node-class n))
296	       (let ((var (first (node-parameters n))))
297		 (or (not (db-get db var 'global))
298		     (variable-mark var '##compiler#always-bound))))))
299
300    (define (drop! n)
301      (sub-boxed n)
302      (node-class-set! n '##core#undefined)
303      (node-parameters-set! n '())
304      (node-subexpressions-set! n '()))
305
306    (define (extinguish! node rpl)	; replace ##core#inline call
307      (report (first (node-parameters node)))
308      (let ((subs (node-subexpressions node))
309	    (alldropped #t))
310	(for-each
311	 (lambda (sn)
312	   (if (droppable? sn)
313	       (drop! sn)
314	       (set! alldropped #f)))
315	 subs)
316	(if alldropped
317	    (drop! node)
318	    (node-parameters-set!
319	     node
320	     (list
321	      (string-append
322	       rpl
323	       (case (length (node-subexpressions node))
324		 ((1) "1")
325		 ((2) "2")
326		 ((3) "3")
327		 (else (bomb "bad number of arguments to extinguished ##core#inline")))))))))
328
329    (define (vartype v te ae)
330      (cond ((assq v te) => cdr)
331	    (else
332	     (let loop ((ae ae))
333	       (cond ((null? ae) '*)
334		     ((and (eq? v (cdar ae)) 
335			   (assq (caar ae) te) )
336		      => cdr)
337		     (else (loop (cdr ae))))))))
338
339    (define (varnode? n)
340      (eq? '##core#variable (node-class n)))
341
342    (define (floatvar? var)
343      (assq var floatvars))
344
345    (define (eliminate-floatvar var)
346      (set! floatvars
347        (remove (lambda (a) (eq? var (car a))) floatvars)))
348
349    (define (count-floatvar node acc #!optional (n 1))
350      (cond ((and (varnode? node)
351                  (assq (first (node-parameters node)) floatvars))
352             =>
353             (lambda (a)
354               (set-car! (acc a) (+ n (car (acc a))))))))
355
356    (define (add-boxed node) (count-floatvar node cdr))
357    (define (add-unboxed node) (count-floatvar node cddr))
358    (define (sub-boxed node) (count-floatvar node cdr -1))
359
360    (define (walk n te ae)
361      (let ((class (node-class n))
362	    (params (node-parameters n))
363	    (subs (node-subexpressions n)))
364	(case class
365	  ((##core#variable)
366           (when (and (floatvar? (first params))
367                      (not (assq (first params) te)))
368             (eliminate-floatvar (first params)))
369           (add-boxed n)
370	   (vartype (first params) te ae))
371	  ((if ##core#cond) 
372	   (let ((tr (walk (first subs) te ae)))
373	     (if (and (pair? tr) (eq? 'boolean (car tr)))
374                 (merge (walk (second subs)
375                              (append (second tr) te)
376                              ae)
377                        (walk (third subs)
378                              (append (third tr) te)
379                              ae))
380                 (merge (walk (second subs) te ae)
381                        (walk (third subs) te ae)))))
382	  ((quote) (constant-result (first params)))
383	  ((let)
384	   (let* ((val (first subs))
385		  (var (first params))
386		  (r (walk val te ae))
387                  (avar (assigned? var)))
388             (cond ((and (not avar)
389                         (eq? 'float r)
390                         (not (floatvar? var)))
391                    (set! floatvars (cons (list var 0 0) floatvars))
392                    (add-unboxed val))
393                   (else (add-boxed val)))
394             (walk (second subs)
395		   (if avar
396		       te
397		       (alist-cons var r te))
398		   (if (and (varnode? val)
399			    (not avar)
400			    (not (assigned? (first (node-parameters val)))))
401		       (let ((var2 (first (node-parameters val))))
402			 (alist-cons var var2 (alist-cons var2 var ae)))
403		       ae))))
404	  ((##core#lambda ##core#direct_lambda)
405	   ;; fresh env and we don't bother to create entries in the environment
406	   ;; for the llist-bound variables (missing implies type '*)
407	   ;;XXX (but we could treat the first arg in non-CPS lambdas as procedure...)
408	   (walk (first subs) '() '())
409	   'procedure)
410	  ((set! ##core#set!)	       ;XXX is ##core#set! still used?
411           (let ((val (first subs)))
412             (when (and (varnode? val)
413                        (floatvar? (first (node-parameters val))))
414               (eliminate-floatvar (first (node-parameters val))))
415             (walk val te ae)
416             'undefined))
417	  ((##core#undefined) 'undefined)
418	  ((##core#primitive) 'procedure)
419	  ((##core#inline ##core#inline_allocate)
420           (let ((ubop (assoc (first params) +unboxed-map+)))
421             (for-each
422               (lambda (arg)
423                 (walk arg te ae)
424                 (when ubop (add-unboxed arg)))
425               subs))
426	   (cond ((assoc (first params) +type-check-map+) =>
427		  (lambda (a)
428		    (let ((r1 (walk (first subs) te ae)))
429		      (cond (unsafe
430			     (extinguish! n "C_i_noop"))
431			    ((eq? '*struct* (cadr a))
432			     ;; handle known structure type
433			     (when (and (pair? r1)
434					(eq? 'struct (first r1))
435					(eq? 'quote (node-class (second subs))))
436			       (let ((st (first (node-parameters (second subs)))))
437				 (when (and (symbol? st)
438					    (eq? st (second r1)))
439				   (extinguish! n "C_i_noop")))))
440			    ((and (pair? r1) (eq? 'boolean (car r1)))
441			     (when (memq 'boolean (cdr a))
442			       (extinguish! n "C_i_noop")))
443			    ;; handle other types
444			    ((member r1 (cdr a))
445			     (extinguish! n "C_i_noop")))
446		      '*)))
447		 ((assoc (first params) +ffi-type-check-map+) =>
448		  (lambda (a)
449		    (let* ((arg (first subs))
450                           (r1 (walk arg te ae)))
451		      (when (member r1 (cdr a))
452                        (node-class-set! n (node-class arg))
453                        (node-parameters-set! n (node-parameters arg))
454	       	        (node-subexpressions-set! n (node-subexpressions arg)))
455                      ;; the ffi checks are enforcing so we always end up with
456		      ;; the correct type
457		      r1)))
458		 ((assoc (first params) +predicate-map+) =>
459		  (lambda (a)
460		    (let ((arg (first subs)))
461		      (cond ((varnode? arg)
462			      `(boolean
463				((,(first (node-parameters arg))
464				  .
465				  ,(if (eq? '*struct* (cadr a))
466				       (if (eq? 'quote (node-class (second subs)))
467					   (let ((st (first
468						       (node-parameters
469							   (second subs)))))
470					     (if (symbol? st)
471						 `(struct ,st)
472						 'struct))
473					    'struct)
474					(cadr a))))
475				()))
476			    (else
477			      (let ((r1 (walk arg te ae)))
478				(cond ((eq? '*struct* (cadr a))
479				       ;; known structure type
480				       (when (and (pair? r1)
481						  (eq? 'struct (first r1))
482						  (eq? 'quote (node-class (second subs))))
483					 (let ((st (first
484						    (node-parameters (second subs)))))
485					   (when (and (symbol? st)
486						      (eq? st (second r1)))
487					     (extinguish! n "C_i_true")))))
488				      ((and (pair? r1) (eq? 'boolean (car r1)))
489				       (when (memq 'boolean (cdr a))
490					 (extinguish! n "C_i_true")))
491				      ;; other types
492				      ((member r1 (cdr a))
493					(extinguish! n "C_i_true")))
494				'boolean))))))
495		 ((assoc (first params) +constructor-map+) =>
496		  (lambda (a)
497		    (let ((arg1 (and (pair? subs) (first subs))))
498		      (if (and arg1
499			       (eq? '*struct* (cadr a))
500			       (eq? 'quote (node-class arg1)))
501			  (let ((tag (first (node-parameters arg1))))
502			    (if (symbol? tag)
503				`(struct ,tag)
504				'struct))
505			  (cadr a)))))))
506	  (else 
507	   (for-each (cut walk <> te ae) subs)
508	   '*))))
509
510    (walk node '() '())
511    (when (pair? stats)
512      (with-debugging-output
513       '(x o)
514       (lambda ()
515	 (print "eliminated type checks:")
516	 (for-each 
517	  (lambda (ss) (printf "  ~a:\t~a~%" (car ss) (cdr ss)))
518	  stats))))
519    floatvars))
520
521
522(define (perform-unboxing node floatvar-counts)
523  (let ((floatvars (filter-map
524		     (lambda (a)
525		       (and (= (cadr a) (caddr a))
526			    (car a)))
527		     floatvar-counts))
528	(count 0))
529
530    (define (walk/unbox n)
531      (let ((class (node-class n))
532	    (params (node-parameters n))
533	    (subs (node-subexpressions n)))
534	(case class
535	  ((quote)
536	   (let ((c (first params)))
537	     (if (##core#inline "C_i_flonump" c)
538		 (make-node '##core#float (list c) '())
539		 n)))
540	  ((##core#variable)
541	   (let ((i (posq (first params) floatvars)))
542	     (if i
543		 (make-node '##core#float-variable (cons i params) '())
544		 (make-node '##core#unbox_float '() (list n)))))
545	  ((##core#inline ##core#inline_allocate)
546	   (cond ((assoc (first params) +unboxed-map+) =>
547		  (lambda (a)
548		    (let ((ub (second a))
549			  (type (third a)))
550		      (set! count (add1 count))
551		      (make-node '##core#inline
552				 (list ub)
553				 (map (if (eq? type 'op)
554					  walk/unbox
555					  walk)
556				   subs)))))
557		 (else
558		   (make-node '##core#unbox_float '()
559			      (list (make-node class params
560					       (map walk subs)))))))
561	  (else (make-node '##core#unbox_float '() (list (walk n)))))))
562
563    (define (walk n)
564      (let ((class (node-class n))
565	    (params (node-parameters n))
566	    (subs (node-subexpressions n)))
567	(case class
568	  ((##core#variable)
569	   (let ((i (posq (first params) floatvars)))
570	     (if i
571		 (make-node '##core#box_float '()
572			    (list (make-node '##core#float-variable
573					     (cons i params) '())))
574		 n)))
575	  ((let)
576	   (let* ((val (first subs))
577		  (var (first params))
578		  (i (posq var floatvars)))
579	     (if i
580		 (make-node '##core#let_float (list i var)
581			    (list (walk/unbox val)
582				  (walk (second subs))))
583		 (make-node 'let params (map walk subs)))))
584	  ((##core#inline ##core#inline_allocate)
585	   (cond ((assoc (first params) +unboxed-map+) =>
586		  (lambda (a)
587		    (let ((ub (second a))
588			  (type (third a)))
589		      (set! count (add1 count))
590		      (let ((n (make-node '##core#inline
591					  (list ub)
592					  (map (if (eq? type 'acc)
593						   walk
594						   walk/unbox)
595					       subs))))
596			(case type
597			  ((pred) n)
598			  (else (make-node '##core#box_float '()
599					   (list n))))))))
600		 (else (make-node class params (map walk subs)))))
601	  (else (make-node class params (map walk subs))))))
602
603    (let ((node (walk node)))
604      (with-debugging-output
605       '(x o)
606       (lambda ()
607	 (printf "number of unboxed float variables: ~a\n"
608	  (length floatvars))
609	 (printf "number of inline operations replaced with unboxed ones: ~a\n"
610		 count)))
611      node)))
612
613)
Trap