~ chicken-core (chicken-5) /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" 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)