~ chicken-core (master) /lfa2.scm
Trap1;;;; 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)