~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to ansi-tests/random-int-form.lsp

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;-*- Mode:     Lisp -*-
 
2
;;;; Author:   Paul Dietz
 
3
;;;; Created:  Wed Sep 10 18:03:52 2003
 
4
;;;; Contains: Simple randon form generator/tester
 
5
 
 
6
(in-package :cl-test)
 
7
 
 
8
(compile-and-load "random-aux.lsp")
 
9
 
 
10
;;;
 
11
;;; This file contains a routine for generating random legal Common Lisp functions
 
12
;;; for differential testing.
 
13
;;;
 
14
;;; To run the random tests by themselves, start a lisp in the ansi-tests directory
 
15
;;; and do the following:
 
16
;;;   (load "gclload1.lsp")
 
17
;;;   (compile-and-load "random-int-form.lsp")
 
18
;;;   (in-package :cl-test)
 
19
;;;   (let ((*random-state* (make-random-state t)))
 
20
;;;      (test-random-integer-forms 100 4 10000)) ;; or other parameters
 
21
;;;
 
22
;;; If a test breaks during testing the variables *optimized-fn-src*,
 
23
;;; *unoptimized-fn-src*, and *int-form-vals* can be used to get the source
 
24
;;; of the optimized/unoptimized lambda forms being compiled, and the arguments
 
25
;;; on which they are called.
 
26
;;;
 
27
;;; If a difference is found between optimized/unoptimized functions the forms,
 
28
;;; values, and results are collected.  A list of all these discrepancies is returned
 
29
;;; after testing finishes (assuming nothing breaks).
 
30
;;;
 
31
;;; The variable *compile-unoptimized-form* controls whether the low optimization
 
32
;;; form is compiled, or if a form funcalling it is EVALed.  The latter is often
 
33
;;; faster, and may find more problems since an interpreter and compiler may evaluate
 
34
;;; forms in very different ways.
 
35
;;;
 
36
;;; The rctest/ subdirectory contains fragments of a more OO random form generator
 
37
;;; that will eventually replace this preliminary effort.
 
38
;;;
 
39
;;; The file misc.lsp contains tests that were mostly for bugs found by this
 
40
;;; random tester in various Common Lisp implementations.
 
41
;;;
 
42
 
 
43
(declaim (special *optimized-fn-src* *unoptimized-fn-src* *int-form-vals*
 
44
                  *opt-result* *unopt-result* $x $y $z
 
45
                  *compile-unoptimized-form*))
 
46
 
 
47
;;; Little functions used to run collected tests.
 
48
;;; (f i) runs the ith collected optimized test
 
49
;;; (g i) runs the ith collected unoptimized test
 
50
;;; (p i) prints the ith test (forms, input values, and other information)
 
51
 
 
52
(defun f (i) (let ((plist (elt $y i)))
 
53
               (apply (compile nil (getf plist :optimized-lambda-form))
 
54
                      (getf plist :vals))))
 
55
 
 
56
(defun g (i) (let ((plist (elt $y i)))
 
57
               (if *compile-unoptimized-form*
 
58
                   (apply (compile nil (getf plist :unoptimized-lambda-form))
 
59
                          (getf plist :vals))
 
60
                 (apply (the function (eval `(function ,(getf plist :unoptimized-lambda-form))))
 
61
                        (getf plist :vals)))))
 
62
 
 
63
(defun p (i) (write (elt $y i) :pretty t :escape t) (values))
 
64
 
 
65
(defun load-failures (&key (pathname "failures.lsp"))
 
66
  (length (setq $y (with-open-file (s pathname :direction :input)
 
67
                                   (loop for x = (read s nil)
 
68
                                         while x collect x)))))
 
69
 
 
70
(defun tn (n &optional (size 100))
 
71
  (length (setq $y (prune-results (setq $x (test-random-integer-forms size 2 n))))))
 
72
 
 
73
(declaim (special *s1* *s2* *s3* *s4* *s5* *s6* *s7* *s8* *s9*))
 
74
 
 
75
(defparameter *loop-random-int-form-period* 2000)
 
76
 
 
77
;;; Run the random tester, collecting failures into the special
 
78
;;; variable $y.
 
79
 
 
80
(defun loop-random-int-forms (&optional (size 200) (nvars 3))
 
81
  (unless (boundp '$x) (setq $x nil))
 
82
  (unless (boundp '$y) (setq $y nil))
 
83
  (loop
 
84
   for i from 1
 
85
   do
 
86
   (format t "~6D | " i)
 
87
   (finish-output *standard-output*)
 
88
   (let ((x (test-random-integer-forms
 
89
             size nvars *loop-random-int-form-period*
 
90
             :index (* (1- i) *loop-random-int-form-period*))))
 
91
     (when x
 
92
       (setq $x (append $x x))
 
93
       (setq x (prune-results x))
 
94
       (terpri) (print x) (finish-output *standard-output*)
 
95
       (setq $y (append $y x)))
 
96
     (terpri))))
 
97
 
 
98
(defvar *random-int-form-blocks* nil)
 
99
(defvar *random-int-form-catch-tags* nil)
 
100
(defvar *go-tags* nil)
 
101
 
 
102
(defvar *maximum-random-int-bits* 45)
 
103
 
 
104
(defvar *random-vals-list-bound* 10)
 
105
 
 
106
(defvar *max-compile-time* 0)
 
107
(defvar *max-compile-term* nil)
 
108
 
 
109
(defvar *print-immediately* nil)
 
110
 
 
111
(defvar *compile-unoptimized-form*
 
112
  #+(or allegro sbcl) t
 
113
  #-(or allegro sbcl) nil)
 
114
 
 
115
(declaim (special *vars*))
 
116
 
 
117
(defstruct var-desc
 
118
  (name nil :type symbol)
 
119
  (type t))
 
120
 
 
121
(defun test-random-integer-forms
 
122
  (size nvars n
 
123
        &key ((:random-state *random-state*) (make-random-state t))
 
124
        (file-prefix "b")
 
125
        (index 0)
 
126
        (random-size nil)
 
127
        (random-nvars nil)
 
128
        )
 
129
 
 
130
  "Generate random integer forms of size SIZE with NVARS variables.
 
131
   Do this N times, returning all those on which a discrepancy
 
132
   is found between optimized and nonoptimize, notinlined code."
 
133
 
 
134
  (assert (integerp nvars))
 
135
  (assert (<= 1 nvars 26))
 
136
  (assert (and (integerp n) (plusp n)))
 
137
  (assert (and (integerp n) (plusp size)))
 
138
 
 
139
;;;  #+sbcl
 
140
;;;  (loop for x in (reverse sb-ext:*before-gc-hooks*)
 
141
;;;     do (pushnew x sb-ext:*after-gc-hooks*))
 
142
  
 
143
  (loop for i from 1 to n
 
144
        do (when (= (mod i 100) 0)
 
145
             ;; #+sbcl (print "Do gc...")
 
146
             ;; #+sbcl (sb-ext::gc :full t)
 
147
             (prin1 i) (princ " ") (finish-output *standard-output*))
 
148
        nconc (let ((result (test-random-integer-form
 
149
                             (if random-size (1+ (random size)) size)
 
150
                             (if random-nvars (1+ (random nvars)) nvars)
 
151
                             :index (+ index i)
 
152
                             :file-prefix file-prefix)))
 
153
                (when result
 
154
                  (let ((*print-readably* t))
 
155
                    (format t "~%~A~%" (format nil "~S" (car result)))
 
156
                    (finish-output *standard-output*)))
 
157
                result)))
 
158
 
 
159
(defun test-random-integer-form
 
160
  (size nvars &key (index 0) (file-prefix "b"))
 
161
  (let* ((vars (subseq '(a b c d e f g h i j k l m
 
162
                           n o p q r s u v w x y z) 0 nvars))
 
163
         (var-ranges (mapcar #'make-random-integer-range vars))
 
164
         (var-types (mapcar #'(lambda (range)
 
165
                                (let ((lo (car range))
 
166
                                      (hi (cadr range)))
 
167
                                  (assert (>= hi lo))
 
168
                                  `(integer ,lo ,hi)))
 
169
                            var-ranges))
 
170
         (form (let ((*vars* (loop for v in vars
 
171
                                   for tp in var-types
 
172
                                   collect (make-var-desc :name v
 
173
                                                          :type tp)))
 
174
                     (*random-int-form-blocks* nil)
 
175
                     (*random-int-form-catch-tags* nil)
 
176
                     (*go-tags* nil)
 
177
                     )
 
178
                 (make-random-integer-form (1+ (random size)))))
 
179
         (vals-list
 
180
          (loop repeat *random-vals-list-bound*
 
181
                collect
 
182
                (mapcar #'(lambda (range)
 
183
                            (let ((lo (car range))
 
184
                                  (hi (cadr range)))
 
185
                              (random-from-interval (1+ hi) lo)))
 
186
                        var-ranges)))
 
187
         (opt-decls-1 (make-random-optimize-settings))
 
188
         (opt-decls-2 (make-random-optimize-settings)))
 
189
    (when *print-immediately*
 
190
      (with-open-file
 
191
       (s (format nil "~A~A.lsp" file-prefix index)
 
192
          :direction :output :if-exists :error)
 
193
       (print `(defparameter *x*
 
194
                 '(:vars ,vars
 
195
                      :var-types ,var-types
 
196
                      :vals-list ,vals-list
 
197
                      :decls1 ,opt-decls-1
 
198
                      :decls2 ,opt-decls-2
 
199
                      :form ,form))
 
200
              s)
 
201
       (print '(load "c.lsp") s)
 
202
       (finish-output s))
 
203
       ;; (cl-user::gc)
 
204
       (make-list 1000000) ;; try to trigger a gc
 
205
      )
 
206
    (test-int-form form vars var-types vals-list opt-decls-1 opt-decls-2)))
 
207
 
 
208
(defun make-random-optimize-settings ()
 
209
  (loop for settings = (cons
 
210
                        (list 'speed (1+ (random 3)))
 
211
                        (loop for s in '(space safety debug compilation-speed)
 
212
                              for n = (random 4)
 
213
                              collect (list s n)))
 
214
        while
 
215
        #+allegro (subsetp '((speed 3) (safety 0)) settings :test 'equal)
 
216
        #-allegro nil
 
217
        finally (return settings)))
 
218
 
 
219
(defun fn-symbols-in-form (form)
 
220
  "Return a list of the distinct standardized lisp function
 
221
   symbols occuring ing FORM.  These are used to generate a NOTINLINE
 
222
   declaration for the unoptimized form."
 
223
  (intersection
 
224
   (remove-duplicates (fn-symbols-in-form* form) :test #'eq)
 
225
   *cl-function-or-accessor-symbols*))
 
226
 
 
227
(defun fn-symbols-in-form* (form)
 
228
  (when (consp form)
 
229
    (if (symbolp (car form))
 
230
        (cons (car form) (mapcan #'fn-symbols-in-form* (cdr form)))
 
231
      (mapcan #'fn-symbols-in-form* form))))
 
232
 
 
233
(defun make-random-integer-range (&optional var)
 
234
  "Generate a list (LO HI) of integers, LO <= HI.  This is used
 
235
   for generating integer types."
 
236
  (declare (ignore var))
 
237
  (rcase
 
238
   (1 (flet ((%r () (let ((r (ash 1 (1+ (random *maximum-random-int-bits*)))))
 
239
                      (- (random r) (floor (/ r 2))))))
 
240
        (let ((x (%r))
 
241
              (y (%r)))
 
242
          (list (min x y) (max x y)))))
 
243
   (1 (let* ((b (ash 1 (1+ (random *maximum-random-int-bits*))))
 
244
             (b2 (floor (/ b 2))))
 
245
        (let ((x (- (random b) b2))
 
246
              (y (- (random b) b2)))
 
247
          (list (min x y) (max x y)))))))
 
248
 
 
249
(defun fn-arg-name (fn-name arg-index)
 
250
  (intern (concatenate 'string
 
251
                       (subseq (symbol-name fn-name) 1)
 
252
                       (format nil "-~D" arg-index))
 
253
          (symbol-package fn-name)))                   
 
254
 
 
255
(declaim (special *flet-names*))
 
256
(defparameter *flet-names* nil)
 
257
 
 
258
(defun make-random-integer ()
 
259
  (let ((r (ash 1 (1+ (random 32)))))
 
260
    (- (random r) (floor (/ r 2)))))
 
261
 
 
262
(defun random-var-desc ()
 
263
  (loop
 
264
   (let* ((pos (random (length *vars*)))
 
265
          (desc (elt *vars* pos)))
 
266
     (when (= pos (position (var-desc-name desc) (the list *vars*)
 
267
                            :key #'var-desc-name))
 
268
       (return desc)))))
 
269
 
 
270
(defun is-zero-rank-integer-array-type (type)
 
271
  "This function was introduced because of a bug in ACL 6.2"
 
272
  ; (subtypep type '(array integer 0))
 
273
  (and (consp type)
 
274
       (eq (car type) 'array)
 
275
       (cddr type)
 
276
       (or (eq (cadr type) '*)
 
277
           (subtypep (cadr type) 'integer))
 
278
       (or (eql (caddr type) 0)
 
279
           (null (caddr type)))))
 
280
 
 
281
(defun make-random-integer-form (size)
 
282
  "Generate a random legal lisp form of size SIZE (roughly)."
 
283
  
 
284
  (if (<= size 1)
 
285
      ;; Leaf node -- generate a variable, constant, or flet function call
 
286
      (loop
 
287
       when
 
288
       (rcase
 
289
        (10 (make-random-integer))
 
290
        (9 (if *vars*
 
291
               (let* ((desc (random-var-desc))
 
292
                      (type (var-desc-type desc))
 
293
                      (name (var-desc-name desc)))
 
294
                 (cond
 
295
                  ((subtypep type 'integer) name)
 
296
                  (; (subtypep type '(array integer 0))
 
297
                   (is-zero-rank-integer-array-type type)
 
298
                   `(aref ,name))
 
299
                  ((subtypep type '(cons integer integer))
 
300
                   (rcase (1 `(car ,name))
 
301
                          (1 `(cdr ,name))))
 
302
                  (t nil)))
 
303
             nil))
 
304
        (1 (if *go-tags* `(go ,(random-from-seq *go-tags*)) nil))
 
305
        (2 (if *flet-names*
 
306
               (let* ((flet-entry (random-from-seq *flet-names*))
 
307
                      (flet-name (car flet-entry))
 
308
                      (flet-minargs (cadr flet-entry))
 
309
                      (flet-maxargs (caddr flet-entry))
 
310
                      (nargs (random-from-interval (1+ flet-maxargs) flet-minargs))
 
311
                      (args (loop repeat nargs
 
312
                                  collect (make-random-integer-form 1))))
 
313
                 `(,flet-name ,@args))
 
314
             nil)))
 
315
       return it)
 
316
    ;; (> size 1)
 
317
    (rcase
 
318
 
 
319
     ;; flet call
 
320
     #-(or armedbear)
 
321
     (30 ;; 5
 
322
      (make-random-integer-flet-call-form size))
 
323
 
 
324
     (5 (make-random-aref-form size))
 
325
 
 
326
     ;; Unary ops
 
327
     (40
 
328
      (let ((op (random-from-seq '(- abs signum 1+ 1- conjugate
 
329
                                     rational rationalize
 
330
                                     numerator denominator
 
331
                                     identity progn floor
 
332
                                     #-(or armedbear) ignore-errors
 
333
                                     cl:handler-case restart-case
 
334
                                     ceiling truncate round realpart imagpart
 
335
                                     integer-length logcount values
 
336
                                     locally))))
 
337
        `(,op ,(make-random-integer-form (1- size)))))
 
338
 
 
339
     #-(or armedbear)
 
340
     (4
 
341
      (make-random-integer-unwind-protect-form size))
 
342
 
 
343
     (5 (make-random-integer-mapping-form size))
 
344
 
 
345
     ;; prog1, multiple-value-prog1
 
346
     #-(or armedbear)
 
347
     (4
 
348
      (let* ((op (random-from-seq #(prog1 multiple-value-prog1)))
 
349
             (nforms (random 4))
 
350
             (sizes (random-partition (1- size) (1+ nforms)))
 
351
             (args (mapcar #'make-random-integer-form sizes)))
 
352
        `(,op ,@args)))
 
353
 
 
354
     ;; prog2
 
355
     (2 (let* ((nforms (random 4))
 
356
               (sizes (random-partition (1- size) (+ nforms 2)))
 
357
               (args (mapcar #'make-random-integer-form sizes)))
 
358
          `(prog2 ,@args)))
 
359
     
 
360
     (2 `(isqrt (abs ,(make-random-integer-form (- size 2)))))
 
361
 
 
362
     (2 `(the integer ,(make-random-integer-form (1- size))))
 
363
      
 
364
     (1 `(cl:handler-bind nil ,(make-random-integer-form (1- size))))
 
365
     (1 `(restart-bind nil ,(make-random-integer-form (1- size))))
 
366
     #-armedbear (1 `(macrolet () ,(make-random-integer-form (1- size))))
 
367
 
 
368
     ;; dotimes
 
369
     #-allegro
 
370
     (5
 
371
      (let* ((var (random-from-seq #(iv1 iv2 iv3 iv4)))
 
372
             (count (random 4))
 
373
             (sizes (random-partition (1- size) 2))
 
374
             (body (let ((*vars* (cons (make-var-desc :name var :type nil)
 
375
                                       *vars*)))
 
376
                     (make-random-integer-form (first sizes))))
 
377
             (ret-form (make-random-integer-form (second sizes))))
 
378
        (unless (consp body) (setq body `(progn ,body)))
 
379
        `(dotimes (,var ,count ,ret-form) ,body)))
 
380
 
 
381
     ;; loop
 
382
     (5 (make-random-loop-form (1- size)))
 
383
 
 
384
     (5 (make-random-count-form size))
 
385
 
 
386
     #-(or gcl ecl armedbear)
 
387
     ;; load-time-value
 
388
     (2
 
389
      (let ((arg (let ((*flet-names* nil)
 
390
                       (*vars* nil)
 
391
                       (*random-int-form-blocks* nil)
 
392
                       (*random-int-form-catch-tags* nil)
 
393
                       (*go-tags* nil))
 
394
                   (make-random-integer-form (1- size)))))
 
395
        (rcase
 
396
         (4 `(load-time-value ,arg t))
 
397
         (2 `(load-time-value ,arg))
 
398
         (2 `(load-time-value ,arg nil)))))
 
399
 
 
400
     ;; eval
 
401
     (2 (make-random-integer-eval-form size))
 
402
      
 
403
     #-(or cmu allegro)
 
404
     (2
 
405
      (destructuring-bind (s1 s2)
 
406
          (random-partition (- size 2) 2)
 
407
        `(ash ,(make-random-integer-form s1)
 
408
              (min ,(random 100)
 
409
                   ,(make-random-integer-form s2)))))
 
410
     
 
411
     ;; binary floor, ceiling, truncate, round
 
412
     (4
 
413
      (let ((op (random-from-seq #(floor ceiling truncate round mod rem)))
 
414
            (op2 (random-from-seq #(max min))))
 
415
        (destructuring-bind (s1 s2)
 
416
          (random-partition (- size 2) 2)
 
417
          `(,op  ,(make-random-integer-form s1)
 
418
                 (,op2  ,(if (eq op2 'max)
 
419
                             (1+ (random 100))
 
420
                           (- (1+ (random 100))))
 
421
                        ,(make-random-integer-form s2))))))
 
422
            
 
423
     ;; Binary op
 
424
     (30
 
425
      (let* ((op (random-from-seq
 
426
                  '(+ - *  logand min max gcd
 
427
                      lcm
 
428
                      #-:allegro
 
429
                      logandc1
 
430
                      logandc2 logeqv logior lognand lognor
 
431
                      #-:allegro
 
432
                      logorc1
 
433
                      logorc2
 
434
                      logxor
 
435
                      ))))
 
436
        (destructuring-bind (leftsize rightsize)
 
437
            (random-partition (1- size) 2)
 
438
          (let ((e1 (make-random-integer-form leftsize))
 
439
                (e2 (make-random-integer-form rightsize)))
 
440
            `(,op ,e1 ,e2)))))
 
441
 
 
442
     ;; boole
 
443
     (4
 
444
      (let* ((op (random-from-seq
 
445
                  #(boole-1 boole-2 boole-and boole-andc1 boole-andc2
 
446
                    boole-c1 boole-c2 boole-clr boole-eqv boole-ior boole-nand
 
447
                    boole-nor boole-orc1 boole-orc2 boole-set boole-xor))))
 
448
        (destructuring-bind (leftsize rightsize)
 
449
            (random-partition (- size 2) 2)
 
450
          (let ((e1 (make-random-integer-form leftsize))
 
451
                (e2 (make-random-integer-form rightsize)))
 
452
            `(boole ,op ,e1 ,e2)))))        
 
453
 
 
454
     ;; n-ary ops
 
455
     (30
 
456
      (let* ((op (random-from-seq #(+ - * logand min max logior
 
457
                                      values lcm gcd logxor)))
 
458
             (nargs (1+ (min (random 10) (random 10) (random 10))))
 
459
             (sizes (random-partition (1- size) nargs))
 
460
             (args (mapcar #'make-random-integer-form sizes)))
 
461
        `(,op ,@args)))
 
462
 
 
463
     ;; expt
 
464
     (3 `(expt ,(make-random-integer-form (1- size)) ,(random 3)))
 
465
 
 
466
     ;; coerce
 
467
     (2 `(coerce ,(make-random-integer-form (1- size)) 'integer))
 
468
     
 
469
     ;; complex (degenerate case)
 
470
     (2 `(complex ,(make-random-integer-form (1- size)) 0))
 
471
 
 
472
     ;; quotient (degenerate cases)
 
473
     (1 `(/ ,(make-random-integer-form (1- size)) 1))
 
474
     (1 `(/ ,(make-random-integer-form (1- size)) -1))
 
475
 
 
476
     ;; tagbody
 
477
     (5 (make-random-tagbody-and-progn size))
 
478
 
 
479
     ;; conditionals
 
480
     (20
 
481
      (let* ((cond-size (random (max 1 (floor size 2))))
 
482
             (then-size (random (- size cond-size)))
 
483
             (else-size (- size 1 cond-size then-size))
 
484
             (pred (make-random-pred-form cond-size))
 
485
             (then-part (make-random-integer-form then-size))
 
486
             (else-part (make-random-integer-form else-size)))
 
487
        `(if ,pred ,then-part ,else-part)))
 
488
     (5
 
489
      (destructuring-bind (s1 s2 s3) (random-partition (1- size) 3)
 
490
        `(,(random-from-seq '(deposit-field dpb))
 
491
          ,(make-random-integer-form s1)
 
492
          ,(make-random-byte-spec-form s2)
 
493
          ,(make-random-integer-form s3))))
 
494
 
 
495
     #-:allegro
 
496
     (10
 
497
      (destructuring-bind (s1 s2) (random-partition (1- size) 2)
 
498
          `(,(random-from-seq '(ldb mask-field))
 
499
            ,(make-random-byte-spec-form s1)
 
500
            ,(make-random-integer-form s2))))
 
501
 
 
502
     (20 (make-random-integer-binding-form size))
 
503
 
 
504
     ;; progv
 
505
     #-(or armedbear)
 
506
     (4 (make-random-integer-progv-form size))
 
507
     
 
508
     (4 `(let () ,(make-random-integer-form (1- size))))
 
509
 
 
510
     (10
 
511
      (let* ((name (random-from-seq #(b1 b2 b3 b4 b5 b6 b7 b8)))
 
512
             (*random-int-form-blocks* (adjoin name *random-int-form-blocks*)))
 
513
        `(block ,name ,(make-random-integer-form (1- size)))))
 
514
 
 
515
     (20
 
516
      (let* ((tag (list 'quote (random-from-seq #(ct1 ct2 ct2 ct4 ct5 ct6 ct7 ct8))))
 
517
             (*random-int-form-catch-tags* (cons tag *random-int-form-catch-tags*)))
 
518
        `(catch ,tag ,(make-random-integer-form (1- size)))))
 
519
     
 
520
     (4 ;; setq and similar
 
521
      (make-random-integer-setq-form size))
 
522
 
 
523
     (10 (make-random-integer-case-form size))
 
524
 
 
525
     (3
 
526
      (if *random-int-form-blocks*
 
527
          (let ((name (random-from-seq *random-int-form-blocks*))
 
528
                (form (make-random-integer-form (1- size))))
 
529
            `(return-from ,name ,form))
 
530
        ;; No blocks -- try again
 
531
        (make-random-integer-form size)))
 
532
 
 
533
     (20
 
534
      (if *random-int-form-catch-tags*
 
535
          (let ((tag (random-from-seq *random-int-form-catch-tags*))
 
536
                (form (make-random-integer-form (1- size))))
 
537
            `(throw ,tag ,form))
 
538
        ;; No catch tags -- try again
 
539
        (make-random-integer-form size)))
 
540
 
 
541
     (5
 
542
      (if *random-int-form-blocks*
 
543
          (destructuring-bind (s1 s2 s3) (random-partition (1- size) 3)
 
544
            (let ((name (random-from-seq *random-int-form-blocks*))
 
545
                  (pred (make-random-pred-form s1))
 
546
                  (then (make-random-integer-form s2))
 
547
                  (else (make-random-integer-form s3)))
 
548
              `(if ,pred (return-from ,name ,then) ,else)))
 
549
        ;; No blocks -- try again
 
550
        (make-random-integer-form size)))
 
551
 
 
552
     #-(or armedbear)
 
553
     (20
 
554
      (make-random-flet-form size))
 
555
 
 
556
     (2
 
557
      (let* ((nbits (1+ (min (random 20) (random 20))))
 
558
             (bvec (coerce (loop repeat nbits collect (random 2)) 'simple-bit-vector))
 
559
             (op (random-from-seq #(bit sbit))))
 
560
        `(,op ,bvec (min ,(1- nbits) (max 0 ,(make-random-integer-form (- size 3 nbits)))))))
 
561
 
 
562
     (2
 
563
      (let* ((nvals (1+ (min (random 20) (random 20))))
 
564
             (lim (ash 1 (+ 3 (random 40))))
 
565
             (vec (coerce (loop repeat nvals collect (random lim)) 'simple-vector))
 
566
             (op (random-from-seq #(aref svref elt))))
 
567
        `(,op ,vec (min ,(1- nvals) (max 0 ,(make-random-integer-form (- size 3 nvals)))))))
 
568
 
 
569
     (2
 
570
      (let* ((nvals (1+ (min (random 20) (random 20))))
 
571
             (lim (ash 1 (+ 3 (random 40))))
 
572
             (vals (loop repeat nvals collect (random lim)))
 
573
             (op 'elt))
 
574
        `(,op ',vals (min ,(1- nvals) (max 0 ,(make-random-integer-form (- size 3 nvals)))))))
 
575
 
 
576
     )))
 
577
 
 
578
(defun make-random-aref-form (size)
 
579
  (or
 
580
   (when *vars*
 
581
     (let* ((desc (random-var-desc))
 
582
            (type (var-desc-type desc))
 
583
            (name (var-desc-name desc)))
 
584
       (cond
 
585
        ((null type) nil)
 
586
        ((subtypep type '(array integer (*)))
 
587
         `(aref ,name (min ,(1- (first (third type)))
 
588
                           (max 0 ,(make-random-integer-form (- size 2))))))
 
589
        ((subtypep type '(array integer (* *)))
 
590
         (destructuring-bind (s1 s2) (random-partition (max 2 (- size 2)) 2)
 
591
           `(aref ,name
 
592
                  (min ,(1- (first (third type)))
 
593
                       (max 0 ,(make-random-integer-form s1)))
 
594
                  (min ,(1- (second (third type)))
 
595
                       (max 0 ,(make-random-integer-form s2))))))
 
596
        (t nil))))
 
597
   (make-random-integer-form size)))
 
598
 
 
599
(defun make-random-count-form (size)
 
600
  (destructuring-bind (s1 s2)
 
601
      (random-partition (1- size) 2)
 
602
    (let ((arg1 (make-random-integer-form s1))
 
603
          (arg2-args (loop repeat s2 collect (make-random-integer))))
 
604
      (let ((op 'count)
 
605
            (test (random-from-seq #(eql = /= < > <= >=)))
 
606
            (arg2 (rcase
 
607
                   (1 (make-array (list s2) :initial-contents arg2-args))
 
608
                   (1
 
609
                    (let* ((mask (1- (ash 1 (1+ (random 32))))))
 
610
                      (make-array (list s2)
 
611
                                  :initial-contents
 
612
                                  (mapcar #'(lambda (x) (logand x mask)) arg2-args)
 
613
                                  :element-type `(integer 0 ,mask))))
 
614
                   (1 `(quote ,arg2-args)))))
 
615
        `(,op ,arg1 ,arg2 ,@(rcase
 
616
                                    (2 nil)
 
617
                                    (1 (list :test `(quote ,test)))
 
618
                                    (1 (list :test-not `(quote ,test)))))))))
 
619
 
 
620
(defun make-random-integer-flet-call-form (size)
 
621
  (if *flet-names*
 
622
      (let* ((flet-entry (random-from-seq *flet-names*))
 
623
             (flet-name (car flet-entry))
 
624
             (flet-minargs (cadr flet-entry))
 
625
             (flet-maxargs (caddr flet-entry))
 
626
             (nargs (random-from-interval (1+ flet-maxargs) flet-minargs))
 
627
             )
 
628
        (cond
 
629
         ((> nargs 0)
 
630
          (let* ((arg-sizes (random-partition (1- size) nargs))
 
631
                 (args (mapcar #'make-random-integer-form arg-sizes)))
 
632
            (rcase
 
633
             (1 `(,flet-name ,@args))
 
634
             (1 `(multiple-value-call #',flet-name (values ,@args)))
 
635
             (1 `(funcall (function ,flet-name) ,@args))
 
636
             (1 (let ((r (random (1+ (length args)))))
 
637
                  `(apply (function ,flet-name)
 
638
                          ,@(subseq args 0 r)
 
639
                          (list ,@(subseq args r))))))))
 
640
         (t (make-random-integer-form size))))
 
641
    (make-random-integer-form size)))
 
642
 
 
643
(defun make-random-integer-unwind-protect-form (size)
 
644
  (let* ((op 'unwind-protect)
 
645
         (nforms (random 4))
 
646
         (sizes (random-partition (1- size) (1+ nforms)))
 
647
         (arg (make-random-integer-form (first sizes)))
 
648
         (unwind-forms
 
649
          ;; We have to be careful not to generate code that will
 
650
          ;; illegally transfer control to a dead location
 
651
          (let ((*flet-names* nil)
 
652
                (*go-tags* nil)
 
653
                (*random-int-form-blocks* nil)
 
654
                (*random-int-form-catch-tags* nil))
 
655
            (mapcar #'make-random-integer-form (rest sizes)))))
 
656
    `(,op ,arg ,@unwind-forms)))
 
657
 
 
658
(defun make-random-integer-eval-form (size)
 
659
  (flet ((%arg (size)
 
660
               (let ((*flet-names* nil)
 
661
                     (*vars* (remove-if-not #'(lambda (s)
 
662
                                                (member (var-desc-name s)
 
663
                                                        '(*s1* *s2* *s3* *s4* *s5*
 
664
                                                               *s6* *s7* *s8* *s9*)
 
665
                                                        :test #'eq))
 
666
                                            *vars*))
 
667
                     (*random-int-form-blocks* nil)
 
668
                     (*go-tags* nil))
 
669
                 (make-random-integer-form size))))
 
670
    (rcase
 
671
     (2 `(eval ',(%arg (1- size))))
 
672
     (2 (let* ((nargs (1+ (random 4)))
 
673
               (sizes (random-partition (1- size) nargs))
 
674
               (args (mapcar #'%arg sizes)))
 
675
          `(eval (values ,@args))))
 
676
     )))
 
677
 
 
678
(defun make-random-type-for-var (var e1)
 
679
  (let (desc)
 
680
    (values
 
681
     (cond
 
682
      ((and (member var '(*s1* *s2* *s3* *s4* *s5* *s6* *s7* *s8*) :test #'eq)
 
683
            (setq desc (find var *vars* :key #'var-desc-name)))
 
684
       (var-desc-type desc))
 
685
      (t (rcase
 
686
          (4 '(integer * *))
 
687
          (1 (setq e1 `(make-array nil :initial-element ,e1
 
688
                                   ,@(rcase (1 nil) (1 '(:adjustable t)))))
 
689
             '(array integer nil))
 
690
          (1 (let ((size (1+ (random 10))))
 
691
               (setq e1 `(make-array '(,size):initial-element ,e1
 
692
                                     ,@(rcase (1 nil) (1 '(:adjustable t)))))
 
693
               `(array integer (,size))))
 
694
          #|
 
695
          (1 (let ((size1 (1+ (random 10)))
 
696
                   (size2 (1+ (random 10))))
 
697
               (setq e1 `(make-array '(,size1 ,size2):initial-element ,e1
 
698
                                     ,@(rcase (1 nil) (1 '(:adjustable t)))))
 
699
               `(array integer (,size1 ,size2))))
 
700
          |#
 
701
          (1 (setq e1 `(cons ,e1 ,(make-random-integer-form 1)))
 
702
             '(cons integer integer))
 
703
          (1 (setq e1 `(cons ,(make-random-integer-form 1) ,e1))
 
704
             '(cons integer integer)))))
 
705
     e1)))
 
706
 
 
707
(defun make-random-integer-binding-form (size)
 
708
  (destructuring-bind (s1 s2) (random-partition (1- size) 2)
 
709
    (let* ((var (rcase
 
710
                 (2 (random-from-seq #(v1 v2 v3 v4 v5 v6 v7 v8 v9 v10)))
 
711
                 (2 (random-from-seq #(*s1* *s2* *s3* *s4* *s5* *s6* *s7* *s8*)))))
 
712
           (e1 (make-random-integer-form s1))
 
713
           (type (multiple-value-bind (type2 e)
 
714
                     (make-random-type-for-var var e1)
 
715
                   (setq e1 e)
 
716
                   type2))
 
717
           (e2 (let ((*vars* (cons (make-var-desc :name var :type type)
 
718
                                   *vars*)))
 
719
                 (make-random-integer-form s2)))
 
720
           (op (random-from-seq #(let let*))))
 
721
      ;; for now, avoid shadowing
 
722
      (if (member var *vars* :key #'var-desc-name)
 
723
          (make-random-integer-form size)
 
724
        (rcase
 
725
         (8 `(,op ((,var ,e1))
 
726
                  ,@(rcase (1 `((declare (dynamic-extent ,var))))
 
727
                           (1 nil))
 
728
                  ,e2))
 
729
         (2 `(multiple-value-bind (,var) ,e1 ,e2)))))))
 
730
 
 
731
(defun make-random-integer-progv-form (size)
 
732
  (let* ((num-vars (random 4))
 
733
         (possible-vars #(*s1* *s2* *s3* *s4* *s5* *s6* *s7* *s8*))
 
734
         (vars nil))
 
735
    (loop repeat num-vars
 
736
          do (loop for r = (elt possible-vars (random (length possible-vars)))
 
737
                   while (member r vars)
 
738
                   finally (push r vars)))
 
739
    (setq vars (remove-if #'(lambda (var) (let ((desc (find var *vars* :key #'var-desc-name)))
 
740
                                            (and desc (not (subtypep (var-desc-type desc) 'integer)))))
 
741
                          vars)
 
742
          num-vars (length vars))
 
743
    (if (null vars)
 
744
        `(progv nil nil ,(make-random-integer-form (1- size)))
 
745
      (destructuring-bind (s1 s2) (random-partition (1- size) 2)
 
746
        (let* ((var-sizes (random-partition s1 num-vars))
 
747
               (var-forms (mapcar #'make-random-integer-form var-sizes))
 
748
               (*vars* (append (loop for v in vars collect
 
749
                                     (make-var-desc :name v :type '(integer * *)))
 
750
                               *vars*))
 
751
               (body-form (make-random-integer-form s2)))
 
752
          `(progv ',vars (list ,@var-forms) ,body-form))))))
 
753
 
 
754
(defun make-random-integer-mapping-form (size)
 
755
  ;; reduce
 
756
  (let ((keyargs nil)
 
757
        (nargs (1+ (random (min 10 (max 1 size)))))
 
758
        (sequence-op (random-from-seq '(vector list))))
 
759
    (when (coin 2) (setq keyargs '(:from-end t)))
 
760
    (cond
 
761
     ((coin 2)
 
762
      (let ((start (random nargs)))
 
763
        (setq keyargs `(:start ,start ,@keyargs))
 
764
        (when (coin 2)
 
765
          (let ((end (+ start 1 (random (- nargs start)))))
 
766
            (setq keyargs `(:end ,end ,@keyargs))))))
 
767
     (t
 
768
      (when (coin 2)
 
769
        (let ((end (1+ (random nargs))))
 
770
          (setq keyargs `(:end ,end ,@keyargs))))))
 
771
    (rcase
 
772
     (1
 
773
      (let ((sizes (random-partition (1- size) nargs))
 
774
            (op (random-from-seq #(+ - * logand logxor logior max min))))
 
775
        `(reduce ,(rcase (1 `(function ,op))
 
776
                         (1 `(quote ,op)))
 
777
                 (,sequence-op
 
778
                  ,@(mapcar #'make-random-integer-form sizes))
 
779
                 ,@keyargs)))
 
780
     #-(or armedbear)
 
781
     (1
 
782
      (destructuring-bind (size1 size2) (random-partition (1- size) 2)
 
783
        (let* ((vars '(lmv1 lmv2 lmv3 lmv4 lmv5 lmv6))
 
784
               (var1 (random-from-seq vars))
 
785
               (var2 (random-from-seq (remove var1 vars)))
 
786
               (form (let ((*vars* (list*
 
787
                                    (make-var-desc :name var1 :type '(integer * *))
 
788
                                    (make-var-desc :name var2 :type '(integer * *))
 
789
                                    *vars*)))
 
790
                       (make-random-integer-form size1)))
 
791
               (sizes (random-partition size2 nargs))
 
792
               (args (mapcar #'make-random-integer-form sizes)))
 
793
          `(reduce (function (lambda (,var1 ,var2) ,form))
 
794
                   (,sequence-op ,@args)
 
795
                   ,@keyargs)))))))
 
796
 
 
797
(defun make-random-integer-setq-form (size)
 
798
  (if *vars*
 
799
      (let* ((vdesc (random-from-seq *vars*))
 
800
             (var (var-desc-name vdesc))
 
801
             (type (var-desc-type vdesc))
 
802
             (op (random-from-seq #(setq setf shiftf))))
 
803
        (cond
 
804
         ((subtypep '(integer * *) type)
 
805
          (assert (not (member var '(lv1 lv2 lv3 lv4 lv5 lv6 lv7 lv8))))
 
806
          (rcase
 
807
           (1 (when (member var '(*s1* *s2* *s3* *s4* *s5* *s6* *s7* *s8* *s9*))
 
808
                (setq op (random-from-seq #(setf shiftf))
 
809
                      var `(symbol-value ',var))))
 
810
           (1 (setq op 'multiple-value-setq)
 
811
              (setq var (list var)))
 
812
           (5 nil))
 
813
          `(,op ,var ,(make-random-integer-form (1- size))))
 
814
         ((and (consp type)
 
815
               (eq (car type) 'integer)
 
816
               (integerp (second type))
 
817
               (integerp (third type)))
 
818
          (assert (not (member var '(lv1 lv2 lv3 lv4 lv5 lv6 lv7 lv8))))
 
819
          (rcase
 
820
           (1 (when (member var '(*s1* *s2* *s3* *s4* *s5* *s6* *s7* *s8* *s9*))
 
821
                (setq op (random-from-seq #(setf shiftf))
 
822
                      var `(symbol-value ',var))))
 
823
           (1 (setq op 'multiple-value-setq)
 
824
              (setq var (list var)))
 
825
           (5 nil))
 
826
          `(,op ,var ,(random-from-interval (1+ (third type)) (second type))))
 
827
         ((and type (is-zero-rank-integer-array-type type)) ; (subtypep type '(array integer nil))
 
828
          (assert (not (member var '(lv1 lv2 lv3 lv4 lv5 lv6 lv7 lv8))))
 
829
          (when (eq op 'setq)
 
830
            (setq op (random-from-seq #(setf shiftf))))
 
831
          `(,op (aref ,var) ,(make-random-integer-form (- size 2))))
 
832
         ((and type (subtypep type '(array integer (*))))
 
833
          (when (eq op 'setq)
 
834
            (setq op (random-from-seq #(setf shiftf))))
 
835
          (destructuring-bind (s1 s2) (random-partition (max 2 (- size 2)) 2)
 
836
            `(,op (aref ,var (min ,(1- (first (third type)))
 
837
                                  (max 0
 
838
                                       ,(make-random-integer-form s1))))
 
839
                  ,(make-random-integer-form s2))))
 
840
         ((and type (subtypep type '(array integer (* *))))
 
841
          (when (eq op 'setq)
 
842
            (setq op (random-from-seq #(setf shiftf))))
 
843
          (destructuring-bind (s1 s2 s3) (random-partition (max 3 (- size 3)) 3)
 
844
            `(,op (aref ,var
 
845
                        (min ,(1- (first (third type)))
 
846
                             (max 0
 
847
                                  ,(make-random-integer-form s1)))
 
848
                        (min ,(1- (second (third type)))
 
849
                             (max 0
 
850
                                  ,(make-random-integer-form s2))))
 
851
                  ,(make-random-integer-form s3))))
 
852
         ;; Abort -- can't assign
 
853
         (t (make-random-integer-form size))))
 
854
    (make-random-integer-form size)))
 
855
 
 
856
 
 
857
(defun make-random-integer-case-form (size)
 
858
  (let ((ncases (1+ (random 10))))
 
859
    (if (< (+ size size) (+ ncases 2))
 
860
        ;; Too small, give up
 
861
        (make-random-integer-form size)
 
862
      (let* ((sizes (random-partition (1- size) (+ ncases 2)))
 
863
             (bound (ash 1 (+ 2 (random 16))))
 
864
             (lower-bound (if (coin 3) 0 (- bound)))
 
865
             (upper-bound (if (and (< lower-bound 0) (coin 3))
 
866
                              1
 
867
                            (1+ bound)))
 
868
             (cases
 
869
              (loop
 
870
               for case-size in (cddr sizes)
 
871
               for vals = (loop repeat (1+ (min (random 10) (random 10)))
 
872
                                collect (random-from-interval
 
873
                                         upper-bound lower-bound))
 
874
               for result = (make-random-integer-form case-size)
 
875
               repeat ncases
 
876
               collect `(,vals ,result)))
 
877
             (expr (make-random-integer-form (first sizes))))
 
878
        `(case ,expr
 
879
           ,@cases
 
880
           (t ,(make-random-integer-form (second sizes))))))))
 
881
 
 
882
(defun make-random-flet-form (size)
 
883
  "Generate random flet, labels forms, for now with no arguments
 
884
   and a single binding per form."
 
885
  (let ((fname (random-from-seq #(%f1 %f2 %f3 %f4 %f5 %f6 %f7 %f8 %f9 %f10
 
886
                                  %f11 %f12 %f13 %f14 %f15 %f16 %f17 %f18))))
 
887
    (if (assoc fname *flet-names*)
 
888
        ;; Fail if the name is in use
 
889
        (make-random-integer-form size)
 
890
      (let* ((op (random-from-seq #(flet labels)))
 
891
             (minargs (random 4))
 
892
             (maxargs #+:allegro minargs
 
893
                      #-:allegro
 
894
                      (rcase
 
895
                       (1 minargs)
 
896
                       (1 (+ minargs (random 4)))))
 
897
             (keyarg-p (coin 2))
 
898
             (keyarg-n (if keyarg-p (random 3) 0))
 
899
             (arg-names (loop for i from 1 to maxargs
 
900
                              collect (fn-arg-name fname i)))
 
901
             (key-arg-names (loop for i from 1 to keyarg-n
 
902
                                  collect (intern (format nil "KEY~A" i)
 
903
                                                  (find-package "CL-TEST"))))
 
904
             (allow-other-keys (and keyarg-p (coin 3)))
 
905
             )
 
906
        (destructuring-bind (s1 s2 . opt-sizes)
 
907
            (random-partition (1- size) (+ 2 keyarg-n (- maxargs minargs)))
 
908
          (let* ((form1
 
909
                  ;; Allow return-from of the flet/labels function
 
910
                  (let ((*random-int-form-blocks*
 
911
                         (cons fname *random-int-form-blocks*))
 
912
                        (*vars* (nconc (loop for var in (append arg-names key-arg-names)
 
913
                                             collect (make-var-desc :name var
 
914
                                                                    :type '(integer * *)))
 
915
                                       *vars*)))
 
916
                    (make-random-integer-form s1)))
 
917
                 (form2 (let ((*flet-names* (cons (list fname minargs maxargs keyarg-p)
 
918
                                                  *flet-names*)))
 
919
                          (make-random-integer-form s2)))
 
920
                 (opt-forms (mapcar #'make-random-integer-form opt-sizes)))
 
921
            (if opt-forms
 
922
                `(,op ((,fname (,@(subseq arg-names 0 minargs)
 
923
                                  &optional
 
924
                                  ,@(mapcar #'list
 
925
                                            (subseq arg-names minargs)
 
926
                                            opt-forms)
 
927
                                  ,@(when keyarg-p
 
928
                                      (append '(&key)
 
929
                                              (mapcar #'list
 
930
                                                      key-arg-names
 
931
                                                      (subseq opt-forms (- maxargs minargs)))
 
932
                                              (when allow-other-keys '(&allow-other-keys))
 
933
                                              )))
 
934
                               ,form1))
 
935
                      ,form2)
 
936
              `(,op ((,fname (,@arg-names
 
937
                              ,@(when keyarg-p
 
938
                                  (append '(&key)
 
939
                                          (mapcar #'list
 
940
                                                  key-arg-names
 
941
                                                  opt-forms )
 
942
                                          (when allow-other-keys '(&allow-other-keys))
 
943
                                          )))
 
944
                             ,form1))
 
945
                    ,form2))))))))
 
946
 
 
947
(defun make-random-tagbody (size)
 
948
  (let* ((num-forms (random 6))
 
949
         (tags nil))
 
950
    (loop for i below num-forms
 
951
          do (loop for tag = (rcase
 
952
                              #-allegro (1 (random 8))
 
953
                              (1 (random-from-seq #(tag1 tag2 tag3 tag4
 
954
                                                         tag5 tag6 tag7 tag8))))
 
955
                   while (member tag tags)
 
956
                   finally (push tag tags)))
 
957
    (assert (= (length (remove-duplicates tags)) (length tags)))
 
958
    (let* ((*go-tags* (set-difference *go-tags* tags))
 
959
           (sizes (if (> num-forms 0) (random-partition (1- size) num-forms) nil))
 
960
           (forms
 
961
            (loop for tag-list on tags
 
962
                  for i below num-forms
 
963
                  for size in sizes
 
964
                  collect (let ((*go-tags* (append tag-list *go-tags*)))
 
965
                            (make-random-integer-form size)))))
 
966
      `(tagbody ,@(loop for tag in tags
 
967
                        for form in forms
 
968
                        when (atom form) do (setq form `(progn ,form))
 
969
                        append `(,form ,tag))))))
 
970
 
 
971
(defun make-random-tagbody-and-progn (size)
 
972
  (let* ((final-size (random (max 1 (floor size 5))))
 
973
         (tagbody-size (- size final-size)))
 
974
    (let ((final-form (make-random-integer-form final-size))
 
975
          (tagbody-form (make-random-tagbody tagbody-size)))
 
976
      `(progn ,tagbody-form ,final-form))))
 
977
 
 
978
(defun make-random-pred-form (size)
 
979
  "Make a random form whose value is to be used as a generalized boolean."
 
980
  (if (<= size 1)
 
981
      (rcase
 
982
        (1 (if (coin) t nil))
 
983
        (2
 
984
         `(,(random-from-seq '(< <= = > >= /= eql equal))
 
985
           ,(make-random-integer-form size)
 
986
           ,(make-random-integer-form size))))
 
987
    (rcase
 
988
      (1 (if (coin) t nil))
 
989
      (3 `(not ,(make-random-pred-form (1- size))))
 
990
      (6 (destructuring-bind (leftsize rightsize)
 
991
             (random-partition (1- size) 2)
 
992
           `(,(random-from-seq '(and or))
 
993
             ,(make-random-pred-form leftsize)
 
994
             ,(make-random-pred-form rightsize))))
 
995
      (1 (destructuring-bind (leftsize rightsize)
 
996
             (random-partition (1- size) 2)
 
997
           `(,(random-from-seq '(< <= > >= = /= eql equal))
 
998
             ,(make-random-integer-form leftsize)
 
999
             ,(make-random-integer-form rightsize))))
 
1000
      (3 (let* ((cond-size (random (max 1 (floor size 2))))
 
1001
                (then-size (random (- size cond-size)))
 
1002
                (else-size (- size 1 cond-size then-size))
 
1003
                (pred (make-random-pred-form cond-size))
 
1004
                (then-part (make-random-pred-form then-size))
 
1005
                (else-part (make-random-pred-form else-size)))
 
1006
           `(if ,pred ,then-part ,else-part)))
 
1007
      (1 (destructuring-bind (s1 s2)
 
1008
             (random-partition (1- size) 2)
 
1009
           `(ldb-test ,(make-random-byte-spec-form s1)
 
1010
                      ,(make-random-integer-form s2))))
 
1011
 
 
1012
      (2 (destructuring-bind (s1 s2)
 
1013
             (random-partition (1- size) 2)
 
1014
           (let ((arg1 (make-random-integer-form s1))
 
1015
                 (arg2-args (loop repeat s2 collect (make-random-integer))))
 
1016
             (let ((op (random-from-seq #(find position)))
 
1017
                   (test (random-from-seq #(eql = /= < > <= >=)))
 
1018
                   (arg2 (rcase
 
1019
                          (1 (make-array (list s2) :initial-contents arg2-args))
 
1020
                          (1
 
1021
                           (let* ((mask (1- (ash 1 (1+ (random 32))))))
 
1022
                             (make-array (list s2)
 
1023
                                         :initial-contents
 
1024
                                         (mapcar #'(lambda (x) (logand x mask)) arg2-args)
 
1025
                                        :element-type `(integer 0 ,mask))))
 
1026
                          (1 `(quote ,arg2-args)))))
 
1027
               `(,op ,arg1 ,arg2 ,@(rcase
 
1028
                                    (2 nil)
 
1029
                                    (1 (list :test `(quote ,test)))
 
1030
                                    (1 (list :test-not `(quote ,test)))))))))
 
1031
      
 
1032
      (1 (let ((index (random (1+ (random *maximum-random-int-bits*))))
 
1033
               (form (make-random-integer-form (1- size))))
 
1034
           `(logbitp ,index ,form)))
 
1035
      (1 ;; typep form
 
1036
       (let ((subform (make-random-integer-form (- size 2)))
 
1037
             (type
 
1038
              (rcase
 
1039
               (1 `(integer ,@(make-random-integer-range)))
 
1040
               (1 `(integer ,(make-random-integer)))
 
1041
               (1 `(integer * ,(make-random-integer)))
 
1042
               (1 `(integer)))))
 
1043
         `(typep ,subform ',type)))
 
1044
      )))
 
1045
 
 
1046
(defun make-random-loop-form (size)
 
1047
  (if (<= size 2)
 
1048
      (make-random-integer-form size)
 
1049
    (let* ((var (random-from-seq #(lv1 lv2 lv3 lv4)))
 
1050
           (count (random 4))
 
1051
           (*vars* (cons (make-var-desc :name var :type nil)
 
1052
                         *vars*)))
 
1053
      (rcase
 
1054
       (1 `(loop for ,var below ,count count ,(make-random-pred-form (- size 2))))
 
1055
       (1 `(loop for ,var below ,count sum ,(make-random-integer-form (- size 2))))
 
1056
       ))))
 
1057
 
 
1058
(defun make-random-byte-spec-form (size)
 
1059
  (declare (ignore size))
 
1060
  (let* ((pform (random 33))
 
1061
         (sform (1+ (random 33))))
 
1062
    `(byte ,sform ,pform)))
 
1063
 
 
1064
(defun make-random-element-of-type (type)
 
1065
  "Create a random element of a lisp type."
 
1066
  (cond
 
1067
   ((consp type)
 
1068
    (let ((type-op (first type)))
 
1069
      (ecase type-op
 
1070
        (integer
 
1071
         (let ((lo (let ((lo (cadr type)))
 
1072
                     (cond
 
1073
                      ((consp lo) (1+ (car lo)))
 
1074
                      ((eq lo nil) '*)
 
1075
                      (t lo))))
 
1076
               (hi (let ((hi (caddr type)))
 
1077
                     (cond
 
1078
                      ((consp hi) (1- (car hi)))
 
1079
                      ((eq hi nil) '*)
 
1080
                      (t hi)))))
 
1081
         (if (eq lo '*)
 
1082
             (if (eq hi '*)
 
1083
                 (let ((x (ash 1 (random *maximum-random-int-bits*))))
 
1084
                   (random-from-interval x (- x)))
 
1085
               (random-from-interval (1+ hi)
 
1086
                                     (- hi (random (ash 1 *maximum-random-int-bits*)))))
 
1087
 
 
1088
           (if (eq hi '*)
 
1089
               (random-from-interval (+ lo (random (ash 1 *maximum-random-int-bits*)) 1)
 
1090
                                     lo)
 
1091
             ;; May generalize the next case to increase odds
 
1092
             ;; of certain integers (near 0, near endpoints, near
 
1093
             ;; powers of 2...)
 
1094
             (random-from-interval (1+ hi) lo)))))
 
1095
        (mod
 
1096
         (let ((modulus (second type)))
 
1097
           (assert (and (integerp modulus)
 
1098
                        (plusp modulus)))
 
1099
           (make-random-element-of-type `(integer 0 (,modulus)))))
 
1100
        (unsigned-byte
 
1101
         (if (null (cdr type))
 
1102
           (make-random-element-of-type '(integer 0 *))
 
1103
           (let ((bits (second type)))
 
1104
             (if (eq bits'*)
 
1105
                 (make-random-element-of-type '(integer 0 *))
 
1106
               (progn
 
1107
                 (assert (and (integerp bits) (>= bits 1)))
 
1108
                 (make-random-element-of-type
 
1109
                  `(integer 0 ,(1- (ash 1 bits)))))))))
 
1110
        )))
 
1111
   (t
 
1112
    (ecase type
 
1113
      (bit (random 2))
 
1114
      (boolean (random-from-seq #(nil t)))
 
1115
      (symbol (random-from-seq #(nil t a b c :a :b :c |z| foo |foo| cl:car)))
 
1116
      (unsigned-byte (random-from-interval
 
1117
                      (1+ (ash 1 (random *maximum-random-int-bits*))) 0))
 
1118
      (integer (let ((x (ash 1 (random *maximum-random-int-bits*))))
 
1119
                 (random-from-interval (1+ x) (- x))))
 
1120
      ))))
 
1121
 
 
1122
(defun make-optimized-lambda-form (form vars var-types opt-decls)
 
1123
  `(lambda ,vars
 
1124
     ,@(mapcar #'(lambda (tp var) `(declare (type ,tp ,var)))
 
1125
               var-types vars)
 
1126
     (declare (ignorable ,@vars))
 
1127
     #+cmu (declare (optimize (extensions:inhibit-warnings 3)))
 
1128
     (declare (optimize ,@opt-decls))
 
1129
     ,form))
 
1130
 
 
1131
(defun make-unoptimized-lambda-form (form vars var-types opt-decls)
 
1132
  (declare (ignore var-types))
 
1133
  `(lambda ,vars
 
1134
     (declare (notinline ,@(fn-symbols-in-form form)))
 
1135
     #+cmu (declare (optimize (extensions:inhibit-warnings 3)))
 
1136
     (declare (optimize ,@opt-decls))
 
1137
     ,form))
 
1138
 
 
1139
(defvar *compile-using-defun*
 
1140
  #-(or allegro lispworks) nil
 
1141
  #+(or allegro lispworks) t)
 
1142
(defvar *name-to-use-in-optimized-defun* 'dummy-fn-name1)
 
1143
(defvar *name-to-use-in-unoptimized-defun* 'dummy-fn-name2)
 
1144
 
 
1145
(defun test-int-form (form vars var-types vals-list opt-decls-1 opt-decls-2)
 
1146
  ;; Try to compile FORM with associated VARS, and if it compiles
 
1147
  ;; check for equality of the two compiled forms.
 
1148
  ;; Return a non-nil list of details if a problem is found,
 
1149
  ;; NIL otherwise.
 
1150
  (let ((optimized-fn-src (make-optimized-lambda-form form vars var-types opt-decls-1))
 
1151
        (unoptimized-fn-src (make-unoptimized-lambda-form form vars var-types opt-decls-2)))
 
1152
    (setq *int-form-vals* nil
 
1153
          *optimized-fn-src* optimized-fn-src
 
1154
          *unoptimized-fn-src* unoptimized-fn-src)
 
1155
    (flet ((%compile
 
1156
            (lambda-form opt-defun-name)
 
1157
            (cl:handler-bind
 
1158
             (#+sbcl (sb-ext::compiler-note #'muffle-warning)
 
1159
                     (warning #'muffle-warning)
 
1160
                     (error #'(lambda (c)
 
1161
                                (format t "Compilation failure~%~A~%"
 
1162
                                        (format nil "~S" form))
 
1163
                                (finish-output *standard-output*)
 
1164
                                (return-from test-int-form
 
1165
                                  (list (list :vars vars
 
1166
                                              :form form
 
1167
                                              :var-types var-types
 
1168
                                              :vals (first vals-list)
 
1169
                                              :lambda-form lambda-form
 
1170
                                              :decls1 opt-decls-1
 
1171
                                              :decls2 opt-decls-2
 
1172
                                              :compiler-condition
 
1173
                                              (with-output-to-string
 
1174
                                                (s)
 
1175
                                                (prin1 c s))))))))
 
1176
             (let ((start-time (get-universal-time)))
 
1177
               (prog1
 
1178
                   (if *compile-using-defun*
 
1179
                       (progn
 
1180
                         (eval `(defun ,opt-defun-name
 
1181
                                  ,@(cdr lambda-form)))
 
1182
                         (compile opt-defun-name)
 
1183
                         (symbol-function opt-defun-name))
 
1184
                     (compile nil lambda-form))
 
1185
                 (let* ((stop-time (get-universal-time))
 
1186
                        (total-time (- stop-time start-time)))
 
1187
                   (when (> total-time *max-compile-time*)
 
1188
                     (setf *max-compile-time* total-time)
 
1189
                     (setf *max-compile-term* lambda-form)))
 
1190
                 ;; #+:ecl (si:gc t)
 
1191
                 )))))
 
1192
      (let ((optimized-compiled-fn (%compile optimized-fn-src
 
1193
                                             *name-to-use-in-optimized-defun*))
 
1194
            (unoptimized-compiled-fn
 
1195
             (if *compile-unoptimized-form*
 
1196
                 (%compile unoptimized-fn-src *name-to-use-in-unoptimized-defun*)
 
1197
               (eval `(function ,unoptimized-fn-src)))))
 
1198
        (declare (type function optimized-compiled-fn unoptimized-compiled-fn))
 
1199
        (dolist (vals vals-list)
 
1200
          (setq *int-form-vals* vals)
 
1201
          (flet ((%eval-error
 
1202
                  (kind)
 
1203
                  (let ((*print-circle* t))
 
1204
                    (format t "~A~%" (format nil "~S" form)))
 
1205
                  (finish-output *standard-output*)
 
1206
                  (return
 
1207
                   (list (list :vars vars
 
1208
                               :vals vals
 
1209
                               :form form
 
1210
                               :var-types var-types
 
1211
                               :decls1 opt-decls-1
 
1212
                               :decls2 opt-decls-2
 
1213
                               :optimized-lambda-form optimized-fn-src
 
1214
                               :unoptimized-lambda-form unoptimized-fn-src
 
1215
                               :kind kind)))))
 
1216
              
 
1217
            (let ((unopt-result
 
1218
                   (cl:handler-case
 
1219
                    (cl:handler-bind
 
1220
                     (#+sbcl (sb-ext::compiler-note #'muffle-warning)
 
1221
                             (warning #'muffle-warning))
 
1222
                     (identity ;; multiple-value-list
 
1223
                      (apply unoptimized-compiled-fn vals)))
 
1224
                    ((or error serious-condition)
 
1225
                     (c)
 
1226
                     (%eval-error (list :unoptimized-form-error
 
1227
                                        (with-output-to-string
 
1228
                                          (s) (prin1 c s)))))))
 
1229
                  (opt-result
 
1230
                   (cl:handler-case
 
1231
                    (cl:handler-bind
 
1232
                     (#+sbcl (sb-ext::compiler-note #'muffle-warning)
 
1233
                             (warning #'muffle-warning))
 
1234
                     (identity ;; multiple-value-list
 
1235
                      (apply optimized-compiled-fn vals)))
 
1236
                    ((or error serious-condition)
 
1237
                     (c)
 
1238
                     (%eval-error (list :optimized-form-error
 
1239
                                        (with-output-to-string
 
1240
                                          (s) (prin1 c s))))))))
 
1241
              (if (equal opt-result unopt-result)
 
1242
                  nil
 
1243
                (progn
 
1244
                  (format t "Different results: ~A, ~A~%"
 
1245
                          opt-result unopt-result)
 
1246
                  (setq *opt-result* opt-result
 
1247
                        *unopt-result* unopt-result)
 
1248
                  (%eval-error (list :different-results
 
1249
                                     opt-result
 
1250
                                     unopt-result)))))))))))
 
1251
 
 
1252
;;; Interface to the form pruner
 
1253
 
 
1254
(declaim (special *prune-table*))
 
1255
 
 
1256
(defun prune-int-form (input-form vars var-types vals-list opt-decls-1 opt-decls-2)
 
1257
  "Conduct tests on selected simplified versions of INPUT-FORM.  Return the
 
1258
   minimal form that still causes some kind of failure."
 
1259
  (loop do
 
1260
        (let ((form input-form))
 
1261
          (flet ((%try-fn (new-form)
 
1262
                          (when (test-int-form new-form vars var-types vals-list
 
1263
                                               opt-decls-1 opt-decls-2)
 
1264
                            (setf form new-form)
 
1265
                            (throw 'success nil))))
 
1266
            (let ((*prune-table* (make-hash-table :test #'eq)))
 
1267
              (loop
 
1268
               (catch 'success
 
1269
                 (prune form #'%try-fn)
 
1270
                 (return form)))))
 
1271
          (when (equal form input-form) (return form))
 
1272
          (setq input-form form))))
 
1273
 
 
1274
(defun prune-results (result-list)
 
1275
  "Given a list of test results, prune their forms down to a minimal set."
 
1276
  (loop for result in result-list
 
1277
        collect
 
1278
        (let* ((form (getf result :form))
 
1279
               (vars (getf result :vars))
 
1280
               (var-types (getf result :var-types))
 
1281
               (vals-list (list (getf result :vals)))
 
1282
               (opt-decl-1 (getf result :decls1))
 
1283
               (opt-decl-2 (getf result :decls2))
 
1284
               (pruned-form (prune-int-form form vars var-types vals-list opt-decl-1 opt-decl-2))
 
1285
               (optimized-lambda-form (make-optimized-lambda-form
 
1286
                                       pruned-form vars var-types opt-decl-1))
 
1287
               (unoptimized-lambda-form (make-unoptimized-lambda-form
 
1288
                                         pruned-form vars var-types opt-decl-2)))
 
1289
            `(:vars ,vars
 
1290
              :var-types ,var-types
 
1291
              :vals ,(first vals-list)
 
1292
              :form ,pruned-form
 
1293
              :decls1 ,opt-decl-1
 
1294
              :decls2 ,opt-decl-2
 
1295
              :optimized-lambda-form ,optimized-lambda-form
 
1296
              :unoptimized-lambda-form ,unoptimized-lambda-form))))
 
1297
 
 
1298
;;;
 
1299
;;; The call (PRUNE form try-fn) attempts to simplify the lisp form
 
1300
;;; so that it still satisfies TRY-FN.  The function TRY-FN should
 
1301
;;; return if the substitution is a failure.  Otherwise, it should
 
1302
;;; transfer control elsewhere via GO, THROW, etc.
 
1303
;;;
 
1304
;;; The return value of PRUNE should be ignored.
 
1305
;;;
 
1306
(defun prune (form try-fn)
 
1307
  (declare (type function try-fn))
 
1308
  (when (gethash form *prune-table*)
 
1309
    (return-from prune nil))
 
1310
  (flet ((try (x) (funcall try-fn x)))
 
1311
    (cond
 
1312
     ((keywordp form) nil)
 
1313
     ((integerp form)
 
1314
      (unless (zerop form) (try 0)))
 
1315
     ((consp form)
 
1316
      (let* ((op (car form))
 
1317
             (args (cdr form))
 
1318
             (nargs (length args)))
 
1319
        (case op
 
1320
 
 
1321
         ((quote) nil)
 
1322
 
 
1323
         ((go)
 
1324
          (try 0))
 
1325
         
 
1326
         ((signum integer-length logcount
 
1327
                  logandc1 logandc2 lognand lognor logorc1 logorc2
 
1328
                  realpart imagpart)
 
1329
          (try 0)
 
1330
          (mapc try-fn args)
 
1331
          (prune-fn form try-fn))
 
1332
 
 
1333
         ((make-array)
 
1334
          (when (and (eq (car args) nil)
 
1335
                     (eq (cadr args) ':initial-element)
 
1336
                     ; (null (cdddr args))
 
1337
                     )
 
1338
            (prune (caddr args) #'(lambda (form) (try `(make-array nil :initial-element ,form . ,(cdddr args)))))
 
1339
            (when (cdddr args)
 
1340
              (try `(make-array nil :initial-element ,(caddr args))))
 
1341
            ))
 
1342
 
 
1343
         ((cons)
 
1344
          (prune-fn form try-fn))
 
1345
 
 
1346
         ((dotimes)
 
1347
          (try 0)
 
1348
          (let* ((binding-form (first args))
 
1349
                 (body (rest args))
 
1350
                 (var (first binding-form))
 
1351
                 (count-form (second binding-form))
 
1352
                 (result (third binding-form)))
 
1353
            (try result)
 
1354
            (unless (eql count-form 0)
 
1355
              (try `(dotimes (,var 0 ,result) ,@body)))
 
1356
            (prune result #'(lambda (form)
 
1357
                              (try `(dotimes (,var ,count-form ,form) ,@body))))
 
1358
            (when (= (length body) 1)
 
1359
              (prune (first body)
 
1360
                     #'(lambda (form)
 
1361
                         (when (consp form)
 
1362
                           (try `(dotimes (,var ,count-form ,result) ,form))))))))
 
1363
         
 
1364
         ((abs 1+ 1-)
 
1365
          (try 0)
 
1366
          (mapc try-fn args)
 
1367
          (prune-fn form try-fn))
 
1368
 
 
1369
         ((identity  ignore-errors cl:handler-case restart-case locally)
 
1370
          (unless (and (consp args)
 
1371
                       (consp (car args))
 
1372
                       (eql (caar args) 'tagbody))
 
1373
            (mapc try-fn args))
 
1374
          (prune-fn form try-fn))
 
1375
 
 
1376
         ((boole)
 
1377
          (try (second args))
 
1378
          (try (third args))
 
1379
          (prune (second args)
 
1380
                 #'(lambda (form) (try `(boole ,(first args) ,form ,(third args)))))
 
1381
          (prune (third args)
 
1382
                 #'(lambda (form) (try `(boole ,(first args) ,(second args) ,form)))))
 
1383
 
 
1384
         ((unwind-protect prog1 multiple-value-prog1)
 
1385
          (try (first args))
 
1386
          (let ((val (first args))
 
1387
                (rest (rest args)))
 
1388
            (when rest
 
1389
              (try `(unwind-protect ,val))
 
1390
              (when (cdr rest)
 
1391
                (loop for i from 0 below (length rest)
 
1392
                      do
 
1393
                      (try `(unwind-protect ,val
 
1394
                              ,@(subseq rest 0 i)
 
1395
                              ,@(subseq rest (1+ i))))))))
 
1396
          (prune-fn form try-fn))
 
1397
 
 
1398
         ((prog2)
 
1399
          (assert (>= (length args) 2))
 
1400
          (let ((val1 (first args))
 
1401
                (arg2 (second args))
 
1402
                (rest (cddr args)))
 
1403
            (try arg2)
 
1404
            (prune-fn form try-fn)
 
1405
            (when rest
 
1406
              (try `(prog2 ,val1 ,arg2))
 
1407
              (when (cdr rest)
 
1408
                (loop for i from 0 below (length rest)
 
1409
                      do
 
1410
                      (try `(prog2 ,val1 ,arg2
 
1411
                              ,@(subseq rest 0 i)
 
1412
                              ,@(subseq rest (1+ i)))))))))
 
1413
 
 
1414
         ((typep)
 
1415
          (try (car args))
 
1416
          (prune (car args)
 
1417
                 #'(lambda (form) `(,op ,form ,@(cdr args)))))
 
1418
 
 
1419
         ((load-time-value)
 
1420
          (let ((arg (first args)))
 
1421
            (try arg)
 
1422
            (cond
 
1423
             ((cdr args)
 
1424
              (try `(load-time-value ,arg))
 
1425
              (prune arg
 
1426
                     #'(lambda (form)
 
1427
                         (try `(load-time-value ,form ,(second args))))))
 
1428
             (t
 
1429
              (prune arg
 
1430
                     #'(lambda (form)
 
1431
                         (try `(load-time-value ,form))))))))
 
1432
 
 
1433
         ((eval)
 
1434
          (try 0)
 
1435
          (let ((arg (first args)))
 
1436
            (cond
 
1437
             ((consp arg)
 
1438
              (cond
 
1439
               ((eql (car arg) 'quote)
 
1440
                (prune (cadr arg) #'(lambda (form) (try `(eval ',form)))))
 
1441
               (t
 
1442
                (try arg)
 
1443
                (prune arg #'(lambda (form) `(eval ,form))))))
 
1444
             (t (try arg)))))
 
1445
 
 
1446
         ((the macrolet cl:handler-bind restart-bind)
 
1447
          (assert (= (length args) 2))
 
1448
          (try (second args))
 
1449
          (prune (second args) try-fn))
 
1450
         
 
1451
         ((not eq eql equal)
 
1452
          (when (every #'constantp args)
 
1453
            (try (eval form)))
 
1454
          (try t)
 
1455
          (try nil)
 
1456
          (mapc try-fn args)
 
1457
          (prune-fn form try-fn)
 
1458
          )
 
1459
 
 
1460
         ((and or = < > <= >= /=)
 
1461
          (when (every #'constantp args)
 
1462
            (try (eval form)))
 
1463
          (try t)
 
1464
          (try nil)
 
1465
          (mapc try-fn args)
 
1466
          (prune-nary-fn form try-fn)
 
1467
          (prune-fn form try-fn))
 
1468
         
 
1469
         ((- + * min max logand logior logxor logeqv gcd lcm values)
 
1470
          (when (every #'constantp args)
 
1471
            (try (eval form)))
 
1472
          (try 0)
 
1473
          (mapc try-fn args)
 
1474
          (prune-nary-fn form try-fn)
 
1475
          (prune-fn form try-fn))
 
1476
 
 
1477
         ((/)
 
1478
          (when (every #'constantp args)
 
1479
            (try (eval form)))
 
1480
          (try 0)
 
1481
          (try (car args))
 
1482
          (when (cddr args)
 
1483
            (prune (car args) #'(lambda (form) (try `(/ ,form ,(second args)))))))
 
1484
 
 
1485
         ((expt rationalize rational numberator denominator)
 
1486
          (try 0)
 
1487
          (mapc try-fn args)
 
1488
          (prune-fn form try-fn))
 
1489
         
 
1490
         ((coerce)
 
1491
          (try 0)
 
1492
          (try (car args))
 
1493
          (prune #'(lambda (form) (try `(coerce ,form ,(cadr args))))
 
1494
                 (car args)))
 
1495
          
 
1496
 
 
1497
         ((multiple-value-call)
 
1498
          ;; Simplify usual case
 
1499
          (when (= nargs 2)
 
1500
            (destructuring-bind (arg1 arg2) args
 
1501
              (when (and (consp arg1) (consp arg2)
 
1502
                         (eql (first arg1) 'function)
 
1503
                         (eql (first arg2) 'values))
 
1504
                (mapc try-fn (rest arg2))
 
1505
                (let ((fn (second arg1)))
 
1506
                  (when (symbolp fn)
 
1507
                    (try `(,fn ,@(rest arg2)))))
 
1508
                ;; Prune the VALUES form
 
1509
                (prune-list (rest arg2)
 
1510
                            #'prune
 
1511
                            #'(lambda (args)
 
1512
                                (try `(multiple-value-call ,arg1 (values ,@args)))))
 
1513
                )))
 
1514
          (mapc try-fn (rest args)))
 
1515
 
 
1516
         ((bit sbit elt aref svref)
 
1517
          (try 0)
 
1518
          (when (= (length args) 2)
 
1519
            (let ((arg1 (car args))
 
1520
                  (arg2 (cadr args)))
 
1521
              (when (and (consp arg2)
 
1522
                         (eql (car arg2) 'min)
 
1523
                         (integerp (cadr arg2)))
 
1524
                (let ((arg2.2 (caddr arg2)))
 
1525
                  (try arg2.2)
 
1526
                  (when (and (consp arg2.2)
 
1527
                             (eql (car arg2.2) 'max)
 
1528
                             (integerp (cadr arg2.2)))
 
1529
                    (prune (caddr arg2.2)
 
1530
                           #'(lambda (form)
 
1531
                               (try `(,op ,arg1 (min ,(cadr arg2)
 
1532
                                                     (max ,(cadr arg2.2) ,form))))))))))))
 
1533
 
 
1534
         ((car cdr)
 
1535
          (try 0)
 
1536
          (try 1))
 
1537
 
 
1538
         ((if)
 
1539
          (let (;; (pred (first args))
 
1540
                (then (second args))
 
1541
                (else (third args)))
 
1542
            (try then)
 
1543
            (try else)
 
1544
            (when (every #'constantp args)
 
1545
              (try (eval form)))
 
1546
            (prune-fn form try-fn)))
 
1547
 
 
1548
         ((setq setf shiftf)
 
1549
          (try 0)
 
1550
          ;; Assumes only one assignment
 
1551
          (assert (= (length form) 3))
 
1552
          (try (second args))
 
1553
          (unless (integerp (second args))
 
1554
            (prune (second args)
 
1555
                   #'(lambda (form)
 
1556
                       (try `(,op ,(first args) ,form))))))
 
1557
 
 
1558
         ((multiple-value-setq)
 
1559
          (try 0)
 
1560
          ;; Assumes only one assignment, and one variable
 
1561
          (assert (= (length form) 3))
 
1562
          (assert (= (length (first args)) 1))
 
1563
          (try `(setq ,(caar args) ,(cadr args)))
 
1564
          (unless (integerp (second args))
 
1565
            (prune (second args)
 
1566
                   #'(lambda (form)
 
1567
                       (try `(,op ,(first args) ,form))))))
 
1568
 
 
1569
         ((byte)
 
1570
          (prune-fn form try-fn))
 
1571
 
 
1572
         ((deposit-field dpb)
 
1573
          (try 0)
 
1574
          (destructuring-bind (a1 a2 a3)
 
1575
              args
 
1576
            (try a1)
 
1577
            (try a3)
 
1578
            (when (and (integerp a1)
 
1579
                       (integerp a3)
 
1580
                       (and (consp a2)
 
1581
                            (eq (first a2) 'byte)
 
1582
                            (integerp (second a2))
 
1583
                            (integerp (third a2))))
 
1584
              (try (eval form))))
 
1585
          (prune-fn form try-fn))
 
1586
 
 
1587
         ((ldb mask-field)
 
1588
          (try 0)
 
1589
          (try (second args))
 
1590
          (when (and (consp (first args))
 
1591
                     (eq 'byte (first (first args)))
 
1592
                     (every #'numberp (cdr (first args)))
 
1593
                     (numberp (second args)))
 
1594
            (try (eval form)))
 
1595
          (prune-fn form try-fn))
 
1596
 
 
1597
         ((ldb-test)
 
1598
          (try t)
 
1599
          (try nil)
 
1600
          (prune-fn form try-fn))
 
1601
 
 
1602
         ((let let*)
 
1603
          (prune-let form try-fn))
 
1604
 
 
1605
         ((multiple-value-bind)
 
1606
          (assert (= (length args) 3))
 
1607
          (let ((arg1 (first args))
 
1608
                (arg2 (second args))
 
1609
                (body (caddr args)))
 
1610
            (when (= (length arg1) 1)
 
1611
              (try `(let ((,(first arg1) ,arg2)) ,body)))
 
1612
            (prune arg2 #'(lambda (form)
 
1613
                            (try `(multiple-value-bind ,arg1 ,form ,body))))
 
1614
            (prune body #'(lambda (form)
 
1615
                            (try `(multiple-value-bind ,arg1 ,arg2 ,form))))))
 
1616
 
 
1617
         ((block)
 
1618
          (let ((name (second form))
 
1619
                (body (cddr form)))
 
1620
            (when (and body (null (cdr body)))
 
1621
              (let ((form1 (first body)))
 
1622
 
 
1623
                ;; Try removing the block entirely if it is not in use
 
1624
                (when (not (find-in-tree name body))
 
1625
                  (try form1))
 
1626
                
 
1627
                ;; Try removing the block if its only use is an immediately
 
1628
                ;; enclosed return-from: (block <n> (return-from <n> <e>))
 
1629
                (when (and (consp form1)
 
1630
                           (eq (first form1) 'return-from)
 
1631
                           (eq (second form1) name)
 
1632
                           (not (find-in-tree name (third form1))))
 
1633
                  (try (third form1)))
 
1634
                
 
1635
                ;; Otherwise, try to simplify the subexpression
 
1636
                (prune form1
 
1637
                       #'(lambda (x)
 
1638
                           (try `(block ,name ,x))))))))
 
1639
 
 
1640
         ((catch)
 
1641
          (let* ((tag (second form))
 
1642
                 (name (if (consp tag) (cadr tag) tag))
 
1643
                 (body (cddr form)))
 
1644
            (when (and body (null (cdr body)))
 
1645
              (let ((form1 (first body)))
 
1646
 
 
1647
                ;; Try removing the catch entirely if it is not in use
 
1648
                ;; We make assumptions here about what throws can
 
1649
                ;; be present.
 
1650
                (when (or (not (find-in-tree 'throw body))
 
1651
                          (not (find-in-tree name body)))
 
1652
                  (try form1))
 
1653
                
 
1654
                ;; Try removing the block if its only use is an immediately
 
1655
                ;; enclosed return-from: (block <n> (return-from <n> <e>))
 
1656
                (when (and (consp form1)
 
1657
                           (eq (first form1) 'throw)
 
1658
                           (equal (second form1) name)
 
1659
                           (not (find-in-tree name (third form1))))
 
1660
                  (try (third form1)))
 
1661
                
 
1662
                ;; Otherwise, try to simplify the subexpression
 
1663
                (prune form1
 
1664
                       #'(lambda (x)
 
1665
                           (try `(catch ,tag ,x))))))))
 
1666
 
 
1667
         ((throw)
 
1668
          (try (second args))
 
1669
          (prune (second args)
 
1670
                 #'(lambda (x) (try `(throw ,(first args) ,x)))))
 
1671
 
 
1672
         ((flet labels)
 
1673
          (try 0)
 
1674
          (prune-flet form try-fn))
 
1675
 
 
1676
         ((case)
 
1677
          (prune-case form try-fn))
 
1678
 
 
1679
         ((isqrt)
 
1680
          (let ((arg (second form)))
 
1681
            (assert (null (cddr form)))
 
1682
            (assert (consp arg))
 
1683
            (assert (eq (first arg) 'abs))
 
1684
            (let ((arg2 (second arg)))
 
1685
              (try arg2)
 
1686
              ;; Try to fold
 
1687
              (when (integerp arg2)
 
1688
                (try (isqrt (abs arg2))))
 
1689
              ;; Otherwise, simplify arg2
 
1690
              (prune arg2 #'(lambda (form)
 
1691
                              (try `(isqrt (abs ,form))))))))
 
1692
 
 
1693
         ((ash)
 
1694
          (try 0)
 
1695
          (let ((form1 (second form))
 
1696
                (form2 (third form)))
 
1697
            (try form1)
 
1698
            (try form2)
 
1699
            (prune form1
 
1700
                   #'(lambda (form)
 
1701
                       (try `(ash ,form ,form2))))
 
1702
            (when (and (consp form2)
 
1703
                       (= (length form2) 3))
 
1704
              (when (and (integerp form1)
 
1705
                         (eq (first form2) 'min)
 
1706
                         (every #'integerp (cdr form2)))
 
1707
                (try (eval form)))
 
1708
              (let ((form3 (third form2)))
 
1709
                (prune form3
 
1710
                       #'(lambda (form)
 
1711
                           (try
 
1712
                            `(ash ,form1 (,(first form2) ,(second form2)
 
1713
                                          ,form)))))))))
 
1714
 
 
1715
         ((floor ceiling truncate round mod rem)
 
1716
          (try 0)
 
1717
          (let ((form1 (second form))
 
1718
                (form2 (third form)))
 
1719
            (try form1)
 
1720
            (when (cddr form) (try form2))
 
1721
            (prune form1
 
1722
                   (if (cddr form)
 
1723
                       #'(lambda (form)
 
1724
                           (try `(,op ,form ,form2)))
 
1725
                     #'(lambda (form) (try `(,op ,form)))))
 
1726
            (when (and (consp form2)
 
1727
                       (= (length form2) 3))
 
1728
              (when (and (integerp form1)
 
1729
                         (member (first form2) '(max min))
 
1730
                         (every #'integerp (cdr form2)))
 
1731
                (try (eval form)))
 
1732
              (let ((form3 (third form2)))
 
1733
                (prune form3
 
1734
                       #'(lambda (form)
 
1735
                           (try
 
1736
                            `(,op ,form1 (,(first form2) ,(second form2)
 
1737
                                          ,form)))))))))
 
1738
 
 
1739
         ((constantly)
 
1740
          (unless (eql (car args) 0)
 
1741
            (prune (car args)
 
1742
                   #'(lambda (arg) (try `(constantly ,arg))))))
 
1743
 
 
1744
         ((funcall)
 
1745
          (try 0)
 
1746
          (let ((fn (second form))
 
1747
                (fn-args (cddr form)))
 
1748
            (mapc try-fn fn-args)
 
1749
            (unless (equal fn '(constantly 0))
 
1750
              (try `(funcall (constantly 0) ,@fn-args)))
 
1751
            (when (and (consp fn)
 
1752
                       (eql (car fn) 'function)
 
1753
                       (symbolp (cadr fn)))
 
1754
              (try `(,(cadr fn) ,@fn-args)))
 
1755
            (prune-list fn-args
 
1756
                        #'prune
 
1757
                        #'(lambda (args)
 
1758
                            (try `(funcall ,fn ,@args))))))
 
1759
 
 
1760
         ((reduce)
 
1761
          (try 0)
 
1762
          (let ((arg1 (car args))
 
1763
                (arg2 (cadr args))
 
1764
                (rest (cddr args)))
 
1765
            (when (and ;; (null (cddr args))
 
1766
                       (consp arg1)
 
1767
                       (eql (car arg1) 'function))
 
1768
              (let ((arg1.2 (cadr arg1)))
 
1769
                (when (and (consp arg1.2)
 
1770
                           (eql (car arg1.2) 'lambda))
 
1771
                  (let ((largs (cadr arg1.2))
 
1772
                        (body (cddr arg1.2)))
 
1773
                    (when (null (cdr body))
 
1774
                      (prune (car body)
 
1775
                             #'(lambda (bform)
 
1776
                                 (try `(reduce (function (lambda ,largs ,bform))
 
1777
                                               ,arg2 ,@rest)))))))))
 
1778
            (when (consp arg2)
 
1779
              (case (car arg2)
 
1780
                ((list vector)
 
1781
                 (let ((arg2.rest (cdr arg2)))
 
1782
                   (mapc try-fn arg2.rest)
 
1783
                   (prune-list arg2.rest
 
1784
                               #'prune
 
1785
                               #'(lambda (args)
 
1786
                                   (try `(reduce ,arg1
 
1787
                                                 (,(car arg2) ,@args)
 
1788
                                                 ,@rest))))))))))
 
1789
 
 
1790
         ((apply)
 
1791
          (try 0)
 
1792
          (let ((fn (second form))
 
1793
                (fn-args (butlast (cddr form)))
 
1794
                (list-arg (car (last form))))
 
1795
            (mapc try-fn fn-args)
 
1796
            (unless (equal fn '(constantly 0))
 
1797
              (try `(apply (constantly 0) ,@(cddr form))))
 
1798
            (when (and (consp list-arg)
 
1799
                       (eq (car list-arg) 'list))
 
1800
              (mapc try-fn (cdr list-arg)))
 
1801
            (prune-list fn-args
 
1802
                        #'prune
 
1803
                        #'(lambda (args)
 
1804
                            (try `(apply ,fn ,@args ,list-arg))))
 
1805
            (when (and (consp list-arg)
 
1806
                       (eq (car list-arg) 'list))
 
1807
              (try `(apply ,fn ,@fn-args ,@(cdr list-arg) nil))
 
1808
              (prune-list (cdr list-arg)
 
1809
                        #'prune
 
1810
                        #'(lambda (args)
 
1811
                            (try `(apply ,fn ,@fn-args
 
1812
                                         (list ,@args))))))))
 
1813
 
 
1814
         ((progv)
 
1815
          (try 0)
 
1816
          (prune-progv form try-fn))
 
1817
 
 
1818
         ((tagbody)
 
1819
          (try 0)
 
1820
          (prune-tagbody form try-fn))
 
1821
 
 
1822
         ((progn)
 
1823
          (when (null args) (try nil))
 
1824
          (try (car (last args)))
 
1825
          (loop for i from 0 below (1- (length args))
 
1826
                for a in args
 
1827
                do (try `(progn ,@(subseq args 0 i)
 
1828
                                ,@(subseq args (1+ i))))
 
1829
                do (when (and (consp a)
 
1830
                              (or
 
1831
                               (eq (car a) 'progn)
 
1832
                               (and (eq (car a) 'tagbody)
 
1833
                                    (every #'consp (cdr a)))))
 
1834
                     (try `(progn ,@(subseq args 0 i)
 
1835
                                  ,@(copy-list (cdr a))
 
1836
                                  ,@(subseq args (1+ i))))))
 
1837
          (prune-fn form try-fn))
 
1838
 
 
1839
         ((loop)
 
1840
          (try 0)
 
1841
          (when (and (eql (length args) 6)
 
1842
                     (eql (elt args 0) 'for)
 
1843
                     (eql (elt args 2) 'below))
 
1844
            (let ((var (elt args 1))
 
1845
                  (count (elt args 3))
 
1846
                  (form (elt args 5)))
 
1847
              (unless (eql count 0) (try count))
 
1848
              (case (elt args 4)
 
1849
                (sum
 
1850
                 (try `(let ((,(elt args 1) 0)) ,(elt args 5)))
 
1851
                 (prune form #'(lambda (form)
 
1852
                                 (try `(loop for ,var below ,count sum ,form)))))
 
1853
                (count
 
1854
                 (unless (or (eql form t) (eql form nil))
 
1855
                   (try `(loop for ,var below ,count count t))
 
1856
                   (try `(loop for ,var below ,count count nil))
 
1857
                   (prune form
 
1858
                          #'(lambda (form)
 
1859
                              (try `(loop for ,var below ,count count ,form))))))
 
1860
                ))))
 
1861
 
 
1862
         (otherwise
 
1863
          (try 0)
 
1864
          (prune-fn form try-fn))
 
1865
         
 
1866
         )))))
 
1867
  (setf (gethash form *prune-table*) t)
 
1868
  nil)
 
1869
 
 
1870
(defun find-in-tree (value tree)
 
1871
  "Return true if VALUE is eql to a node in TREE."
 
1872
  (or (eql value tree)
 
1873
      (and (consp tree)
 
1874
           (or (find-in-tree value (car tree))
 
1875
               (find-in-tree value (cdr tree))))))
 
1876
 
 
1877
(defun prune-list (list element-prune-fn list-try-fn)
 
1878
  (declare (type function element-prune-fn list-try-fn))
 
1879
  "Utility function for pruning in a list."
 
1880
    (loop for i from 0
 
1881
          for e in list
 
1882
          do (funcall element-prune-fn
 
1883
                      e
 
1884
                      #'(lambda (form)
 
1885
                          (funcall list-try-fn
 
1886
                                   (append (subseq list 0 i)
 
1887
                                           (list form)
 
1888
                                           (subseq list (1+ i))))))))
 
1889
 
 
1890
(defun prune-case (form try-fn)
 
1891
  (declare (type function try-fn))
 
1892
  (flet ((try (e) (funcall try-fn e)))
 
1893
    (let* ((op (first form))
 
1894
           (expr (second form))
 
1895
           (cases (cddr form)))
 
1896
      
 
1897
      ;; Try just the top expression
 
1898
      (try expr)
 
1899
      
 
1900
      ;; Try simplifying the expr
 
1901
      (prune expr
 
1902
             #'(lambda (form)
 
1903
                 (try `(,op ,form ,@cases))))
 
1904
      
 
1905
      ;; Try individual cases
 
1906
      (loop for case in cases
 
1907
            do (try (first (last (rest case)))))
 
1908
      
 
1909
      ;; Try deleting individual cases
 
1910
      (loop for i from 0 below (1- (length cases))
 
1911
            do (try `(,op ,expr
 
1912
                          ,@(subseq cases 0 i)
 
1913
                          ,@(subseq cases (1+ i)))))
 
1914
      
 
1915
      ;; Try simplifying the cases
 
1916
      ;; Assume each case has a single form
 
1917
      (prune-list cases
 
1918
                  #'(lambda (case try-fn)
 
1919
                      (declare (type function try-fn))
 
1920
                      (when (eql (length case) 2)
 
1921
                        (prune (cadr case)
 
1922
                               #'(lambda (form)
 
1923
                                   (funcall try-fn
 
1924
                                            (list (car case) form))))))
 
1925
                  #'(lambda (cases)
 
1926
                      (try `(,op ,expr ,@cases)))))))
 
1927
 
 
1928
(defun prune-tagbody (form try-fn)
 
1929
  (declare (type function try-fn))
 
1930
  (let (;; (op (car form))
 
1931
        (body (cdr form)))
 
1932
    (loop for i from 0
 
1933
          for e in body
 
1934
          do
 
1935
          (cond
 
1936
           ((atom e)
 
1937
            ;; A tag
 
1938
            (unless (find-in-tree e (subseq body 0 i))
 
1939
              (funcall try-fn `(tagbody ,@(subseq body 0 i)
 
1940
                                        ,@(subseq body (1+ i))))))
 
1941
           (t
 
1942
            (funcall try-fn
 
1943
                     `(tagbody ,@(subseq body 0 i)
 
1944
                               ,@(subseq body (1+ i))))
 
1945
            (prune e
 
1946
                   #'(lambda (form)
 
1947
                       ;; Don't put an atom here.
 
1948
                       (when (consp form)
 
1949
                         (funcall
 
1950
                          try-fn
 
1951
                          `(tagbody ,@(subseq body 0 i)
 
1952
                                    ,form
 
1953
                                    ,@(subseq body (1+ i))))))))))))
 
1954
 
 
1955
(defun prune-progv (form try-fn)
 
1956
  (declare (type function try-fn))
 
1957
  (let (;; (op (car form))
 
1958
        (vars-form (cadr form))
 
1959
        (vals-form (caddr form))
 
1960
        (body-list (cdddr form)))
 
1961
    (when (and (null vars-form) (null vals-form))
 
1962
      (funcall try-fn `(let () ,@body-list)))
 
1963
    (when (and (consp vals-form) (eql (car vals-form) 'list))
 
1964
      (when (and (consp vars-form) (eql (car vars-form) 'quote))
 
1965
        (let ((vars (cadr vars-form))
 
1966
              (vals (cdr vals-form)))
 
1967
          (when (eql (length vars) (length vals))
 
1968
            (let ((let-form `(let () ,@body-list)))
 
1969
              (mapc #'(lambda (var val)
 
1970
                        (setq let-form `(let ((,var ,val)) ,let-form)))
 
1971
                    vars vals)
 
1972
              (funcall try-fn let-form)))
 
1973
          ;; Try simplifying the vals forms
 
1974
          (prune-list vals
 
1975
                      #'prune
 
1976
                      #'(lambda (vals)
 
1977
                          (funcall try-fn
 
1978
                                   `(progv ,vars-form (list ,@vals) ,@body-list)))))))
 
1979
    ;; Try simplifying the body
 
1980
    (when (eql (length body-list) 1)
 
1981
      (prune (car body-list)
 
1982
             #'(lambda (form)
 
1983
                 (funcall try-fn
 
1984
                          `(progv ,vars-form ,vals-form ,form)))))))
 
1985
 
 
1986
(defun prune-nary-fn (form try-fn)
 
1987
  ;; Attempt to reduce the number of arguments to the fn
 
1988
  ;; Do not reduce below 1
 
1989
  (declare (type function try-fn))
 
1990
  (let* ((op (car form))
 
1991
         (args (cdr form))
 
1992
         (nargs (length args)))
 
1993
    (when (> nargs 1)
 
1994
      (loop for i from 1 to nargs
 
1995
            do (funcall try-fn `(,op ,@(subseq args 0 (1- i))
 
1996
                                     ,@(subseq args i)))))))
 
1997
 
 
1998
(defun prune-fn (form try-fn)
 
1999
  "Attempt to simplify a function call form.  It is considered
 
2000
   acceptable to replace the call by one of its argument forms."
 
2001
  (declare (type function try-fn))
 
2002
  (prune-list (cdr form)
 
2003
              #'prune
 
2004
              #'(lambda (args)
 
2005
                  (funcall try-fn (cons (car form) args)))))
 
2006
 
 
2007
(defun prune-let (form try-fn)
 
2008
  "Attempt to simplify a LET form."
 
2009
  (declare (type function try-fn))
 
2010
  (let* ((op (car form))
 
2011
         (binding-list (cadr form))
 
2012
         (body (cddr form))
 
2013
         (body-len (length body))
 
2014
         (len (length binding-list))
 
2015
         )
 
2016
 
 
2017
    (when (> body-len 1)
 
2018
      (funcall try-fn `(,op ,binding-list ,@(cdr body))))
 
2019
 
 
2020
    ;; Try to simplify (let ((<name> <form>)) ...) to <form>
 
2021
    #|
 
2022
    (when (and (>= len 1)
 
2023
               ;; (eql body-len 1)
 
2024
               ;; (eql (caar binding-list) (car body))
 
2025
               )
 
2026
      (let ((val-form (cadar binding-list)))
 
2027
        (unless (and (consp val-form)
 
2028
                     (eql (car val-form) 'make-array))
 
2029
          (funcall try-fn val-form))))
 
2030
    |#
 
2031
 
 
2032
    (when (>= len 1)
 
2033
      (let ((val-form (cadar binding-list)))
 
2034
        (when (consp val-form)
 
2035
          (case (car val-form)
 
2036
            ((make-array)
 
2037
             (let ((init (getf (cddr val-form) :initial-element)))
 
2038
               (when init
 
2039
                 (funcall try-fn init))))
 
2040
            ((cons)
 
2041
             (funcall try-fn (cadr val-form))
 
2042
             (funcall try-fn (caddr val-form)))))))
 
2043
 
 
2044
    ;; Try to simplify the forms in the RHS of the bindings
 
2045
    (prune-list binding-list
 
2046
                #'(lambda (binding try-fn)
 
2047
                    (declare (type function try-fn))
 
2048
                    (prune (cadr binding)
 
2049
                           #'(lambda (form)
 
2050
                               (funcall try-fn
 
2051
                                        (list (car binding)
 
2052
                                              form)))))
 
2053
                #'(lambda (bindings)
 
2054
                    (funcall try-fn `(,op ,bindings ,@body))))
 
2055
 
 
2056
    ;; Prune off unused variable
 
2057
    (when (and binding-list
 
2058
               (not (rest binding-list))
 
2059
               (let ((name (caar binding-list)))
 
2060
                 (and (symbolp name)
 
2061
                      (not (find-if-subtree #'(lambda (x) (eq x name)) body)))))
 
2062
      (funcall try-fn `(progn ,@body)))
 
2063
 
 
2064
    ;; Try to simplify the body of the LET form
 
2065
    (when body
 
2066
      (unless binding-list
 
2067
        (funcall try-fn (car (last body))))
 
2068
      (when (and (first binding-list)
 
2069
                 (not (rest binding-list))
 
2070
                 (not (rest body)))
 
2071
        (let ((binding (first binding-list)))
 
2072
          (unless (or (consp (second binding))
 
2073
                      (has-binding-to-var (first binding) body)
 
2074
                      (has-assignment-to-var (first binding) body)
 
2075
                      )
 
2076
            (funcall try-fn `(let ()
 
2077
                               ,@(subst (second binding)
 
2078
                                        (first binding)
 
2079
                                        (remove-if #'(lambda (x) (and (consp x) (eq (car x) 'declare)))
 
2080
                                                   body)
 
2081
                                        ))))))
 
2082
      (prune (car (last body))
 
2083
             #'(lambda (form2)
 
2084
                 (funcall try-fn
 
2085
                          `(,@(butlast form) ,form2)))))))
 
2086
 
 
2087
(defun has-assignment-to-var (var form)
 
2088
  (find-if-subtree
 
2089
   #'(lambda (form)
 
2090
       (and (consp form)
 
2091
            (or
 
2092
             (and (member (car form) '(setq setf shiftf) :test #'eq)
 
2093
                  (eq (cadr form) var))
 
2094
             (and (eql (car form) 'multiple-value-setq)
 
2095
                  (member var (cadr form))))))
 
2096
   form))
 
2097
 
 
2098
(defun has-binding-to-var (var form)
 
2099
  (find-if-subtree
 
2100
   #'(lambda (form)
 
2101
       (and (consp form)
 
2102
            (case (car form)
 
2103
              ((let let*)
 
2104
               (loop for binding in (cadr form)
 
2105
                     thereis (eq (car binding) var)))
 
2106
              ((progv)
 
2107
               (and (consp (cadr form))
 
2108
                    (eq (caadr form) 'quote)
 
2109
                    (consp (second (cadr form)))
 
2110
                    (member var (second (cadr form)))))
 
2111
              (t nil))))
 
2112
   form))
 
2113
 
 
2114
(defun find-if-subtree (pred tree)
 
2115
  (declare (type function pred))
 
2116
  (cond
 
2117
   ((funcall pred tree) tree)
 
2118
   ((consp tree)
 
2119
    (or (find-if-subtree pred (car tree))
 
2120
        (find-if-subtree pred (cdr tree))))
 
2121
   (t nil)))
 
2122
 
 
2123
(defun prune-flet (form try-fn)
 
2124
  "Attempt to simplify a FLET form."
 
2125
  (declare (type function try-fn))
 
2126
 
 
2127
  (let* ((op (car form))
 
2128
         (binding-list (cadr form))
 
2129
         (body (cddr form)))
 
2130
 
 
2131
    ;; Remove a declaration, if any
 
2132
    (when (and (consp body)
 
2133
               (consp (car body))
 
2134
               (eq (caar body) 'declare))
 
2135
      (funcall try-fn `(,op ,binding-list ,@(cdr body))))
 
2136
 
 
2137
    ;; Try to prune optional arguments
 
2138
    (prune-list binding-list
 
2139
                #'(lambda (binding try-fn)
 
2140
                    (declare (type function try-fn))
 
2141
                    (let* ((name (car binding))
 
2142
                           (args (cadr binding))
 
2143
                           (body (cddr binding))
 
2144
                           (opt-pos (position-if #'(lambda (e) (member e '(&key &optional)))
 
2145
                                                 (the list args))))
 
2146
                      (when opt-pos
 
2147
                        (incf opt-pos)
 
2148
                        (let ((normal-args (subseq args 0 (1- opt-pos)))
 
2149
                              (optionals (subseq args opt-pos)))
 
2150
                          (prune-list optionals
 
2151
                                      #'(lambda (opt-lambda-arg try-fn)
 
2152
                                          (declare (type function try-fn))
 
2153
                                          (when (consp opt-lambda-arg)
 
2154
                                            (let ((name (first opt-lambda-arg))
 
2155
                                                  (form (second opt-lambda-arg)))
 
2156
                                              (prune form
 
2157
                                                     #'(lambda (form)
 
2158
                                                         (funcall try-fn (list name form)))))))
 
2159
                                      #'(lambda (opt-args)
 
2160
                                          (funcall try-fn
 
2161
                                                   `(,name (,@normal-args
 
2162
                                                              &optional
 
2163
                                                              ,@opt-args)
 
2164
                                                           ,@body))))))))
 
2165
                #'(lambda (bindings)
 
2166
                    (funcall try-fn `(,op ,bindings ,@body))))
 
2167
                       
 
2168
    
 
2169
    ;; Try to simplify the forms in the RHS of the bindings
 
2170
    (prune-list binding-list
 
2171
                #'(lambda (binding try-fn)
 
2172
                    (declare (type function try-fn))
 
2173
                      
 
2174
                    ;; Prune body of a binding
 
2175
                    (prune (third binding)
 
2176
                           #'(lambda (form)
 
2177
                               (funcall try-fn
 
2178
                                        (list (first binding)
 
2179
                                              (second binding)
 
2180
                                              form)))))
 
2181
                #'(lambda (bindings)
 
2182
                    (funcall try-fn `(,op ,bindings ,@body))))
 
2183
 
 
2184
    ;; ;; Try to simplify the body of the FLET form
 
2185
    (when body
 
2186
 
 
2187
      ;; No bindings -- try to simplify to the last form in the body
 
2188
      (unless binding-list
 
2189
        (funcall try-fn (first (last body))))
 
2190
 
 
2191
      (when (and (consp binding-list)
 
2192
                 (null (rest binding-list)))
 
2193
        (let ((binding (first binding-list)))
 
2194
          ;; One binding -- match on (flet ((<name> () <body>)) (<name>))
 
2195
          (when (and (symbolp (first binding))
 
2196
                     (not (find-in-tree (first binding) (rest binding)))
 
2197
                     (null (second binding))
 
2198
                     (equal body (list (list (first binding)))))
 
2199
            (funcall try-fn `(,op () ,@(cddr binding))))
 
2200
          ;; One binding -- try to remove it if not used
 
2201
          (when (and (symbolp (first binding))
 
2202
                     (not (find-in-tree (first binding) body)))
 
2203
            (funcall try-fn (first (last body))))
 
2204
        ))
 
2205
 
 
2206
 
 
2207
      ;; Try to simplify (the last form in) the body.
 
2208
      (prune (first (last body))
 
2209
             #'(lambda (form2)
 
2210
                 (funcall try-fn
 
2211
                          `(,@(butlast form) ,form2)))))))
 
2212
 
 
2213
;;; Routine to walk form, applying a function at each form
 
2214
;;; The fn is applied in preorder.  When it returns :stop, do
 
2215
;;; not descend into subforms
 
2216
 
 
2217
#|
 
2218
(defun walk (form fn)
 
2219
  (declare (type function fn))
 
2220
  (unless (eq (funcall fn form) :stop)
 
2221
    (when (consp form)
 
2222
      (let ((op (car form)))
 
2223
        (case op
 
2224
          ((let let*)
 
2225
           (walk-let form fn))
 
2226
          ((cond)
 
2227
           (dolist (clause (cdr form))
 
2228
             (walk-implicit-progn clause fn)))
 
2229
          ((multiple-value-bind)
 
2230
              (walk (third form) fn)
 
2231
              (walk-body (cdddr form) fn))
 
2232
          ((function quote declare) nil)
 
2233
          ((block the return-from)
 
2234
           (walk-implicit-progn (cddr form) fn))
 
2235
          ((case typecase)
 
2236
           (walk (cadr form) fn)
 
2237
           (dolist (clause (cddr form))
 
2238
             (walk-implicit-progn (cdr clause) fn)))
 
2239
          ((flet labels)
 
2240
           
 
2241
          
 
2242
              
 
2243
          
 
2244
|#  
 
2245
 
 
2246
;;;;;;;;;;;;;;;;;;;;;;
 
2247
;;; Convert pruned results to test cases
 
2248
 
 
2249
(defun produce-test-cases (instances &key
 
2250
                                     (stream *standard-output*)
 
2251
                                     (prefix "MISC.")
 
2252
                                     (index 1))
 
2253
  (dolist (inst instances)
 
2254
    (let* (;; (vars (getf inst :vars))
 
2255
           (vals (getf inst :vals))
 
2256
           (optimized-lambda-form (getf inst :optimized-lambda-form))
 
2257
           (unoptimized-lambda-form (getf inst :unoptimized-lambda-form))
 
2258
           (name (intern
 
2259
                  (concatenate 'string prefix (format nil "~D" index))
 
2260
                  "CL-TEST"))
 
2261
           (test-form
 
2262
            `(deftest ,name
 
2263
               (let* ((fn1 ',optimized-lambda-form)
 
2264
                      (fn2 ',unoptimized-lambda-form)
 
2265
                      (vals ',vals)
 
2266
                      (v1 (apply (compile nil fn1) vals))
 
2267
                      (v2 (apply (compile nil fn2) vals)))
 
2268
                 (if (eql v1 v2)
 
2269
                     :good
 
2270
                   (list v1 v2)))
 
2271
               :good)))
 
2272
      (print test-form stream)
 
2273
      (terpri stream)
 
2274
      (incf index)))
 
2275
  (values))