~ 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_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" bytevector)
 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" bytevector)
 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" bytevector)
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" bytevector)
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	    ((bwp-object? lit) 'bwp)
271	    ((vector? lit) 'vector)
272	    ((and (not (##sys#immediate? lit)) (##sys#generic-structure? lit))
273	     `(struct ,(##sys#slot lit 0)))
274	    ((char? lit) 'char)
275	    (else '*)))
276    
277    (define (merge t1 t2)
278      (cond ((eq? t1 t2) t1)
279            ((and (pair? t1) (pair? t2)
280                  (eq? (car t1) 'struct)
281                  (eq? (car t2) 'struct)
282                  (eq? (cadr t1) (cadr t2)))
283             t1)
284            (else '*)))
285
286    (define (report elim)
287      (cond ((assoc elim stats) =>
288	     (lambda (a) (set-cdr! a (add1 (cdr a)))))
289	    (else (set! stats (alist-cons elim 1 stats)))))
290 
291    (define (assigned? var)
292      (db-get db var 'assigned))
293
294    (define (droppable? n)
295      (or (memq (node-class n) 
296		'(quote ##core#undefined ##core#primitive ##core#lambda))
297	  (and (eq? '##core#variable (node-class n))
298	       (let ((var (first (node-parameters n))))
299		 (or (not (db-get db var 'global))
300		     (variable-mark var '##compiler#always-bound))))))
301
302    (define (drop! n)
303      (sub-boxed n)
304      (node-class-set! n '##core#undefined)
305      (node-parameters-set! n '())
306      (node-subexpressions-set! n '()))
307
308    (define (extinguish! node rpl)	; replace ##core#inline call
309      (report (first (node-parameters node)))
310      (let ((subs (node-subexpressions node))
311	    (alldropped #t))
312	(for-each
313	 (lambda (sn)
314	   (if (droppable? sn)
315	       (drop! sn)
316	       (set! alldropped #f)))
317	 subs)
318	(if alldropped
319	    (drop! node)
320	    (node-parameters-set!
321	     node
322	     (list
323	      (string-append
324	       rpl
325	       (case (length (node-subexpressions node))
326		 ((1) "1")
327		 ((2) "2")
328		 ((3) "3")
329		 (else (bomb "bad number of arguments to extinguished ##core#inline")))))))))
330
331    (define (vartype v te ae)
332      (cond ((assq v te) => cdr)
333	    (else
334	     (let loop ((ae ae))
335	       (cond ((null? ae) '*)
336		     ((and (eq? v (cdar ae)) 
337			   (assq (caar ae) te) )
338		      => cdr)
339		     (else (loop (cdr ae))))))))
340
341    (define (varnode? n)
342      (eq? '##core#variable (node-class n)))
343
344    (define (floatvar? var)
345      (assq var floatvars))
346
347    (define (eliminate-floatvar var)
348      (set! floatvars
349        (remove (lambda (a) (eq? var (car a))) floatvars)))
350
351    (define (count-floatvar node acc #!optional (n 1))
352      (cond ((and (varnode? node)
353                  (assq (first (node-parameters node)) floatvars))
354             =>
355             (lambda (a)
356               (set-car! (acc a) (+ n (car (acc a))))))))
357
358    (define (add-boxed node) (count-floatvar node cdr))
359    (define (add-unboxed node) (count-floatvar node cddr))
360    (define (sub-boxed node) (count-floatvar node cdr -1))
361
362    (define (walk n te ae)
363      (let ((class (node-class n))
364	    (params (node-parameters n))
365	    (subs (node-subexpressions n)))
366	(case class
367	  ((##core#variable)
368           (when (and (floatvar? (first params))
369                      (not (assq (first params) te)))
370             (eliminate-floatvar (first params)))
371           (add-boxed n)
372	   (vartype (first params) te ae))
373	  ((if ##core#cond) 
374	   (let ((tr (walk (first subs) te ae)))
375	     (if (and (pair? tr) (eq? 'boolean (car tr)))
376                 (merge (walk (second subs)
377                              (append (second tr) te)
378                              ae)
379                        (walk (third subs)
380                              (append (third tr) te)
381                              ae)))
382                 (merge (walk (second subs) te ae)
383                        (walk (third subs) te ae))))
384	  ((quote) (constant-result (first params)))
385	  ((let)
386	   (let* ((val (first subs))
387		  (var (first params))
388		  (r (walk val te ae))
389                  (avar (assigned? var)))
390             (cond ((and (not avar)
391                         (eq? 'float r)
392                         (not (floatvar? var)))
393                    (set! floatvars (cons (list var 0 0) floatvars))
394                    (add-unboxed val))
395                   (else (add-boxed val)))
396             (walk (second subs)
397		   (if avar
398		       te
399		       (alist-cons var r te))
400		   (if (and (varnode? val)
401			    (not avar)
402			    (not (assigned? (first (node-parameters val)))))
403		       (let ((var2 (first (node-parameters val))))
404			 (alist-cons var var2 (alist-cons var2 var ae)))
405		       ae))))
406	  ((##core#lambda ##core#direct_lambda)
407	   ;; fresh env and we don't bother to create entries in the environment
408	   ;; for the llist-bound variables (missing implies type '*)
409	   ;;XXX (but we could treat the first arg in non-CPS lambdas as procedure...)
410	   (walk (first subs) '() '())
411	   'procedure)
412	  ((set! ##core#set!)	       ;XXX is ##core#set! still used?
413           (let ((val (first subs)))
414             (when (and (varnode? val)
415                        (floatvar? (first (node-parameters val))))
416               (eliminate-floatvar (first (node-parameters val))))
417             (walk val te ae)
418             'undefined))
419	  ((##core#undefined) 'undefined)
420	  ((##core#primitive) 'procedure)
421	  ((##core#inline ##core#inline_allocate)
422           (let ((ubop (assoc (first params) +unboxed-map+)))
423             (for-each
424               (lambda (arg)
425                 (walk arg te ae)
426                 (when ubop (add-unboxed arg)))
427               subs))
428	   (cond ((assoc (first params) +type-check-map+) =>
429		  (lambda (a)
430		    (let ((r1 (walk (first subs) te ae)))
431		      (cond (unsafe
432			     (extinguish! n "C_i_noop"))
433			    ((eq? '*struct* (cadr a))
434			     ;; handle known structure type
435			     (when (and (pair? r1)
436					(eq? 'struct (first r1))
437					(eq? 'quote (node-class (second subs))))
438			       (let ((st (first (node-parameters (second subs)))))
439				 (when (and (symbol? st)
440					    (eq? st (second r1)))
441				   (extinguish! n "C_i_noop")))))
442			    ((and (pair? r1) (eq? 'boolean (car r1)))
443			     (when (memq 'boolean (cdr a))
444			       (extinguish! n "C_i_noop")))
445			    ;; handle other types
446			    ((member r1 (cdr a))
447			     (extinguish! n "C_i_noop")))
448		      '*)))
449		 ((assoc (first params) +ffi-type-check-map+) =>
450		  (lambda (a)
451		    (let* ((arg (first subs))
452                           (r1 (walk arg te ae)))
453		      (when (member r1 (cdr a))
454                        (node-class-set! n (node-class arg))
455                        (node-parameters-set! n (node-parameters arg))
456	       	        (node-subexpressions-set! n (node-subexpressions arg)))
457                      ;; the ffi checks are enforcing so we always end up with
458		      ;; the correct type
459		      r1)))
460		 ((assoc (first params) +predicate-map+) =>
461		  (lambda (a)
462		    (let ((arg (first subs)))
463		      (cond ((varnode? arg)
464			      `(boolean
465				((,(first (node-parameters arg))
466				  .
467				  ,(if (eq? '*struct* (cadr a))
468				       (if (eq? 'quote (node-class (second subs)))
469					   (let ((st (first
470						       (node-parameters
471							   (second subs)))))
472					     (if (symbol? st)
473						 `(struct ,st)
474						 'struct))
475					    'struct)
476					(cadr a))))
477				()))
478			    (else
479			      (let ((r1 (walk arg te ae)))
480				(cond ((eq? '*struct* (cadr a))
481				       ;; known structure type
482				       (when (and (pair? r1)
483						  (eq? 'struct (first r1))
484						  (eq? 'quote (node-class (second subs))))
485					 (let ((st (first
486						    (node-parameters (second subs)))))
487					   (when (and (symbol? st)
488						      (eq? st (second r1)))
489					     (extinguish! n "C_i_true")))))
490				      ((and (pair? r1) (eq? 'boolean (car r1)))
491				       (when (memq 'boolean (cdr a))
492					 (extinguish! n "C_i_true")))
493				      ;; other types
494				      ((member r1 (cdr a))
495					(extinguish! n "C_i_true")))
496				'boolean))))))
497		 ((assoc (first params) +constructor-map+) =>
498		  (lambda (a)
499		    (let ((arg1 (and (pair? subs) (first subs))))
500		      (if (and arg1
501			       (eq? '*struct* (cadr a))
502			       (eq? 'quote (node-class arg1)))
503			  (let ((tag (first (node-parameters arg1))))
504			    (if (symbol? tag)
505				`(struct ,tag)
506				'struct))
507			  (cadr a)))))))
508	  (else 
509	   (for-each (cut walk <> te ae) subs)
510	   '*))))
511
512    (walk node '() '())
513    (when (pair? stats)
514      (with-debugging-output
515       '(x o)
516       (lambda ()
517	 (print "eliminated type checks:")
518	 (for-each 
519	  (lambda (ss) (printf "  ~a:\t~a~%" (car ss) (cdr ss)))
520	  stats))))
521    floatvars))
522
523
524(define (perform-unboxing node floatvar-counts)
525  (let ((floatvars (filter-map
526		     (lambda (a)
527		       (and (= (cadr a) (caddr a))
528			    (car a)))
529		     floatvar-counts))
530	(count 0))
531
532    (define (walk/unbox n)
533      (let ((class (node-class n))
534	    (params (node-parameters n))
535	    (subs (node-subexpressions n)))
536	(case class
537	  ((quote)
538	   (let ((c (first params)))
539	     (if (##core#inline "C_i_flonump" c)
540		 (make-node '##core#float (list c) '())
541		 n)))
542	  ((##core#variable)
543	   (let ((i (posq (first params) floatvars)))
544	     (if i
545		 (make-node '##core#float-variable (cons i params) '())
546		 (make-node '##core#unbox_float '() (list n)))))
547	  ((##core#inline ##core#inline_allocate)
548	   (cond ((assoc (first params) +unboxed-map+) =>
549		  (lambda (a)
550		    (let ((ub (second a))
551			  (type (third a)))
552		      (set! count (add1 count))
553		      (make-node '##core#inline
554				 (list ub)
555				 (map (if (eq? type 'op)
556					  walk/unbox
557					  walk)
558				   subs)))))
559		 (else
560		   (make-node '##core#unbox_float '()
561			      (list (make-node class params
562					       (map walk subs)))))))
563	  (else (make-node '##core#unbox_float '() (list (walk n)))))))
564
565    (define (walk n)
566      (let ((class (node-class n))
567	    (params (node-parameters n))
568	    (subs (node-subexpressions n)))
569	(case class
570	  ((##core#variable)
571	   (let ((i (posq (first params) floatvars)))
572	     (if i
573		 (make-node '##core#box_float '()
574			    (list (make-node '##core#float-variable
575					     (cons i params) '())))
576		 n)))
577	  ((let)
578	   (let* ((val (first subs))
579		  (var (first params))
580		  (i (posq var floatvars)))
581	     (if i
582		 (make-node '##core#let_float (list i var)
583			    (list (walk/unbox val)
584				  (walk (second subs))))
585		 (make-node 'let params (map walk subs)))))
586	  ((##core#inline ##core#inline_allocate)
587	   (cond ((assoc (first params) +unboxed-map+) =>
588		  (lambda (a)
589		    (let ((ub (second a))
590			  (type (third a)))
591		      (set! count (add1 count))
592		      (let ((n (make-node '##core#inline
593					  (list ub)
594					  (map (if (eq? type 'acc)
595						   walk
596						   walk/unbox)
597					       subs))))
598			(case type
599			  ((pred) n)
600			  (else (make-node '##core#box_float '()
601					   (list n))))))))
602		 (else (make-node class params (map walk subs)))))
603	  (else (make-node class params (map walk subs))))))
604
605    (let ((node (walk node)))
606      (with-debugging-output
607       '(x o)
608       (lambda ()
609	 (printf "number of unboxed float variables: ~a\n"
610	  (length floatvars))
611	 (printf "number of inline operations replaced with unboxed ones: ~a\n"
612		 count)))
613      node)))
614
615)
Trap