~ubuntu-branches/ubuntu/trusty/mit-scheme/trusty-proposed

« back to all changes in this revision

Viewing changes to src/sf/subst.scm

  • Committer: Package Import Robot
  • Author(s): Chris Hanson
  • Date: 2011-10-15 03:08:33 UTC
  • mfrom: (1.1.8) (3.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20111015030833-x7qc6yxuulvxbafv
Tags: 9.1-1
* New upstream.
* debian/control, debian/copyright, debian/mit-scheme-doc.*,
  debian/mit-scheme.install, debian/rules, Upstream has removed cover
  texts from documentation licenses, so merge packages mit-scheme and
  mit-scheme-doc back together.
* debian/compat: Bump to current version.
* debian/control: Bump standards-version to current and make
  necessary changes.
* debian/rules: Fix lintian warnings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4
4
    1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5
 
    2006, 2007, 2008, 2009, 2010 Massachusetts Institute of Technology
 
5
    2006, 2007, 2008, 2009, 2010, 2011 Massachusetts Institute of
 
6
    Technology
6
7
 
7
8
This file is part of MIT/GNU Scheme.
8
9
 
27
28
;;; package: (scode-optimizer integrate)
28
29
 
29
30
(declare (usual-integrations)
30
 
         (integrate-external "object" "lsets"))
 
31
         (integrate-external "object"))
31
32
 
32
33
(define *top-level-block*)
33
34
 
38
39
;;; descriptive.
39
40
(define *current-block-names*)
40
41
 
 
42
(define (ignored-variable-warning name)
 
43
  (warn (string-append "Variable \""
 
44
                       (symbol->string name)
 
45
                       "\" was declared IGNORE, but used anyway.")
 
46
        name *current-block-names*))
 
47
 
41
48
(define (integrate/top-level block expression)
42
49
  (integrate/top-level* (object/scode expression) block expression))
43
50
 
44
51
(define (integrate/top-level* scode block expression)
45
52
  (fluid-let ((*top-level-block* block)
46
 
              (*current-block-names* '()))
 
53
              (*current-block-names* '()))
47
54
    (call-with-values
48
 
        (lambda ()
49
 
          (let ((operations (operations/make))
50
 
                (environment (environment/make)))
51
 
            (if (open-block? expression)
52
 
                (integrate/open-block operations environment expression)
53
 
                (let ((operations
54
 
                       (declarations/bind operations
55
 
                                          (block/declarations block))))
56
 
                  (process-block-flags (block/flags block)
57
 
                    (lambda ()
58
 
                      (values operations
59
 
                              environment
60
 
                              (integrate/expression operations
61
 
                                                    environment
62
 
                                                    expression))))))))
 
55
        (lambda ()
 
56
          (let ((operations (operations/make))
 
57
                (environment (environment/make)))
 
58
            (if (open-block? expression)
 
59
                (integrate/open-block operations environment expression)
 
60
                (let ((operations
 
61
                       (declarations/bind operations
 
62
                                          (block/declarations block))))
 
63
                  (values operations
 
64
                          environment
 
65
                          (integrate/expression operations
 
66
                                                environment
 
67
                                                expression))))))
63
68
     (lambda (operations environment expression)
64
69
       (values operations environment
65
 
               (quotation/make scode
66
 
                               block
67
 
                               expression))))))
 
70
               (quotation/make scode
 
71
                               block
 
72
                               expression))))))
68
73
 
69
74
(define (integrate/expressions operations environment expressions)
70
75
  (map (lambda (expression)
71
 
         (integrate/expression operations environment expression))
 
76
         (integrate/expression operations environment expression))
72
77
       expressions))
73
78
 
 
79
(define (integrate/actions operations environment actions)
 
80
  (map (lambda (action)
 
81
         (if (eq? action open-block/value-marker)
 
82
             action
 
83
             (integrate/expression operations environment action)))
 
84
       actions))
 
85
 
74
86
(define (integrate/expression operations environment expression)
75
87
  ((expression/method dispatch-vector expression)
76
88
   operations environment expression))
81
93
(define define-method/integrate
82
94
  (expression/make-method-definer dispatch-vector))
83
95
 
84
 
;;;; Variables
85
 
 
 
96
;;;; ACCESS
 
97
(define-method/integrate 'ACCESS
 
98
  (lambda (operations environment expression)
 
99
    (let ((environment* (integrate/expression operations environment
 
100
                                              (access/environment expression)))
 
101
          (name (access/name expression)))
 
102
 
 
103
      (define (dont-integrate)
 
104
        (access/make (access/scode expression)
 
105
                     (access/block expression)
 
106
                     environment* name))
 
107
 
 
108
      (if (not (constant/system-global-environment? environment*))
 
109
          (dont-integrate)
 
110
          (operations/lookup-global
 
111
           operations name
 
112
           (lambda (operation info)
 
113
             (case operation
 
114
               ((#F EXPAND) (dont-integrate))
 
115
 
 
116
               ((IGNORE)
 
117
                (ignored-variable-warning name)
 
118
                (dont-integrate))
 
119
 
 
120
               ((INTEGRATE)
 
121
                (reassign name (copy/expression/intern
 
122
                                (access/block expression)
 
123
                                (integration-info/expression info))))
 
124
 
 
125
               ((INTEGRATE-OPERATOR)
 
126
                (warn "Not integrating operator in access: " name)
 
127
                (dont-integrate))
 
128
 
 
129
               (else
 
130
                (error "Unknown operation" operation))))
 
131
           dont-integrate)))))
 
132
 
 
133
;;;; ASSIGNMENT
86
134
(define-method/integrate 'ASSIGNMENT
87
135
  (lambda (operations environment assignment)
88
136
    (let ((variable (assignment/variable assignment)))
89
137
      (operations/lookup operations variable
90
 
        (lambda (operation info)
91
 
          info                          ;ignore
92
 
          (case operation
93
 
            ((INTEGRATE INTEGRATE-OPERATOR EXPAND)
94
 
             (warn "Attempt to assign integrated name"
95
 
                   (variable/name variable)))
96
 
            (else (error "Unknown operation" operation))))
97
 
        (lambda () 'DONE))
98
 
      ;; The value of an assignment is the old value
99
 
      ;; of the variable, hence, it is refernced.
 
138
       (lambda (operation info)
 
139
         info                           ;ignore
 
140
         (case operation
 
141
           ((IGNORE)
 
142
            (ignored-variable-warning (variable/name variable)))
 
143
           ((EXPAND INTEGRATE INTEGRATE-OPERATOR)
 
144
            (warn "Attempt to assign integrated name"
 
145
                  (variable/name variable)))
 
146
           (else (error "Unknown operation" operation))))
 
147
       false-procedure)
 
148
 
100
149
      (variable/reference! variable)
101
150
      (assignment/make (assignment/scode assignment)
102
 
                       (assignment/block assignment)
103
 
                       variable
104
 
                       (integrate/expression operations
105
 
                                             environment
106
 
                                             (assignment/value assignment))))))
107
 
 
108
 
(define *eager-integration-switch #f)
 
151
                       (assignment/block assignment)
 
152
                       variable
 
153
                       (integrate/expression operations
 
154
                                             environment
 
155
                                             (assignment/value assignment))))))
 
156
 
 
157
;;;; COMBINATION
 
158
(define-method/integrate 'COMBINATION
 
159
  (lambda (operations environment combination)
 
160
    (integrate/combination
 
161
     combination operations environment
 
162
     (combination/block combination)
 
163
     (combination/operator combination)
 
164
     (integrate/expressions operations
 
165
                            environment
 
166
                            (combination/operands combination)))))
 
167
 
 
168
;;;; CONDITIONAL
 
169
(define-method/integrate 'CONDITIONAL
 
170
  (lambda (operations environment expression)
 
171
    (integrate/conditional operations environment expression
 
172
                           (integrate/expression
 
173
                            operations environment
 
174
                            (conditional/predicate expression))
 
175
                           (conditional/consequent expression)
 
176
                           (conditional/alternative expression))))
 
177
 
 
178
(define sf:enable-conditional-folding? #t)
 
179
 
 
180
(define (integrate/conditional operations environment expression
 
181
                               integrated-predicate
 
182
                               consequent
 
183
                               alternative)
 
184
  (cond ((expression/call-to-not? integrated-predicate)
 
185
         ;; (if (not <e1>) <e2> <e3>) => (if <e1> <e3> <e2>)
 
186
         (integrate/conditional
 
187
          operations environment expression
 
188
          (first (combination/operands integrated-predicate))
 
189
          alternative consequent))
 
190
 
 
191
        ((sequence? integrated-predicate)
 
192
         (sequence/make
 
193
          (and expression (object/scode expression))
 
194
          (append (except-last-pair (sequence/actions integrated-predicate))
 
195
                  (list (integrate/conditional
 
196
                         operations environment #f
 
197
                         (last (sequence/actions integrated-predicate))
 
198
                         consequent
 
199
                         alternative)))))
 
200
 
 
201
        ((and (expression/never-false? integrated-predicate)
 
202
              (noisy-test sf:enable-conditional-folding?
 
203
                          "Fold constant true conditional"))
 
204
         (sequence/make
 
205
          (and expression (conditional/scode expression))
 
206
          (list integrated-predicate
 
207
                (integrate/expression operations environment consequent))))
 
208
 
 
209
        ((and (expression/always-false? integrated-predicate)
 
210
              (noisy-test sf:enable-conditional-folding?
 
211
                          "Fold constant false conditional"))
 
212
         (sequence/make
 
213
          (and expression (conditional/scode expression))
 
214
          (list integrated-predicate
 
215
                (integrate/expression operations environment alternative))))
 
216
 
 
217
        (else
 
218
         (conditional/make (and expression (conditional/scode expression))
 
219
                           integrated-predicate
 
220
                           (integrate/expression operations environment consequent)
 
221
                           (integrate/expression operations environment alternative)))))
 
222
 
 
223
;;; CONSTANT
 
224
(define-method/integrate 'CONSTANT
 
225
  (lambda (operations environment expression)
 
226
    (declare (ignore operations environment))
 
227
    expression))
 
228
 
 
229
;;; DECLARATION
 
230
(define-method/integrate 'DECLARATION
 
231
  (lambda (operations environment declaration)
 
232
    (let ((answer
 
233
           (integrate/expression
 
234
            (declarations/bind operations
 
235
                               (declaration/declarations declaration))
 
236
            environment (declaration/expression declaration))))
 
237
      (if (constant? answer)
 
238
          answer
 
239
          (declaration/make
 
240
           (declaration/scode declaration)
 
241
           (declaration/declarations declaration)
 
242
           answer)))))
 
243
 
 
244
;;; DELAY
 
245
(define-method/integrate 'DELAY
 
246
  (lambda (operations environment expression)
 
247
    (delay/make
 
248
     (delay/scode expression)
 
249
     (integrate/expression operations environment
 
250
                           (delay/expression expression)))))
 
251
 
 
252
 
 
253
;;; DISJUNCTION
 
254
(define-method/integrate 'DISJUNCTION
 
255
  (lambda (operations environment expression)
 
256
    (integrate/disjunction
 
257
     operations environment expression
 
258
     (integrate/expression
 
259
      operations environment (disjunction/predicate expression))
 
260
     (disjunction/alternative expression))))
 
261
 
 
262
(define sf:enable-disjunction-folding? #t)
 
263
 
 
264
(define (integrate/disjunction operations environment expression
 
265
                               integrated-predicate alternative)
 
266
  (cond ((expression/call-to-not? integrated-predicate)
 
267
         ;; (or (not e1) e2) => (if e1 e2 #t)
 
268
         (integrate/conditional
 
269
          operations environment expression
 
270
          (first (combination/operands integrated-predicate))
 
271
          alternative
 
272
          (constant/make #f #t)))
 
273
 
 
274
        ((and (expression/never-false? integrated-predicate)
 
275
              (noisy-test sf:enable-disjunction-folding?
 
276
                          "Fold constant true disjunction"))
 
277
         ;; (or <exp1> <exp2>) => <exp1> if <exp1> is never false
 
278
         integrated-predicate)
 
279
 
 
280
        ((and (expression/always-false? integrated-predicate)
 
281
              (noisy-test sf:enable-disjunction-folding?
 
282
                          "Fold constant false disjunction"))
 
283
         ;; (or <exp1> <exp2>)
 
284
         ;; => (begin <exp1> <exp2>) if <exp1> is always false
 
285
         (sequence/make (and expression (object/scode expression))
 
286
                        (list integrated-predicate
 
287
                              (integrate/expression
 
288
                               operations environment alternative))))
 
289
 
 
290
        ((sequence? integrated-predicate)
 
291
         (sequence/make
 
292
          (and expression (object/scode expression))
 
293
          (append (except-last-pair (sequence/actions integrated-predicate))
 
294
                  (list (integrate/disjunction
 
295
                         operations environment #f
 
296
                         (last (sequence/actions integrated-predicate))
 
297
                         alternative)))))
 
298
 
 
299
        (else
 
300
         (disjunction/make (and expression (object/scode expression))
 
301
                           integrated-predicate
 
302
                           (integrate/expression
 
303
                            operations
 
304
                            environment alternative)))))
 
305
 
 
306
;;; OPEN-BLOCK
 
307
(define-method/integrate 'OPEN-BLOCK
 
308
  (lambda (operations environment expression)
 
309
    (call-with-values
 
310
        (lambda () (integrate/open-block operations environment expression))
 
311
      (lambda (operations environment expression)
 
312
        (declare (ignore operations environment))
 
313
        expression))))
 
314
 
 
315
;;; PROCEDURE
 
316
(define-method/integrate 'PROCEDURE
 
317
  (lambda (operations environment procedure)
 
318
    (integrate/procedure operations
 
319
                         (simulate-unknown-application environment procedure)
 
320
                         procedure)))
 
321
 
 
322
;;;; Quotation
 
323
(define-method/integrate 'QUOTATION
 
324
  (lambda (operations environment expression)
 
325
    (declare (ignore operations environment))
 
326
    (integrate/quotation expression)))
 
327
 
 
328
(define (integrate/quotation quotation)
 
329
  (call-with-values
 
330
      (lambda ()
 
331
        (integrate/top-level* (quotation/scode quotation)
 
332
                              (quotation/block quotation)
 
333
                              (quotation/expression quotation)))
 
334
    (lambda (operations environment expression)
 
335
      operations environment            ;ignore
 
336
      expression)))
 
337
 
 
338
;;;; Reference
 
339
(define sf:warn-on-unintegrated-argument #f)
109
340
 
110
341
(define-method/integrate 'REFERENCE
111
342
  (lambda (operations environment expression)
112
343
    (let ((variable (reference/variable expression)))
113
 
      (letrec ((integration-success
114
 
                (lambda (new-expression)
115
 
                  (variable/integrated! variable)
116
 
                  new-expression))
117
 
               (integration-failure
118
 
                (lambda ()
119
 
                  (variable/reference! variable)
120
 
                  expression))
121
 
               (try-safe-integration
122
 
                (lambda ()
123
 
                  (integrate/name-if-safe expression expression
124
 
                                          environment operations
125
 
                                          '(INTEGRATE INTEGRATE-SAFELY)
126
 
                                          integration-success
127
 
                                          integration-failure))))
128
 
        (operations/lookup operations variable
129
 
         (lambda (operation info)
130
 
           (case operation
131
 
             ((INTEGRATE-OPERATOR EXPAND)
132
 
              (variable/reference! variable)
133
 
              expression)
134
 
             ((INTEGRATE)
135
 
              (integrate/name expression expression info environment
136
 
                              integration-success integration-failure))
137
 
             ((INTEGRATE-SAFELY)
138
 
              (try-safe-integration))
139
 
             (else
140
 
              (error "Unknown operation" operation))))
141
 
         (lambda ()
142
 
           (if *eager-integration-switch
143
 
               (try-safe-integration)
144
 
               (integration-failure))))))))
145
 
 
146
 
(define (integrate/name-if-safe expr reference environment
147
 
                                operations safe-operations if-win if-fail)
148
 
  (let ((variable (reference/variable reference)))
149
 
    (if (or (variable/side-effected variable)
150
 
            (not (block/safe? (variable/block variable))))
151
 
        (if-fail)
152
 
        (let ((finish
153
 
               (lambda (value)
154
 
                 (if (safely-integrable-value? value environment operations
155
 
                                               safe-operations)
156
 
                     (if-win
157
 
                      (reassign
158
 
                       expr
159
 
                       (copy/expression/intern (reference/block reference)
160
 
                                               value)))
161
 
                     (if-fail)))))
162
 
          (environment/lookup environment variable
163
 
            (lambda (value)
164
 
              (if (delayed-integration? value)
165
 
                  (if (delayed-integration/in-progress? value)
166
 
                      (if-fail)
167
 
                      (finish (delayed-integration/force value)))
168
 
                  (finish value)))
169
 
            (lambda () (if-fail))
170
 
            (lambda () (if-fail)))))))
 
344
      (define (dont-integrate)
 
345
        (variable/reference! variable)
 
346
        expression)
 
347
 
 
348
      (operations/lookup
 
349
       operations variable
 
350
       (lambda (operation info)
 
351
         (case operation
 
352
           ((IGNORE)
 
353
            (ignored-variable-warning (variable/name variable))
 
354
            (dont-integrate))
 
355
 
 
356
           ((EXPAND)
 
357
            (dont-integrate))
 
358
 
 
359
           ((INTEGRATE)
 
360
            (let ((new-expression
 
361
                   (integrate/name expression expression info environment)))
 
362
              (if new-expression
 
363
                  (begin (variable/integrated! variable)
 
364
                         new-expression)
 
365
                  (dont-integrate))))
 
366
 
 
367
           ((INTEGRATE-OPERATOR)
 
368
            (if sf:warn-on-unintegrated-argument
 
369
                (warn "Not integrating operator in argument position: " variable))
 
370
            (dont-integrate))
 
371
 
 
372
           (else
 
373
            (error "Unknown operation" operation))))
 
374
 
 
375
       dont-integrate))))
171
376
 
172
377
(define (reassign expr object)
173
378
  (if (and expr (object/scode expr))
174
 
      ;; Abstraction violation
175
379
      (with-new-scode (object/scode expr) object)
176
380
      object))
177
381
 
178
 
(define (safely-integrable-value? value environment operations safe-operations)
179
 
  (let check ((value value) (top? #t))
180
 
    (or (constant? value)
181
 
        (and (reference? value)
182
 
             (or (not top?)
183
 
                 (let ((variable (reference/variable value)))
184
 
                   (or (operations/lookup operations variable
185
 
                         (lambda (operation info)
186
 
                           info         ;ignore
187
 
                           (memq operation safe-operations))
188
 
                         (lambda () #f))
189
 
                       (and (not (variable/side-effected variable))
190
 
                            (block/safe? (variable/block variable))
191
 
                            (environment/lookup environment variable
192
 
                              (lambda (value*)
193
 
                                (check value* #f))
194
 
                              (lambda ()
195
 
                                ;; unknown value
196
 
                                (operations/lookup operations variable
197
 
                                  (lambda (operation info)
198
 
                                    operation info
199
 
                                    #f)
200
 
                                  (lambda ()
201
 
                                    ;; No operations
202
 
                                    #t)))
203
 
                              (lambda ()
204
 
                                ;; not found variable
205
 
                                #t))))))))))
206
 
 
207
 
(define (integrate/reference-operator expression operations environment
208
 
                                      block operator operands)
209
 
  (let ((variable (reference/variable operator)))
210
 
    (letrec ((mark-integrated!
211
 
              (lambda ()
212
 
                (variable/integrated! variable)))
213
 
             (integration-failure
214
 
              (lambda ()
215
 
                (variable/reference! variable)
216
 
                (combination/optimizing-make expression block
217
 
                                             operator operands)))
218
 
             (integration-success
219
 
              (lambda (operator)
220
 
                (mark-integrated!)
221
 
                (integrate/combination expression operations environment
222
 
                                       block operator operands)))
223
 
             (try-safe-integration
224
 
              (lambda ()
225
 
                (integrate/name-if-safe expression operator
226
 
                                        environment operations
227
 
                                        '(EXPAND INTEGRATE INTEGRATE-OPERATOR
228
 
                                                 INTEGRATE-SAFELY)
229
 
                                        integration-success
230
 
                                        integration-failure))))
231
 
      (operations/lookup operations variable
232
 
       (lambda (operation info)
233
 
         (case operation
234
 
           ((#F) (integration-failure))
235
 
           ((INTEGRATE INTEGRATE-OPERATOR)
236
 
            (integrate/name expression
237
 
                            operator info environment
238
 
                            integration-success
239
 
                            integration-failure))
240
 
           ((INTEGRATE-SAFELY)
241
 
            (try-safe-integration))
242
 
           ((EXPAND)
243
 
            (info expression
244
 
                  operands
245
 
                  (lambda (new-expression)
246
 
                    (mark-integrated!)
247
 
                    (integrate/expression operations environment
248
 
                                          new-expression))
249
 
                  integration-failure
250
 
                  (reference/block operator)))
251
 
           (else
252
 
            (error "Unknown operation" operation))))
253
 
       (lambda ()
254
 
         (if *eager-integration-switch
255
 
             (try-safe-integration)
256
 
             (integration-failure)))))))
 
382
;;; SEQUENCE
 
383
(define-method/integrate 'SEQUENCE
 
384
  (lambda (operations environment expression)
 
385
    (sequence/make
 
386
     (and expression (object/scode expression))
 
387
     (integrate/actions operations environment
 
388
                        (sequence/actions expression)))))
 
389
 
 
390
;;; THE-ENVIRONMENT
 
391
(define-method/integrate 'THE-ENVIRONMENT
 
392
  (lambda (operations environment expression)
 
393
    operations
 
394
    environment
 
395
    expression))
 
396
 
257
397
 
258
398
;;;; Binding
259
399
 
 
400
;;; If not #f, display the top-level procedure names as they are
 
401
;;; processed.  Useful for debugging.
 
402
(define sf:display-top-level-procedure-names? #f)
 
403
 
 
404
(define (maybe-displaying-name name thunk)
 
405
  (if (and sf:display-top-level-procedure-names?
 
406
           (null? *current-block-names*))
 
407
      (with-notification
 
408
       (lambda (port)
 
409
         (write-string "Integrating procedure " port)
 
410
         (write name port))
 
411
       thunk)
 
412
      (thunk)))
 
413
 
260
414
(define (integrate/open-block operations environment expression)
261
415
  (let ((variables (open-block/variables expression))
262
 
        (block (open-block/block expression)))
 
416
        (block (open-block/block expression)))
263
417
    (let ((operations
264
 
           (declarations/bind (operations/shadow operations variables)
265
 
                              (block/declarations block))))
266
 
      (process-block-flags (block/flags block)
267
 
        (lambda ()
268
 
          (call-with-values
269
 
              (lambda ()
270
 
                (environment/recursive-bind operations
271
 
                                            environment
272
 
                                            variables
273
 
                                            (open-block/values expression)))
274
 
            (lambda (environment vals)
275
 
              (let ((actions
276
 
                     (integrate/actions operations
277
 
                                        environment
278
 
                                        (open-block/actions expression))))
279
 
                ;; Complain about unreferenced variables.
280
 
                ;; If the block is unsafe, then it is likely that
281
 
                ;; there will be a lot of them on purpose (top level or
282
 
                ;; the-environment) so no complaining.
283
 
                (if (block/safe? (open-block/block expression))
284
 
                    (for-each (lambda (variable)
285
 
                                (if (variable/unreferenced? variable)
286
 
                                    (warn "Unreferenced defined variable:"
287
 
                                          (variable/name variable))))
288
 
                              variables))
289
 
                (values operations
290
 
                        environment
291
 
                        (if (open-block/optimized expression)
292
 
                            (open-block/make
293
 
                             (and expression (object/scode expression))
294
 
                             block variables
295
 
                             vals actions #t)
296
 
                            (open-block/optimizing-make
297
 
                             expression block variables vals
298
 
                             actions operations environment)))))))))))
299
 
 
300
 
(define-method/integrate 'OPEN-BLOCK
301
 
  (lambda (operations environment expression)
302
 
    (call-with-values
303
 
        (lambda () (integrate/open-block operations environment expression))
304
 
      (lambda (operations environment expression)
305
 
        operations environment
306
 
        expression))))
307
 
 
308
 
(define (process-block-flags flags continuation)
309
 
  (if (null? flags)
310
 
      (continuation)
311
 
      (let ((this-flag (car flags)))
312
 
        (case this-flag
313
 
          ((AUTOMAGIC-INTEGRATIONS)
314
 
           (fluid-let ((*eager-integration-switch #T))
315
 
             (process-block-flags (cdr flags) continuation)))
316
 
          ((NO-AUTOMAGIC-INTEGRATIONS)
317
 
           (fluid-let ((*eager-integration-switch #F))
318
 
             (process-block-flags (cdr flags) continuation)))
319
 
          ((ETA-SUBSTITUTION)
320
 
           (fluid-let ((*eta-substitution-switch #T))
321
 
             (process-block-flags (cdr flags) continuation)))
322
 
          ((NO-ETA-SUBSTITUTION)
323
 
           (fluid-let ((*eta-substitution-switch #F))
324
 
             (process-block-flags (cdr flags) continuation)))
325
 
          ((OPEN-BLOCK-OPTIMIZATIONS)
326
 
           (fluid-let ((*block-optimizing-switch #T))
327
 
             (process-block-flags (cdr flags) continuation)))
328
 
          ((NO-OPEN-BLOCK-OPTIMIZATIONS)
329
 
           (fluid-let ((*block-optimizing-switch #F))
330
 
             (process-block-flags (cdr flags) continuation)))
331
 
          (else (error "Bad flag"))))))
332
 
 
 
418
           (declarations/bind (operations/shadow operations variables)
 
419
                              (block/declarations block))))
 
420
      (call-with-values
 
421
          (lambda ()
 
422
            (environment/recursive-bind operations
 
423
                                        environment
 
424
                                        variables
 
425
                                        (open-block/values expression)))
 
426
        (lambda (environment vals)
 
427
          (let ((actions
 
428
                 (integrate/actions operations
 
429
                                    environment
 
430
                                    (open-block/actions expression))))
 
431
            ;; Complain about unreferenced variables.
 
432
            ;; If the block is unsafe, then it is likely that
 
433
            ;; there will be a lot of them on purpose (top level or
 
434
            ;; the-environment) so no complaining.
 
435
            (if (block/safe? (open-block/block expression))
 
436
                (for-each (lambda (variable)
 
437
                            (if (variable/unreferenced? variable)
 
438
                                (warn "Unreferenced defined variable:"
 
439
                                      (variable/name variable))))
 
440
                          variables))
 
441
            (values operations
 
442
                    environment
 
443
                    (open-block/make
 
444
                     (and expression (object/scode expression))
 
445
                     block variables
 
446
                     vals actions))))))))
 
447
 
333
448
(define (variable/unreferenced? variable)
334
449
  (and (not (variable/integrated variable))
335
450
       (not (variable/referenced variable))
336
 
       (not (variable/can-ignore? variable))))
337
 
 
338
 
(define-method/integrate 'PROCEDURE
339
 
  (lambda (operations environment procedure)
340
 
    (integrate/procedure operations
341
 
                         (simulate-unknown-application environment procedure)
342
 
                         procedure)))
343
 
 
344
 
;; Cannot optimize (lambda () (bar)) => bar (eta substitution) because
345
 
;; BAR may be a procedure with different arity than the lambda
346
 
 
347
 
#| You can get some weird stuff with this
348
 
 
349
 
(define (foo x)
350
 
  (define (loop1) (loop2))
351
 
  (define (loop2) (loop3))
352
 
  (define (loop3) (loop1))
353
 
  (bar x))
354
 
 
355
 
will optimize into
356
 
 
357
 
(define (foo x)
358
 
  (define loop1 loop3)
359
 
  (define loop2 loop3)
360
 
  (define loop3 loop3)
361
 
  (bar x))
362
 
 
363
 
and if you have automagic integrations on, this won't finish
364
 
optimizing.  Well, you told the machine to loop forever, and it
365
 
determines that it can do this at compile time, so you get what
366
 
you ask for.
367
 
 
368
 
|#
369
 
 
370
 
(define *eta-substitution-switch #F)
371
 
 
 
451
       (not (variable/may-ignore? variable))
 
452
       (not (variable/must-ignore? variable))))
 
453
 
372
454
(define (integrate/procedure operations environment procedure)
373
455
  (let ((block (procedure/block procedure))
374
 
        (required (procedure/required procedure))
375
 
        (optional (procedure/optional procedure))
376
 
        (rest (procedure/rest procedure)))
377
 
    (fluid-let ((*current-block-names*
378
 
                 (cons (procedure/name procedure)
379
 
                       *current-block-names*)))
380
 
      (process-block-flags (block/flags block)
381
 
        (lambda ()
382
 
          (let ((body
383
 
                 (integrate/expression
384
 
                  (declarations/bind
385
 
                   (operations/shadow
386
 
                    operations
387
 
                    (append required optional (if rest (list rest) '())))
388
 
                   (block/declarations block))
389
 
                  environment
390
 
                  (procedure/body procedure))))
391
 
            ;; Possibly complain about variables bound and not
392
 
            ;; referenced.
393
 
            (if (block/safe? block)
394
 
                (for-each (lambda (variable)
395
 
                            (if (variable/unreferenced? variable)
396
 
                                (warn "Unreferenced bound variable:"
397
 
                                      (variable/name variable)
398
 
                                      *current-block-names*)))
399
 
                          (if rest
400
 
                              (append required optional (list rest))
401
 
                              (append required optional))))
402
 
            (if (and *eta-substitution-switch
403
 
                     (combination? body)
404
 
                     (null? optional)
405
 
                     (null? rest)
406
 
                     (let ((operands (combination/operands body)))
407
 
                       (match-up? operands required))
408
 
                     (set/empty?
409
 
                      (set/intersection
410
 
                       (list->set variable? eq? required)
411
 
                       (free/expression (combination/operator body)))))
412
 
                (combination/operator body)
413
 
                (procedure/make (procedure/scode procedure)
414
 
                                block
415
 
                                (procedure/name procedure)
416
 
                                required
417
 
                                optional
418
 
                                rest
419
 
                                body))))))))
420
 
 
421
 
(define (match-up? operands required)
422
 
  (if (null? operands)
423
 
      (null? required)
424
 
      (and (not (null? required))
425
 
           (let ((this-operand (car operands))
426
 
                 (this-required (car required)))
427
 
             (and (reference? this-operand)
428
 
                  (eq? (reference/variable this-operand) this-required)
429
 
                  (match-up? (cdr operands) (cdr required)))))))
 
456
        (name  (procedure/name procedure))
 
457
        (required (procedure/required procedure))
 
458
        (optional (procedure/optional procedure))
 
459
        (rest (procedure/rest procedure)))
 
460
    (maybe-displaying-name
 
461
     name
 
462
     (lambda ()
 
463
       (fluid-let ((*current-block-names* (cons name *current-block-names*)))
 
464
         (let ((body (integrate/expression
 
465
                      (declarations/bind
 
466
                       (operations/shadow
 
467
                        operations
 
468
                        (append required optional (if rest (list rest) '())))
 
469
                       (block/declarations block))
 
470
                      environment
 
471
                      (procedure/body procedure))))
 
472
           ;; Possibly complain about variables bound and not
 
473
           ;; referenced.
 
474
           (if (block/safe? block)
 
475
               (for-each (lambda (variable)
 
476
                           (if (variable/unreferenced? variable)
 
477
                               (warn "Unreferenced bound variable:"
 
478
                                     (variable/name variable)
 
479
                                     *current-block-names*)))
 
480
                         (if rest
 
481
                             (append required optional (list rest))
 
482
                             (append required optional))))
 
483
           (procedure/make (procedure/scode procedure)
 
484
                           block
 
485
                           name
 
486
                           required
 
487
                           optional
 
488
                           rest
 
489
                           body)))))))
430
490
 
431
 
(define-method/integrate 'COMBINATION
432
 
  (lambda (operations environment combination)
433
 
    (integrate/combination
434
 
     combination operations environment
435
 
     (combination/block combination)
436
 
     (combination/operator combination)
437
 
     (integrate/expressions operations
438
 
                            environment
439
 
                            (combination/operands combination)))))
 
491
 
 
492
;;; INTEGRATE-COMBINATION
 
493
(define integrate-combination-dispatch-vector
 
494
  (expression/make-dispatch-vector))
 
495
 
 
496
(define define-method/integrate-combination
 
497
  (expression/make-method-definer integrate-combination-dispatch-vector))
440
498
 
441
499
(define (integrate/combination expression operations environment
442
 
                               block operator operands)
443
 
  (cond ((reference? operator)
444
 
         (integrate/reference-operator expression operations environment
445
 
                                       block operator operands))
446
 
        ((and (access? operator)
447
 
              (constant/system-global-environment?
448
 
               (integrate/expression operations environment (access/environment operator))))
449
 
         (integrate/access-operator expression operations environment
450
 
                                    block operator operands))
451
 
        ((and (constant? operator)
452
 
              (primitive-procedure? (constant/value operator)))
453
 
         (let ((operands*
454
 
                (and (eq? (constant/value operator) (ucode-primitive apply))
455
 
                     (integrate/hack-apply? operands))))
456
 
           (if operands*
457
 
               (integrate/combination expression operations environment
458
 
                                      block (car operands*) (cdr operands*))
459
 
               (integrate/primitive-operator expression operations environment
460
 
                                             block operator operands))))
461
 
        (else
462
 
         (combination/optimizing-make
463
 
          expression
464
 
          block
465
 
          (let* ((integrate-procedure
466
 
                  (lambda (operator)
467
 
                    (integrate/procedure-operator operations environment
468
 
                                                  block operator operands)))
469
 
                 (operator
470
 
                  (if (procedure? operator)
471
 
                      (integrate-procedure operator)
472
 
                      (let ((operator
473
 
                             (integrate/expression operations
474
 
                                                   environment
475
 
                                                   operator)))
476
 
                        (if (procedure? operator)
477
 
                            (integrate-procedure operator)
478
 
                            operator)))))
479
 
            (cond ((integrate/compound-operator operator operands)
480
 
                   => integrate-procedure)
481
 
                  (else operator)))
482
 
          operands))))
 
500
                               block operator operands)
 
501
  ((expression/method integrate-combination-dispatch-vector operator)
 
502
   expression operations environment block operator operands))
 
503
 
 
504
;;;; access-operator
 
505
(define-method/integrate-combination 'ACCESS
 
506
  (lambda (expression operations environment block operator operands)
 
507
    (integrate/access-operator expression operations environment
 
508
                               block operator operands)))
 
509
 
 
510
(define (integrate/access-operator expression operations environment block operator operands)
 
511
  (let ((name (access/name operator))
 
512
        (environment*
 
513
         (integrate/expression operations environment (access/environment operator))))
 
514
 
 
515
    (define (dont-integrate)
 
516
      (combination/make
 
517
       expression block
 
518
       (access/make (access/scode operator)
 
519
                    (access/block operator)
 
520
                    environment* name) operands))
 
521
 
 
522
    (if (not (constant/system-global-environment? environment*))
 
523
        (dont-integrate)
 
524
        (operations/lookup-global
 
525
         operations name
 
526
         (lambda (operation info)
 
527
           (case operation
 
528
             ((#F) (dont-integrate))
 
529
 
 
530
             ((EXPAND)
 
531
              (cond ((info expression operands (reference/block operator))
 
532
                     => (lambda (new-expression)
 
533
                          (integrate/expression operations environment new-expression)))
 
534
                    (else (dont-integrate))))
 
535
 
 
536
             ((IGNORE)
 
537
              (ignored-variable-warning (variable/name name))
 
538
              (dont-integrate))
 
539
 
 
540
             ((INTEGRATE INTEGRATE-OPERATOR)
 
541
              (let ((new-operator
 
542
                     (reassign operator
 
543
                               (copy/expression/intern block (integration-info/expression info)))))
 
544
                (integrate/combination expression operations environment block new-operator operands)))
 
545
 
 
546
             (else
 
547
              (error "unknown operation" operation))))
 
548
         dont-integrate))))
 
549
 
 
550
;;; assignment-operator
 
551
(define-method/integrate-combination 'ASSIGNMENT
 
552
  (lambda (expression operations environment block operator operands)
 
553
    (warn "Value of assignment used as an operator.")
 
554
    ;; We don't try to make sense of this, we just
 
555
    ;; build the code and let the runtime raise an error.
 
556
    (combination/make expression
 
557
                      block
 
558
                      (integrate/expression operations environment operator)
 
559
                      operands)))
 
560
 
 
561
;;; combination-operator
 
562
(define-method/integrate-combination 'COMBINATION
 
563
  (lambda (expression operations environment block operator operands)
 
564
    (integrate-combination/default expression operations environment block operator operands)))
 
565
 
 
566
;;; conditional-operator
 
567
(define-method/integrate-combination 'CONDITIONAL
 
568
  (lambda (expression operations environment block operator operands)
 
569
    (integrate-combination/default expression operations environment block operator operands)))
 
570
 
 
571
;;; constant-operator
 
572
(define sf:enable-elide-double-negatives? #t)
 
573
 
 
574
(define-method/integrate-combination 'CONSTANT
 
575
  (lambda (expression operations environment block operator operands)
 
576
    ;; Elide a double negative only if it doesn't change the type of the answer.
 
577
    (cond ((and (expression/constant-eq? operator (ucode-primitive not))
 
578
                (length=? operands 1)
 
579
                (expression/call-to-not? (first operands))
 
580
                (expression/boolean?
 
581
                 (first (combination/operands (first operands))))
 
582
                (noisy-test sf:enable-elide-double-negatives?
 
583
                            "Elide double negative"))
 
584
           (first (combination/operands (first operands))))
 
585
 
 
586
          ((primitive-procedure? (constant/value operator))
 
587
           (let ((operands*
 
588
                  (and (eq? (constant/value operator) (ucode-primitive apply))
 
589
                       (integrate/hack-apply? operands))))
 
590
             (if operands*
 
591
                 (integrate/combination expression operations environment
 
592
                                        block (car operands*) (cdr operands*))
 
593
                 (integrate/primitive-operator expression operations environment
 
594
                                               block operator operands))))
 
595
 
 
596
          (else
 
597
           (warn "Application of constant value" (constant/value operator))
 
598
           (integrate-combination/default expression operations environment
 
599
                                          block operator operands)))))
 
600
 
 
601
(define (integrate/primitive-operator expression operations environment
 
602
                                      block operator operands)
 
603
  (declare (ignore operations environment))
 
604
  (combination/make expression block operator operands))
 
605
 
 
606
;;; declaration-operator
 
607
(define-method/integrate-combination 'DECLARATION
 
608
  (lambda (expression operations environment block operator operands)
 
609
    (integrate-combination/default expression operations environment block operator operands)))
 
610
 
 
611
;;; delay-operator
 
612
(define-method/integrate-combination 'DELAY
 
613
  (lambda (expression operations environment block operator operands)
 
614
    ;; Nonsense - generate a warning.
 
615
    (warn "Delayed object in operator position.  This will cause a runtime error.")
 
616
    (combination/make expression
 
617
                      block
 
618
                      (integrate/expression operations environment operator)
 
619
                      operands)))
 
620
 
 
621
;;; disjunction-operator
 
622
(define-method/integrate-combination 'DISJUNCTION
 
623
  (lambda (expression operations environment block operator operands)
 
624
    (integrate-combination/default expression operations environment
 
625
                                   block operator operands)))
 
626
 
 
627
;;; open-block-operator
 
628
(define-method/integrate-combination 'OPEN-BLOCK
 
629
  (lambda (expression operations environment block operator operands)
 
630
    (declare (ignore expression operations environment block operator operands))
 
631
    ;; This shouldn't be possible.
 
632
    (error "INTERNAL-ERROR: integrate-combination 'open-block")))
 
633
 
 
634
;;; procedure-operator (let)
 
635
(define-method/integrate-combination 'PROCEDURE
 
636
  (lambda (expression operations environment block operator operands)
 
637
    (integrate-combination/default expression operations environment
 
638
                                   block operator operands)))
483
639
 
484
640
(define (integrate/procedure-operator operations environment
485
 
                                      block procedure operands)
 
641
                                      block procedure operands)
486
642
  (integrate/procedure operations
487
 
                       (simulate-application environment block
488
 
                                             procedure operands)
489
 
                       procedure))
490
 
 
491
 
(define (integrate/primitive-operator expression operations environment
492
 
                                      block operator operands)
493
 
  (let ((integration-failure
494
 
         (lambda ()
495
 
           (combination/optimizing-make expression block operator operands))))
496
 
    (operations/lookup operations (constant/value operator)
497
 
      (lambda (operation info)
498
 
        (case operation
499
 
          ((#F) (integration-failure))
500
 
          ((EXPAND)
501
 
           (info expression
502
 
                 operands
503
 
                 (lambda (expression)
504
 
                   (integrate/expression operations environment expression))
505
 
                 integration-failure
506
 
                 block))
507
 
          (else (error "Unknown operation" operation))))
508
 
      integration-failure)))
 
643
                       (simulate-application environment block
 
644
                                             procedure operands)
 
645
                       procedure))
 
646
 
 
647
;;; quotation-operator
 
648
(define-method/integrate-combination 'QUOTATION
 
649
  (lambda (expression operations environment block operator operands)
 
650
    (integrate-combination/default expression operations environment
 
651
                                   block operator operands)))
 
652
 
 
653
;;; reference-operator
 
654
(define-method/integrate-combination 'REFERENCE
 
655
  (lambda (expression operations environment block operator operands)
 
656
    (integrate/reference-operator expression operations environment
 
657
                                  block operator operands)))
 
658
 
 
659
(define (integrate/reference-operator expression operations environment
 
660
                                      block operator operands)
 
661
  (let ((variable (reference/variable operator)))
 
662
    (let ((integration-failure
 
663
           (lambda ()
 
664
             (variable/reference! variable)
 
665
             (combination/make expression block operator operands))))
 
666
      (operations/lookup operations variable
 
667
        (lambda (operation info)
 
668
          (case operation
 
669
            ((#F) (integration-failure))
 
670
 
 
671
            ((EXPAND)
 
672
             (let ((new-expression (info expression operands (reference/block operator))))
 
673
               (if new-expression
 
674
                   (begin
 
675
                     (variable/integrated! variable)
 
676
                     (integrate/expression operations environment new-expression))
 
677
                   (integration-failure))))
 
678
 
 
679
            ((IGNORE)
 
680
             (ignored-variable-warning (variable/name variable))
 
681
             (integration-failure))
 
682
 
 
683
            ((INTEGRATE INTEGRATE-OPERATOR)
 
684
             (let ((new-expression (integrate/name expression
 
685
                                                   operator info environment)))
 
686
               (if new-expression
 
687
                   (begin
 
688
                     (variable/integrated! variable)
 
689
                     (integrate/combination expression operations environment
 
690
                                            block new-expression operands))
 
691
                   (integration-failure))))
 
692
 
 
693
            (else
 
694
             (error "Unknown operation" operation))))
 
695
        integration-failure))))
 
696
 
 
697
;;; sequence-operator
 
698
(define-method/integrate-combination 'SEQUENCE
 
699
  (lambda (expression operations environment block operator operands)
 
700
    (integrate-combination/default expression operations environment
 
701
                                   block operator operands)))
 
702
 
 
703
;;; the-environment-operator
 
704
(define-method/integrate-combination 'THE-ENVIRONMENT
 
705
  (lambda (expression operations environment block operator operands)
 
706
    (warn "(THE-ENVIRONMENT) used as an operator.  Will cause a runtime error.")
 
707
    (combination/make expression block
 
708
                      (integrate/expression operations environment operator)
 
709
                      operands)))
 
710
 
 
711
(define (integrate-combination/default expression operations environment
 
712
                                       block operator operands)
 
713
  (combination/make
 
714
   expression
 
715
   block
 
716
   (let* ((integrate-procedure
 
717
           (lambda (operator)
 
718
             (integrate/procedure-operator operations environment
 
719
                                           block operator operands)))
 
720
          (operator
 
721
           (if (procedure? operator)
 
722
               (integrate-procedure operator)
 
723
               (let ((operator
 
724
                      (integrate/expression operations
 
725
                                            environment
 
726
                                            operator)))
 
727
                 (if (procedure? operator)
 
728
                     (integrate-procedure operator)
 
729
                     operator)))))
 
730
     (cond ((integrate/compound-operator operator operands)
 
731
            => integrate-procedure)
 
732
           (else operator)))
 
733
   operands))
 
734
 
 
735
(define (integrate/hack-apply? operands)
 
736
  (define (check operand)
 
737
    (cond ((constant? operand)
 
738
           (if (null? (constant/value operand))
 
739
               '()
 
740
               'FAIL))
 
741
          ((not (combination? operand))
 
742
           'FAIL)
 
743
          (else
 
744
           (let ((rator (combination/operator operand)))
 
745
             (if (or (and (constant? rator)
 
746
                          (eq? (ucode-primitive cons)
 
747
                               (constant/value rator)))
 
748
                     (eq? 'cons (global-ref? rator)))
 
749
                 (let* ((rands (combination/operands operand))
 
750
                        (next (check (cadr rands))))
 
751
                   (if (eq? next 'FAIL)
 
752
                       'FAIL
 
753
                       (cons (car rands) next)))
 
754
                 'FAIL)))))
 
755
 
 
756
  (and (not (null? operands))
 
757
       (let ((tail (check (car (last-pair operands)))))
 
758
         (and (not (eq? tail 'FAIL))
 
759
              (append (except-last-pair operands)
 
760
                      tail)))))
 
761
 
509
762
 
510
763
;;; ((let ((a (foo)) (b (bar)))
511
764
;;;    (lambda (receiver)
553
806
(define (integrate/compound-operator operator operands)
554
807
  (define (scan-body body encloser)
555
808
    (if (procedure? body)
556
 
        (and (not (open-block? (procedure/body body)))
557
 
             (procedure-with-body body (encloser (procedure/body body))))
558
 
        (scan-operator body encloser)))
 
809
        (and (not (open-block? (procedure/body body)))
 
810
             (procedure-with-body body (encloser (procedure/body body))))
 
811
        (scan-operator body encloser)))
559
812
  (define (scan-operator operator encloser)
560
813
    (cond ((sequence? operator)
561
 
           (let ((reversed-actions (reverse (sequence/actions operator))))
562
 
             (scan-body (car reversed-actions)
563
 
                        (let ((commands (cdr reversed-actions)))
564
 
                          (lambda (expression)
565
 
                            (encloser
566
 
                             (sequence-with-actions
567
 
                              operator
568
 
                              (reverse (cons expression commands)))))))))
569
 
          ((combination? operator)
570
 
           (let ((descend
571
 
                  (lambda (operator*)
572
 
                    (and (not (open-block? (procedure/body operator*)))
573
 
                         (scan-body
574
 
                          (procedure/body operator*)
575
 
                          (lambda (body*)
576
 
                            (encloser
577
 
                             (combination-with-operator
578
 
                              operator
579
 
                              (procedure-with-body operator* body*))))))))
580
 
                 (operator* (combination/operator operator)))
581
 
             (cond ((procedure? operator*) (descend operator*))
582
 
                   ((integrate/compound-operator
583
 
                     operator*
584
 
                     (combination/operands operator))
585
 
                    => descend)
586
 
                   (else #f))))
587
 
          ((declaration? operator)
588
 
           (scan-body (declaration/expression operator)
589
 
                      (lambda (expression)
590
 
                        (encloser
591
 
                         (declaration-with-expression operator expression)))))
592
 
          (else #f)))
593
 
  (and (for-all? operands non-side-effecting?)
 
814
           (let ((reversed-actions (reverse (sequence/actions operator))))
 
815
             (scan-body (car reversed-actions)
 
816
                        (let ((commands (cdr reversed-actions)))
 
817
                          (lambda (expression)
 
818
                            (encloser
 
819
                             (sequence-with-actions
 
820
                              operator
 
821
                              (reverse (cons expression commands)))))))))
 
822
          ((combination? operator)
 
823
           (let ((descend
 
824
                  (lambda (operator*)
 
825
                    (and (not (open-block? (procedure/body operator*)))
 
826
                         (scan-body
 
827
                          (procedure/body operator*)
 
828
                          (lambda (body*)
 
829
                            (encloser
 
830
                             (combination-with-operator
 
831
                              operator
 
832
                              (procedure-with-body operator* body*))))))))
 
833
                 (operator* (combination/operator operator)))
 
834
             (cond ((procedure? operator*) (descend operator*))
 
835
                   ((integrate/compound-operator
 
836
                     operator*
 
837
                     (combination/operands operator))
 
838
                    => descend)
 
839
                   (else #f))))
 
840
          ((declaration? operator)
 
841
           (scan-body (declaration/expression operator)
 
842
                      (lambda (expression)
 
843
                        (encloser
 
844
                         (declaration-with-expression operator expression)))))
 
845
          (else #f)))
 
846
  (and (for-all? operands expression/effect-free?)
594
847
       (scan-operator operator (lambda (body) body))))
595
848
 
596
849
(define (combination-with-operator combination operator)
597
 
  (combination/make (combination/scode combination)
598
 
                    (combination/block combination)
599
 
                    operator
600
 
                    (combination/operands combination)))
 
850
  (combination/make combination
 
851
                    (combination/block combination)
 
852
                    operator
 
853
                    (combination/operands combination)))
601
854
 
602
855
(define (declaration-with-expression declaration expression)
603
856
  (declaration/make (declaration/scode declaration)
604
 
                    (declaration/declarations declaration)
605
 
                    expression))
 
857
                    (declaration/declarations declaration)
 
858
                    expression))
606
859
 
607
860
;;; Replacing the body may cause variables from outside the original
608
861
;;; body to be shadowed, so we use a sleazy stupid hack to work around
615
868
  (for-each hackify-variable (procedure/optional procedure))
616
869
  (cond ((procedure/rest procedure) => hackify-variable))
617
870
  (procedure/make (procedure/scode procedure)
618
 
                  (procedure/block procedure)
619
 
                  (procedure/name procedure)
620
 
                  (procedure/required procedure)
621
 
                  (procedure/optional procedure)
622
 
                  (procedure/rest procedure)
623
 
                  body))
 
871
                  (procedure/block procedure)
 
872
                  (procedure/name procedure)
 
873
                  (procedure/required procedure)
 
874
                  (procedure/optional procedure)
 
875
                  (procedure/rest procedure)
 
876
                  body))
624
877
 
625
878
(define (hackify-variable variable)
626
879
  (set-variable/name!
630
883
(define (sequence-with-actions sequence actions)
631
884
  (sequence/make (sequence/scode sequence) actions))
632
885
 
633
 
(define (non-side-effecting? expression)
634
 
  (or (reference? expression)
635
 
      (non-side-effecting-in-sequence? expression)))
636
 
 
637
 
(define-method/integrate 'DECLARATION
638
 
  (lambda (operations environment declaration)
639
 
    (let ((declarations (declaration/declarations declaration))
640
 
          (expression (declaration/expression declaration)))
641
 
      (declaration/make
642
 
       (declaration/scode declaration)
643
 
       declarations
644
 
       (integrate/expression (declarations/bind operations declarations)
645
 
                             environment
646
 
                             expression)))))
647
 
 
648
 
;;;; Easy Cases
649
 
 
650
 
(define-method/integrate 'CONSTANT
651
 
  (lambda (operations environment expression)
652
 
    operations
653
 
    environment
654
 
    expression))
655
 
 
656
 
(define-method/integrate 'THE-ENVIRONMENT
657
 
  (lambda (operations environment expression)
658
 
    operations
659
 
    environment
660
 
    expression))
661
 
 
662
 
(define-method/integrate 'QUOTATION
663
 
  (lambda (operations environment expression)
664
 
    operations
665
 
    environment
666
 
    (integrate/quotation expression)))
667
 
 
668
 
;; Optimize (if #f a b) => b; (if #t a b) => a
669
 
;;   (if (let (...) t) a b) => (let (...) (if t a b))
670
 
;;   (if (begin ... t) a b) => (begin ... (if t a b))
671
 
 
672
 
(define-method/integrate 'CONDITIONAL
673
 
  (lambda (operations environment expression)
674
 
    (let ((predicate (integrate/expression
675
 
                      operations environment
676
 
                      (conditional/predicate expression)))
677
 
          (consequent (integrate/expression
678
 
                       operations environment
679
 
                       (conditional/consequent expression)))
680
 
          (alternative (integrate/expression
681
 
                        operations environment
682
 
                        (conditional/alternative expression))))
683
 
      (let loop ((predicate predicate))
684
 
        (cond ((constant? predicate)
685
 
               (if (constant/value predicate)
686
 
                   consequent
687
 
                   alternative))
688
 
              ((sequence? predicate)
689
 
               (sequence-with-actions
690
 
                predicate
691
 
                (let ((actions (reverse (sequence/actions predicate))))
692
 
                  (reverse
693
 
                   (cons (loop (car actions))
694
 
                         (cdr actions))))))
695
 
              ((and (combination? predicate)
696
 
                    (procedure? (combination/operator predicate))
697
 
                    (not
698
 
                     (open-block?
699
 
                      (procedure/body (combination/operator predicate)))))
700
 
               (combination-with-operator
701
 
                predicate
702
 
                (procedure-with-body
703
 
                 (combination/operator predicate)
704
 
                 (loop (procedure/body (combination/operator predicate))))))
705
 
              (else
706
 
               (conditional/make (conditional/scode expression)
707
 
                                 predicate consequent alternative)))))))
708
 
 
709
 
;; Optimize (or #f a) => a; (or #t a) => #t
710
 
 
711
 
(define-method/integrate 'DISJUNCTION
712
 
  (lambda (operations environment expression)
713
 
    (let ((predicate (integrate/expression operations environment
714
 
                                           (disjunction/predicate expression)))
715
 
          (alternative (integrate/expression
716
 
                        operations environment
717
 
                        (disjunction/alternative expression))))
718
 
      (if (constant? predicate)
719
 
          (if (constant/value predicate)
720
 
              predicate
721
 
              alternative)
722
 
          (disjunction/make (disjunction/scode expression)
723
 
                            predicate alternative)))))
724
 
 
725
 
(define-method/integrate 'SEQUENCE
726
 
  (lambda (operations environment expression)
727
 
    ;; Optimize (begin (foo)) => (foo)
728
 
    ;; Optimize (begin a b (foo) 22 (bar)) => (begin (foo) (bar))
729
 
    (sequence/optimizing-make
730
 
     expression
731
 
     (integrate/actions operations environment
732
 
                        (sequence/actions expression)))))
733
 
 
734
 
(define (integrate/actions operations environment actions)
735
 
  (let ((action (car actions)))
736
 
    (if (null? (cdr actions))
737
 
        (list (if (eq? action open-block/value-marker)
738
 
                  action
739
 
                  (integrate/expression operations environment action)))
740
 
        (cons (cond ((reference? action)
741
 
                     ;; This clause lets you ignore a variable by
742
 
                     ;; mentioning it in a sequence.
743
 
                     (variable/can-ignore! (reference/variable action))
744
 
                     action)
745
 
                    ((eq? action open-block/value-marker)
746
 
                     action)
747
 
                    (else
748
 
                     (integrate/expression operations environment action)))
749
 
              (integrate/actions operations environment (cdr actions))))))
750
 
 
751
 
(define (sequence/optimizing-make expression actions)
752
 
  (let ((actions (remove-non-side-effecting actions)))
753
 
    (if (null? (cdr actions))
754
 
        (car actions)
755
 
        (sequence/make (and expression (object/scode expression))
756
 
                       actions))))
757
 
 
758
 
(define (remove-non-side-effecting actions)
759
 
  ;; Do not remove references from sequences, because they have
760
 
  ;; meaning as declarations.  The output code generator will take
761
 
  ;; care of removing them when they are no longer needed.
762
 
  (if (null? (cdr actions))
763
 
      actions
764
 
      (let ((rest (remove-non-side-effecting (cdr actions))))
765
 
        (if (non-side-effecting-in-sequence? (car actions))
766
 
            rest
767
 
            (cons (car actions) rest)))))
768
 
 
769
 
(define (non-side-effecting-in-sequence? expression)
770
 
  ;; Compiler does a better job of this because it is smarter about
771
 
  ;; what kinds of expressions can cause side effects.  But this
772
 
  ;; should be adequate to catch most of the simple cases.
773
 
  (or (constant? expression)
774
 
      (quotation? expression)
775
 
      (delay? expression)
776
 
      (procedure? expression)
777
 
      (and (access? expression)
778
 
           (non-side-effecting-in-sequence? (access/environment expression)))))
779
 
 
780
 
(define-method/integrate 'ACCESS
781
 
  (lambda (operations environment expression)
782
 
    (let ((environment* (integrate/expression operations environment
783
 
                                              (access/environment expression)))
784
 
          (name (access/name expression)))
785
 
      (cond ((and (constant/system-global-environment? environment*)
786
 
                  (assq name usual-integrations/constant-alist))
787
 
             => (lambda (entry)
788
 
                  (constant/make (access/scode expression)
789
 
                                 (constant/value (cdr entry)))))
790
 
            (else (access/make (access/scode expression)
791
 
                               environment* name))))))
792
 
 
793
886
(define (constant/system-global-environment? expression)
794
887
  (and (constant? expression)
795
888
       (system-global-environment? (constant/value expression))))
796
 
 
797
 
(define-method/integrate 'DELAY
798
 
  (lambda (operations environment expression)
799
 
    (delay/make
800
 
     (delay/scode expression)
801
 
     (integrate/expression operations environment
802
 
                           (delay/expression expression)))))
803
 
 
804
 
(define (integrate/quotation quotation)
805
 
  (call-with-values
806
 
      (lambda ()
807
 
        (integrate/top-level* (quotation/scode quotation)
808
 
                              (quotation/block quotation)
809
 
                              (quotation/expression quotation)))
810
 
    (lambda (operations environment expression)
811
 
      operations environment            ;ignore
812
 
      expression)))
813
 
 
814
 
(define (integrate/access-operator expression operations environment
815
 
                                   block operator operands)
816
 
  (let ((name (access/name operator))
817
 
        (dont-integrate
818
 
         (lambda ()
819
 
           (combination/make
820
 
            (and expression (object/scode expression))
821
 
            block
822
 
            (integrate/expression operations environment operator)
823
 
            (integrate/expressions operations environment operands)))))
824
 
    (cond ((and (eq? name 'APPLY)
825
 
                (integrate/hack-apply? operands))
826
 
           => (lambda (operands*)
827
 
                (integrate/combination expression operations environment
828
 
                                       block (car operands*) (cdr operands*))))
829
 
          ((assq name usual-integrations/constant-alist)
830
 
           => (lambda (entry)
831
 
                (integrate/combination expression operations environment
832
 
                                       block (cdr entry) operands)))
833
 
          ((assq name usual-integrations/expansion-alist)
834
 
           => (lambda (entry)
835
 
                ((cdr entry) expression operands
836
 
                             identity-procedure dont-integrate #f)))
837
 
          (else
838
 
           (dont-integrate)))))
839
889
 
840
890
;;;; Environment
841
891
 
844
894
  ;; integrate one another.  When circularities are detected within
845
895
  ;; the definition-reference graph, integration is disabled.
846
896
  (let ((vals
847
 
         (map (lambda (value)
848
 
                (delayed-integration/make operations value))
849
 
              vals)))
 
897
         (map (lambda (value)
 
898
                (delayed-integration/make operations value))
 
899
              vals)))
850
900
    (let ((environment
851
 
           (environment/bind-multiple environment variables vals)))
 
901
           (environment/bind-multiple environment variables vals)))
852
902
      (for-each (lambda (value)
853
 
                  (set-delayed-integration/environment! value environment))
854
 
                vals)
 
903
                  (set-delayed-integration/environment! value environment))
 
904
                vals)
855
905
      (values environment (map delayed-integration/force vals)))))
856
906
 
857
 
(define (integrate/name expr reference info environment if-integrated if-not)
 
907
(define (integrate/name expr reference info environment)
858
908
  (let ((variable (reference/variable reference)))
859
909
    (let ((finish
860
 
           (lambda (value)
861
 
             (if-integrated
862
 
              (reassign
863
 
               expr
864
 
               (copy/expression/intern (reference/block reference) value))))))
 
910
           (lambda (value)
 
911
             (reassign
 
912
              expr
 
913
              (copy/expression/intern (reference/block reference) value)))))
865
914
      (if info
866
 
          (finish (integration-info/expression info))
867
 
          (environment/lookup environment variable
868
 
            (lambda (value)
869
 
              (if (delayed-integration? value)
870
 
                  (if (delayed-integration/in-progress? value)
871
 
                      (if-not)
872
 
                      (finish (delayed-integration/force value)))
873
 
                  (finish value)))
874
 
            if-not
875
 
            if-not)))))
 
915
          (finish (integration-info/expression info))
 
916
          (environment/lookup environment variable
 
917
            (lambda (value)
 
918
              (if (delayed-integration? value)
 
919
                  (if (delayed-integration/in-progress? value)
 
920
                      #f
 
921
                      (finish (delayed-integration/force value)))
 
922
                  (finish value)))
 
923
            false-procedure
 
924
            false-procedure)))))
876
925
 
877
926
(define (variable/final-value variable environment if-value if-not)
878
927
  (environment/lookup environment variable
879
928
    (lambda (value)
880
929
      (if (delayed-integration? value)
881
 
          (if (delayed-integration/in-progress? value)
882
 
              (error "Unfinished integration" value)
883
 
              (if-value (delayed-integration/force value)))
884
 
          (if-value value)))
885
 
    (lambda ()
886
 
      (if-not))
 
930
          (if (delayed-integration/in-progress? value)
 
931
              (error "Unfinished integration" value)
 
932
              (if-value (delayed-integration/force value)))
 
933
          (if-value value)))
 
934
    if-not
887
935
    (lambda ()
888
936
      (warn "Unable to integrate" (variable/name variable))
889
937
      (if-not))))
890
938
 
891
 
(define *unknown-value "Unknown Value")
892
 
 
893
 
(define (simulate-unknown-application environment procedure)
894
 
  (define (bind-required environment required)
895
 
    (if (null? required)
896
 
        (bind-optional environment (procedure/optional procedure))
897
 
        (bind-required
898
 
         (environment/bind environment (car required) *unknown-value)
899
 
         (cdr required))))
900
 
 
901
 
  (define (bind-optional environment optional)
902
 
    (if (null? optional)
903
 
        (bind-rest environment (procedure/rest procedure))
904
 
        (bind-optional
905
 
         (environment/bind environment (car optional) *unknown-value)
906
 
         (cdr optional))))
907
 
 
908
 
  (define (bind-rest environment rest)
909
 
    (if (null? rest)
910
 
        environment
911
 
        (environment/bind environment rest *unknown-value)))
912
 
 
913
 
  (bind-required environment (procedure/required procedure)))
914
 
 
915
 
(define (integrate/hack-apply? operands)
916
 
  (define (check operand)
917
 
    (cond ((constant? operand)
918
 
           (if (null? (constant/value operand))
919
 
               '()
920
 
               'FAIL))
921
 
          ((not (combination? operand))
922
 
           'FAIL)
923
 
          (else
924
 
           (let ((rator (combination/operator operand)))
925
 
             (if (or (and (constant? rator)
926
 
                          (eq? (ucode-primitive cons)
927
 
                               (constant/value rator)))
928
 
                     (eq? 'cons (global-ref? rator)))
929
 
                 (let* ((rands (combination/operands operand))
930
 
                        (next (check (cadr rands))))
931
 
                   (if (eq? next 'FAIL)
932
 
                       'FAIL
933
 
                       (cons (car rands) next)))
934
 
                 'FAIL)))))
935
 
 
936
 
  (and (not (null? operands))
937
 
       (let ((tail (check (car (last-pair operands)))))
938
 
         (and (not (eq? tail 'FAIL))
939
 
              (append (except-last-pair operands)
940
 
                      tail)))))
941
 
 
942
 
(define (simulate-application environment block procedure operands)
943
 
  (define (procedure->pretty procedure)
944
 
    (if (procedure/scode procedure)
945
 
        (unsyntax (procedure/scode procedure))
946
 
        (let ((arg-list (append (procedure/required procedure)
947
 
                                (if (null? (procedure/optional procedure))
948
 
                                    '()
949
 
                                    (cons lambda-tag:optional
950
 
                                          (procedure/optional procedure)))
951
 
                                (if (not (procedure/rest procedure))
952
 
                                    '()
953
 
                                    (procedure/rest procedure)))))
954
 
          (if (procedure/name procedure)
955
 
              `(named-lambda (,(procedure/name procedure) ,@arg-list)
956
 
                 ...)
957
 
              `(lambda ,arg-list
958
 
                 ...)))))
959
 
 
960
 
  (define (match-required environment required operands)
961
 
    (cond ((null? required)
962
 
           (match-optional environment
963
 
                           (procedure/optional procedure)
964
 
                           operands))
965
 
          ((null? operands)
966
 
           (error "Too few operands in call to procedure"
967
 
                  procedure
968
 
                  (procedure->pretty procedure)))
969
 
          (else
970
 
           (match-required (environment/bind environment
971
 
                                             (car required)
972
 
                                             (car operands))
973
 
                           (cdr required)
974
 
                           (cdr operands)))))
975
 
 
976
 
  (define (match-optional environment optional operands)
977
 
    (cond ((null? optional)
978
 
           (match-rest environment (procedure/rest procedure) operands))
979
 
          ((null? operands)
980
 
           (match-rest environment (procedure/rest procedure) '()))
981
 
          (else
982
 
           (match-optional (environment/bind environment
983
 
                                             (car optional)
984
 
                                             (car operands))
985
 
                           (cdr optional)
986
 
                           (cdr operands)))))
987
 
 
988
 
  (define (listify-tail operands)
989
 
    (let ((const-null (constant/make #f '())))
990
 
      (if (null? operands)
991
 
          const-null
992
 
          (let ((const-cons (constant/make #f (ucode-primitive cons))))
993
 
            (let walk ((operands operands))
994
 
              (if (null? operands)
995
 
                  const-null
996
 
                  (combination/make #f
997
 
                                    block
998
 
                                    const-cons
999
 
                                    (list (car operands)
1000
 
                                          (walk (cdr operands))))))))))
1001
 
 
1002
 
  (define (match-rest environment rest operands)
1003
 
    (cond (rest
1004
 
           (environment/bind environment rest (listify-tail operands)))
1005
 
          ((null? operands)
1006
 
           environment)
1007
 
          (else
1008
 
           (error "Too many operands in call to procedure"
1009
 
                  procedure
1010
 
                  (procedure->pretty procedure)))))
1011
 
 
1012
 
  (match-required environment (procedure/required procedure) operands))
1013
 
 
1014
 
(define (environment/make)
1015
 
  '())
1016
 
 
1017
 
(define-integrable (environment/bind environment variable value)
1018
 
  (cons (cons variable value) environment))
1019
 
 
1020
 
(define-integrable (environment/bind-multiple environment variables values)
1021
 
  (map* environment cons variables values))
1022
 
 
1023
 
(define (environment/lookup environment variable if-found if-unknown if-not)
1024
 
  (let ((association (assq variable environment)))
1025
 
    (if association
1026
 
        (if (eq? (cdr association) *unknown-value)
1027
 
            (if-unknown)
1028
 
            (if-found (cdr association)))
1029
 
        (if-not))))
1030
939
 
1031
940
(define (delayed-integration/in-progress? delayed-integration)
1032
941
  (eq? (delayed-integration/state delayed-integration) 'BEING-INTEGRATED))
1035
944
  (case (delayed-integration/state delayed-integration)
1036
945
    ((NOT-INTEGRATED)
1037
946
     (let ((value
1038
 
            (let ((environment
1039
 
                   (delayed-integration/environment delayed-integration))
1040
 
                  (operations
1041
 
                   (delayed-integration/operations delayed-integration))
1042
 
                  (expression (delayed-integration/value delayed-integration)))
1043
 
              (set-delayed-integration/state! delayed-integration
1044
 
                                              'BEING-INTEGRATED)
1045
 
              (set-delayed-integration/environment! delayed-integration #f)
1046
 
              (set-delayed-integration/operations! delayed-integration #f)
1047
 
              (set-delayed-integration/value! delayed-integration #f)
1048
 
              (integrate/expression operations environment expression))))
 
947
            (let ((environment
 
948
                   (delayed-integration/environment delayed-integration))
 
949
                  (operations
 
950
                   (delayed-integration/operations delayed-integration))
 
951
                  (expression (delayed-integration/value delayed-integration)))
 
952
              (set-delayed-integration/state! delayed-integration
 
953
                                              'BEING-INTEGRATED)
 
954
              (set-delayed-integration/environment! delayed-integration #f)
 
955
              (set-delayed-integration/operations! delayed-integration #f)
 
956
              (set-delayed-integration/value! delayed-integration #f)
 
957
              (integrate/expression operations environment expression))))
1049
958
       (set-delayed-integration/state! delayed-integration 'INTEGRATED)
1050
959
       (set-delayed-integration/value! delayed-integration value)))
1051
960
    ((INTEGRATED) 'DONE)
1052
961
    ((BEING-INTEGRATED)
1053
962
     (error "Attempt to re-force delayed integration"
1054
 
            delayed-integration))
 
963
            delayed-integration))
1055
964
    (else
1056
965
     (error "Delayed integration has unknown state"
1057
 
            delayed-integration)))
1058
 
  (delayed-integration/value delayed-integration))
1059
 
 
1060
 
;;;; Optimizations
1061
 
 
1062
 
#|
1063
 
Simple LET-like combination.  Delete any unreferenced
1064
 
parameters.  If no parameters remain, delete the
1065
 
combination and lambda.  Values bound to the unreferenced
1066
 
parameters are pulled out of the combination.  But integrated
1067
 
forms are simply removed.
1068
 
 
1069
 
(define (foo a)
1070
 
  (let ((a (+ a 3))
1071
 
        (b (bar a))
1072
 
        (c (baz a)))
1073
 
    (declare (integrate c))
1074
 
    (+ c a)))
1075
 
 
1076
 
        ||
1077
 
        \/
1078
 
 
1079
 
(define (foo a)
1080
 
  (bar a)
1081
 
  (let ((a (+ a 3)))
1082
 
    (+ (baz a) a)))
1083
 
 
1084
 
|#
1085
 
 
1086
 
(define (foldable-constant? thing)
1087
 
  (constant? thing))
1088
 
 
1089
 
(define (foldable-constants? list)
1090
 
  (or (null? list)
1091
 
      (and (foldable-constant? (car list))
1092
 
           (foldable-constants? (cdr list)))))
1093
 
 
1094
 
(define (foldable-constant-value thing)
1095
 
  (cond ((constant? thing)
1096
 
         (constant/value thing))
1097
 
        (else
1098
 
         (error "foldable-constant-value: can't happen" thing))))
1099
 
 
1100
 
(define *foldable-primitive-procedures
1101
 
  (map make-primitive-procedure
1102
 
       '(OBJECT-TYPE OBJECT-TYPE?
1103
 
         NOT EQ? NULL? PAIR? ZERO? POSITIVE? NEGATIVE?
1104
 
         &= &< &> &+ &- &* &/ 1+ -1+)))
1105
 
 
1106
 
(define (foldable-operator? operator)
1107
 
  (and (constant? operator)
1108
 
       (primitive-procedure? (constant/value operator))
1109
 
       (memq (constant/value operator) *foldable-primitive-procedures)))
1110
 
 
1111
 
;;; deal with (let () (define ...))
1112
 
;;; deal with (let ((x 7)) (let ((y 4)) ...)) => (let ((x 7) (y 4)) ...)
1113
 
;;; Actually, we really don't want to hack with these for various
1114
 
;;; reasons
1115
 
 
1116
 
(define (combination/optimizing-make expression block operator operands)
1117
 
  (cond (
1118
 
         ;; fold constants
1119
 
         (and (foldable-operator? operator)
1120
 
              (foldable-constants? operands))
1121
 
         (constant/make (and expression (object/scode expression))
1122
 
                        (apply (constant/value operator)
1123
 
                               (map foldable-constant-value operands))))
1124
 
 
1125
 
        (
1126
 
         ;; (force (delay x)) ==> x
1127
 
         (and (constant? operator)
1128
 
              (eq? (constant/value operator) force)
1129
 
              (= (length operands) 1)
1130
 
              (delay? (car operands)))
1131
 
         (delay/expression (car operands)))
1132
 
 
1133
 
        ((and (procedure? operator)
1134
 
              (block/safe? (procedure/block operator))
1135
 
              (for-all? (declarations/original
1136
 
                         (block/declarations (procedure/block operator)))
1137
 
                declarations/known?)
1138
 
              (for-all? (procedure/optional operator)
1139
 
                variable/integrated)
1140
 
              (or (not (procedure/rest operator))
1141
 
                  (variable/integrated (procedure/rest operator))))
1142
 
         (delete-unreferenced-parameters
1143
 
          (append (procedure/required operator)
1144
 
                  (procedure/optional operator))
1145
 
          (procedure/rest operator)
1146
 
          (procedure/body operator)
1147
 
          operands
1148
 
          (lambda (required referenced-operands unreferenced-operands)
1149
 
            (let ((form
1150
 
                   (if (and (null? required)
1151
 
                            ;; need to avoid things like this
1152
 
                            ;; (foo bar (let () (define (baz) ..) ..))
1153
 
                            ;; optimizing into
1154
 
                            ;; (foo bar (define (baz) ..) ..)
1155
 
                            (not (open-block? (procedure/body operator))))
1156
 
                       (reassign expression (procedure/body operator))
1157
 
                       (combination/make
1158
 
                        (and expression (object/scode expression))
1159
 
                        block
1160
 
                        (procedure/make
1161
 
                         (procedure/scode operator)
1162
 
                         (procedure/block operator)
1163
 
                         (procedure/name operator)
1164
 
                         required
1165
 
                         '()
1166
 
                         #f
1167
 
                         (procedure/body operator))
1168
 
                        referenced-operands))))
1169
 
              (if (null? unreferenced-operands)
1170
 
                  form
1171
 
                  (sequence/optimizing-make
1172
 
                   expression
1173
 
                   (append unreferenced-operands (list form))))))))
1174
 
        (else
1175
 
         (combination/make (and expression (object/scode expression))
1176
 
                           block operator operands))))
1177
 
 
1178
 
(define (delete-unreferenced-parameters parameters rest body operands receiver)
1179
 
  (let ((free-in-body (free/expression body)))
1180
 
    (let loop ((parameters              parameters)
1181
 
               (operands                operands)
1182
 
               (required-parameters     '())
1183
 
               (referenced-operands     '())
1184
 
               (unreferenced-operands   '()))
1185
 
    (cond ((null? parameters)
1186
 
           (if (or rest (null? operands))
1187
 
               (receiver (reverse required-parameters) ; preserve order
1188
 
                         (reverse referenced-operands)
1189
 
                         (if (or (null? operands)
1190
 
                                 (variable/integrated rest))
1191
 
                             unreferenced-operands
1192
 
                             (append operands unreferenced-operands)))
1193
 
               (error "Argument mismatch" operands)))
1194
 
          ((null? operands)
1195
 
           (error "Argument mismatch" parameters))
1196
 
          (else
1197
 
           (let ((this-parameter (car parameters))
1198
 
                 (this-operand   (car operands)))
1199
 
             (cond ((set/member? free-in-body this-parameter)
1200
 
                    (loop (cdr parameters)
1201
 
                          (cdr operands)
1202
 
                          (cons this-parameter required-parameters)
1203
 
                          (cons this-operand   referenced-operands)
1204
 
                          unreferenced-operands))
1205
 
                   ((variable/integrated this-parameter)
1206
 
                    (loop (cdr parameters)
1207
 
                          (cdr operands)
1208
 
                          required-parameters
1209
 
                          referenced-operands
1210
 
                          unreferenced-operands))
1211
 
                   (else
1212
 
                    (loop (cdr parameters)
1213
 
                          (cdr operands)
1214
 
                          required-parameters
1215
 
                          referenced-operands
1216
 
                          (cons this-operand
1217
 
                                unreferenced-operands))))))))))
1218
 
 
1219
 
(define *block-optimizing-switch #f)
1220
 
 
1221
 
;; This is overly hairy, but if it works, no one need know.
1222
 
;; What we do is this:
1223
 
;; 1 Make a directed graph of the dependencies in an open
1224
 
;;    block.
1225
 
;; 2 Identify the circular dependencies and place them in
1226
 
;;    a open block.
1227
 
;; 3 Identify the bindings that can be made in parallel and
1228
 
;;    make LET type statements.
1229
 
;; 4 This deletes unused bindings in an open block and
1230
 
;;    compartmentalizes the environment.
1231
 
;; 5 Re-optimize the code in the body.  This can help if the
1232
 
;;    eta-substitution-switch is on.
1233
 
 
1234
 
(define (open-block/optimizing-make expression block vars values
1235
 
                                    actions operations environment)
1236
 
  (if (and *block-optimizing-switch
1237
 
           (block/safe? block))
1238
 
      (let ((table:var->vals (associate-vars-and-vals vars values))
1239
 
            (bound-variables (varlist->varset vars)))
1240
 
        (let ((table:vals->free
1241
 
               (get-free-vars-in-bindings bound-variables values))
1242
 
              (body-free (get-body-free-vars bound-variables actions)))
1243
 
          ;; (write-string "Free vars in body")
1244
 
          ;; (display (map variable/name body-free))
1245
 
          (let ((graph (build-graph vars
1246
 
                                    table:var->vals
1247
 
                                    table:vals->free
1248
 
                                    body-free)))
1249
 
            (collapse-circularities! graph)
1250
 
            ;; (print-graph graph)
1251
 
            (label-node-depth! graph)
1252
 
            (let ((template (linearize graph)))
1253
 
              ;; (print-template template)
1254
 
              (integrate/expression
1255
 
               operations environment
1256
 
               (build-new-code expression
1257
 
                               template
1258
 
                               (block/parent block)
1259
 
                               table:var->vals actions))))))
1260
 
      (open-block/make
1261
 
       (and expression (object/scode expression))
1262
 
       block vars values actions #t)))
1263
 
 
1264
 
#|
1265
 
(define (print-template template)
1266
 
  (if (null? template)
1267
 
      '()
1268
 
      (let ((this (car template)))
1269
 
        (newline)
1270
 
        (display (car this))
1271
 
        (display (map variable/name (cdr this)))
1272
 
        (print-template (cdr template)))))
1273
 
|#
1274
 
 
1275
 
(define (associate-vars-and-vals vars vals)
1276
 
  (let ((table (make-generic-eq?-table)))
1277
 
    (define (fill-table vars vals)
1278
 
      (cond ((null? vars) (if (null? vals) '() (error "Mismatch")))
1279
 
            ((null? vals) (error "Mismatch"))
1280
 
            (else (table-put! table (car vars) (car vals))
1281
 
                  (fill-table (cdr vars) (cdr vals)))))
1282
 
    (fill-table vars vals)
1283
 
    table))
1284
 
 
1285
 
(declare (integrate varlist->varset nodelist->nodeset
1286
 
                    empty-nodeset singleton-nodeset
1287
 
                    empty-varset singleton-varset))
1288
 
 
1289
 
(define (varlist->varset list)
1290
 
  (declare (integrate list))
1291
 
  (list->set variable? eq? list))
1292
 
 
1293
 
(define (nodelist->nodeset list)
1294
 
  (declare (integrate list))
1295
 
  (list->set node? eq? list))
1296
 
 
1297
 
(define (empty-nodeset)
1298
 
  (empty-set node? eq?))
1299
 
 
1300
 
(define (singleton-nodeset node)
1301
 
  (declare (integrate node))
1302
 
  (singleton-set node? eq? node))
1303
 
 
1304
 
(define (empty-varset)
1305
 
  (declare (integrate node))
1306
 
  (empty-set variable? eq?))
1307
 
 
1308
 
(define (singleton-varset variable)
1309
 
  (declare (integrate variable))
1310
 
  (singleton-set variable? eq? variable))
1311
 
 
1312
 
(define (get-free-vars-in-bindings bound-variables vals)
1313
 
  ;; find variables in bindings that are scoped to these
1314
 
  ;; bound variables
1315
 
  (let ((table (make-generic-eq?-table)))
1316
 
    (define (kernel val)
1317
 
      (let ((free-variables (free/expression val)))
1318
 
        (table-put! table val
1319
 
                    (set/intersection bound-variables free-variables))))
1320
 
    (for-each kernel vals)
1321
 
    table))
1322
 
 
1323
 
(define (get-body-free-vars bound-variables actions)
1324
 
  (let ((body-forms (get-body actions)))
1325
 
    (let loop ((body-forms body-forms)
1326
 
               (free (empty-varset)))
1327
 
      (if (null? body-forms)
1328
 
          free
1329
 
          (loop (cdr body-forms)
1330
 
                (set/union free
1331
 
                           (set/intersection bound-variables
1332
 
                                             (free/expression
1333
 
                                              (car body-forms)))))))))
1334
 
 
1335
 
(define (get-body actions)
1336
 
  (cond ((null? actions) '())
1337
 
        ((eq? (car actions) open-block/value-marker) (get-body (cdr actions)))
1338
 
        (else (cons (car actions) (get-body (cdr actions))))))
1339
 
 
1340
 
;;; Graph structure for figuring out dependencies in a LETREC
1341
 
 
1342
 
(define-structure (node
1343
 
                   (constructor %make-node (type vars))
1344
 
                   (conc-name %node-))
1345
 
  type
1346
 
  (vars #f read-only #t)
1347
 
  (needs (empty-nodeset))
1348
 
  (needed-by (empty-nodeset))
1349
 
  (depth #f))
1350
 
 
1351
 
(define-integrable (make-base-node)
1352
 
  (%make-node 'BASE (empty-varset)))
1353
 
 
1354
 
(define-integrable (variable->node variable)
1355
 
  (%make-node 'SETUP (singleton-varset variable)))
1356
 
 
1357
 
(define-integrable (make-letrec-node variable-set)
1358
 
  (%make-node 'LETREC variable-set))
1359
 
 
1360
 
(define-integrable (add-node-need! needer what-i-need)
1361
 
  (set-%node-needs! needer (set/adjoin (%node-needs needer) what-i-need)))
1362
 
 
1363
 
(define-integrable (remove-node-need! needer what-i-no-longer-need)
1364
 
  (set-%node-needs! needer
1365
 
                    (set/remove (%node-needs needer) what-i-no-longer-need)))
1366
 
 
1367
 
(define-integrable (add-node-needed-by! needee what-needs-me)
1368
 
  (set-%node-needed-by! needee
1369
 
                        (set/adjoin (%node-needed-by needee) what-needs-me)))
1370
 
 
1371
 
(define-integrable (remove-node-needed-by! needee what-needs-me)
1372
 
  (set-%node-needed-by! needee
1373
 
                        (set/remove (%node-needed-by needee) what-needs-me)))
1374
 
 
1375
 
(define (build-graph vars table:var->vals table:vals->free body-free)
1376
 
  (let ((table:variable->node (make-generic-eq?-table)))
1377
 
 
1378
 
    (define (kernel variable)
1379
 
      (let ((node (variable->node variable)))
1380
 
        (table-put! table:variable->node variable node)))
1381
 
 
1382
 
    (for-each kernel vars)
1383
 
 
1384
 
    (link-nodes! body-free table:var->vals table:vals->free vars
1385
 
                 table:variable->node)))
1386
 
 
1387
 
(define-integrable (link-2-nodes! from-node to-node)
1388
 
  (add-node-need! from-node to-node)
1389
 
  (add-node-needed-by! to-node from-node))
1390
 
 
1391
 
(define (unlink-node! node)
1392
 
  (set/for-each (lambda (needer)
1393
 
                  (remove-node-needed-by! needer node))
1394
 
                (%node-needs node))
1395
 
  (set/for-each (lambda (needee)
1396
 
                  (remove-node-need! needee node))
1397
 
                (%node-needed-by node))
1398
 
  (set-%node-type! node 'UNLINKED))
1399
 
 
1400
 
(define-integrable (unlink-nodes! nodelist)
1401
 
  (for-each unlink-node! nodelist))
1402
 
 
1403
 
(define (link-nodes! body-free
1404
 
                    table:var->vals table:vals->free variables table:var->node)
1405
 
 
1406
 
  (define (kernel variable)
1407
 
    (table-get table:var->node variable
1408
 
      (lambda (node)
1409
 
        (table-get-chain variable
1410
 
          (lambda (free-vars)
1411
 
            (set/for-each
1412
 
              (lambda (needed-var)
1413
 
                (table-get table:var->node needed-var
1414
 
                           (lambda (needed-node)
1415
 
                             (link-2-nodes! node needed-node))
1416
 
                           (lambda ()
1417
 
                             (error "Broken analysis: can't get node"))))
1418
 
              free-vars))
1419
 
          (lambda () (error "Broken analysis: can't get free variable info"))
1420
 
          table:var->vals table:vals->free))
1421
 
      (lambda () (error "Broken analysis: no node for variable"))))
1422
 
 
1423
 
  (for-each kernel variables)
1424
 
 
1425
 
  (let ((base-node (make-base-node)))
1426
 
    (set/for-each
1427
 
     (lambda (needed-var)
1428
 
       (table-get table:var->node needed-var
1429
 
                  (lambda (needed-node)
1430
 
                    (link-2-nodes! base-node needed-node))
1431
 
                  (lambda () (error "Broken analysis: free var"))))
1432
 
     body-free)
1433
 
    base-node))
1434
 
 
1435
 
(define (collapse-circularities! graph)
1436
 
  ;; Search for a circularity:  if found, collapse it, and repeat
1437
 
  ;; until none are found.
1438
 
  (define (loop)
1439
 
    (find-circularity graph
1440
 
      (lambda (nodelist)
1441
 
        (collapse-nodelist! nodelist)
1442
 
        (loop))
1443
 
      (lambda () graph)))
1444
 
  (loop))
1445
 
 
1446
 
(define (find-circularity graph if-found if-not)
1447
 
  ;; Walk the tree keeping track of nodes visited
1448
 
  ;; If a node is encountered more than once, there is
1449
 
  ;; a circularitiy.  NODES-VISITED is a list kept in
1450
 
  ;; base node first order.  If a node is found on the
1451
 
  ;; list, the tail of the list is the nodes in the
1452
 
  ;; circularity.
1453
 
 
1454
 
  (define (fc this-node nodes-visited if-found if-not)
1455
 
    (if (null? this-node)
1456
 
        (if-not)
1457
 
        (let ((circularity (memq this-node nodes-visited)))
1458
 
          (if circularity
1459
 
              (if-found circularity)
1460
 
              ;; Add this node to the visited list, and loop
1461
 
              ;; over the needs of this node.
1462
 
              (let ((new-visited (append nodes-visited (list this-node))))
1463
 
                (let loop ((needs (set->list (%node-needs this-node))))
1464
 
                  (if (null? needs)
1465
 
                      (if-not)
1466
 
                      (fc (car needs) new-visited if-found
1467
 
                          (lambda () (loop (cdr needs)))))))))))
1468
 
 
1469
 
  (fc graph '() if-found if-not))
1470
 
 
1471
 
(define (collapse-nodelist! nodelist)
1472
 
  ;; Replace the nodes in the nodelist with a single node that
1473
 
  ;; has all the variables in it.  This node will become a LETREC
1474
 
  ;; form.
1475
 
 
1476
 
  ;; Error check:  make sure graph is consistant.
1477
 
  (for-each (lambda (node) (if (eq? (%node-type node) 'UNLINKED)
1478
 
                               (error "node not linked")))
1479
 
            nodelist)
1480
 
 
1481
 
  (let ((nodeset (nodelist->nodeset nodelist)))
1482
 
    (let ((varset (apply set/union* (map %node-vars nodelist)))
1483
 
          (needs-set  (set/difference
1484
 
                       (apply set/union* (map %node-needs nodelist))
1485
 
                       nodeset))
1486
 
          (needed-by (set/difference
1487
 
                      (apply set/union* (map %node-needed-by nodelist))
1488
 
                      nodeset)))
1489
 
 
1490
 
    (let ((letrec-node (make-letrec-node varset)))
1491
 
      (set/for-each (lambda (need) (link-2-nodes! letrec-node need))
1492
 
                    needs-set)
1493
 
      (set/for-each
1494
 
       (lambda (needer) (link-2-nodes! needer letrec-node)) needed-by)
1495
 
      ;; now delete nodes in nodelist
1496
 
      (unlink-nodes! nodelist)))))
1497
 
 
1498
 
(define (label-node-depth! graph)
1499
 
  (define (label-nodes! nodeset depth)
1500
 
    (if (set/empty? nodeset)
1501
 
        '()
1502
 
        (begin
1503
 
          (set/for-each (lambda (node) (set-%node-depth! node depth)) nodeset)
1504
 
          (label-nodes!
1505
 
           (apply set/union* (map %node-needs (set->list nodeset)))
1506
 
           (1+ depth)))))
1507
 
  (label-nodes! (singleton-nodeset graph) 0))
1508
 
 
1509
 
#|
1510
 
(define (print-graph node)
1511
 
  (if (null? node)
1512
 
      '()
1513
 
      (begin
1514
 
        (newline)
1515
 
        (display (%node-depth node))
1516
 
        (display (%node-type node))
1517
 
        (set/for-each (lambda (variable)
1518
 
                        (display " ")
1519
 
                        (display (variable/name variable)))
1520
 
                      (%node-vars node))
1521
 
        (set/for-each print-graph (%node-needs node)))))
1522
 
|#
1523
 
 
1524
 
(define (collapse-parallel-nodelist depth nodeset)
1525
 
  (if (set/empty? nodeset)
1526
 
      '()
1527
 
      (let loop ((nodestream      (set->list nodeset))
1528
 
                 (let-children    (empty-varset))
1529
 
                 (letrec-children (empty-varset))
1530
 
                 (children        (empty-nodeset)))
1531
 
        (if (null? nodestream)
1532
 
            (let ((outer-contour
1533
 
                   (collapse-parallel-nodelist (1+ depth) children)))
1534
 
              (append (if (set/empty? let-children)
1535
 
                          '()
1536
 
                          (list (cons 'LET (set->list let-children))))
1537
 
                      (if (set/empty? letrec-children)
1538
 
                          '()
1539
 
                          (list (cons 'LETREC (set->list letrec-children))))
1540
 
                      outer-contour))
1541
 
            (let ((this-node (car nodestream)))
1542
 
              (if (= (%node-depth this-node) (1+ depth))
1543
 
                  (if (eq? (%node-type this-node) 'LETREC)
1544
 
                      (loop (cdr nodestream)
1545
 
                            let-children
1546
 
                            (set/union (%node-vars this-node) letrec-children)
1547
 
                            (set/union (%node-needs this-node) children))
1548
 
                      (loop (cdr nodestream)
1549
 
                            (set/union (%node-vars this-node) let-children)
1550
 
                            letrec-children
1551
 
                            (set/union (%node-needs this-node) children)))
1552
 
                  ;; deeper nodes will be picked up later
1553
 
                  (loop (cdr nodestream)
1554
 
                        let-children
1555
 
                        letrec-children
1556
 
                        children)))))))
1557
 
 
1558
 
(define (linearize graph)
1559
 
  (collapse-parallel-nodelist 0 (%node-needs graph)))
1560
 
 
1561
 
(define (build-new-code expression template parent vars->vals actions)
1562
 
  (let ((body (sequence/optimizing-make expression (get-body actions))))
1563
 
    (let loop ((template template)
1564
 
               (block    parent)
1565
 
               (code     body))
1566
 
      (if (null? template)
1567
 
           code
1568
 
           (let ((this (car template)))
1569
 
             (let ((this-type (car this))
1570
 
                   (this-vars (cdr this)))
1571
 
               (let ((this-vals
1572
 
                      (map (lambda (var)
1573
 
                             (table-get vars->vals var
1574
 
                                        (lambda (val) val)
1575
 
                                        (lambda () (error "broken"))))
1576
 
                           this-vars)))
1577
 
 
1578
 
               (if (eq? this-type 'LET)
1579
 
                   (let ((block (block/make block #t this-vars)))
1580
 
                     (loop (cdr template)
1581
 
                           block
1582
 
                           (combination/optimizing-make
1583
 
                            expression
1584
 
                            block
1585
 
                            (procedure/make
1586
 
                             #f
1587
 
                             block
1588
 
                             lambda-tag:let
1589
 
                             this-vars
1590
 
                             '()
1591
 
                             #f
1592
 
                             code)
1593
 
                            this-vals)))
1594
 
                   (let ((block (block/make block #t this-vars)))
1595
 
                     (loop (cdr template)
1596
 
                           block
1597
 
                           (open-block/make
1598
 
                            (and expression (object/scode expression))
1599
 
                            block this-vars this-vals
1600
 
                            (append (make-list
1601
 
                                     (length this-vals)
1602
 
                                     open-block/value-marker)
1603
 
                                    (list code))
1604
 
                            #t)))))))))))
 
 
b'\\ No newline at end of file'
 
966
            delayed-integration)))
 
967
  (delayed-integration/value delayed-integration))
 
 
b'\\ No newline at end of file'