~ubuntu-branches/ubuntu/trusty/librep/trusty

« back to all changes in this revision

Viewing changes to lisp/rep/vm/peephole.jl

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2001-11-13 15:06:22 UTC
  • Revision ID: james.westby@ubuntu.com-20011113150622-vgmgmk6srj3kldr3
Tags: upstream-0.15.2
ImportĀ upstreamĀ versionĀ 0.15.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#| peephole.jl -- peephole optimizer for rep assembly code
 
2
 
 
3
   $Id: peephole.jl,v 1.30 2000/11/21 21:28:24 jsh Exp $
 
4
 
 
5
   Copyright (C) 1999, 2000 John Harper <john@dcs.warwick.ac.uk>
 
6
 
 
7
   This file is part of librep.
 
8
 
 
9
   librep is free software; you can redistribute it and/or modify it
 
10
   under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 2, or (at your option)
 
12
   any later version.
 
13
 
 
14
   librep is distributed in the hope that it will be useful, but
 
15
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with Jade; see the file COPYING.  If not, write to
 
21
   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
22
|#
 
23
 
 
24
;; Most of the optimisation patterns in the peephole optimiser were
 
25
;; lifted from jwz's byte-optimize.el (XEmacs)
 
26
 
 
27
(declare (unsafe-for-call/cc))
 
28
 
 
29
(define-structure rep.vm.peephole
 
30
 
 
31
    (export peephole-optimizer)
 
32
 
 
33
    (open rep
 
34
          rep.vm.bytecodes)
 
35
 
 
36
  ;; todo:
 
37
 
 
38
  ;; c{dd..d}r; car --> ca{dd..d}r
 
39
  ;; c{dd..d}r; cdr --> cd{dd..d}r
 
40
 
 
41
  ;; shift the instruction window
 
42
  (defmacro shift ()
 
43
    '(progn
 
44
       (setq point (cdr point))
 
45
       (setq insn0 insn1)
 
46
       (setq insn1 insn2)
 
47
       (setq insn2 (nth 3 point))))
 
48
 
 
49
  ;; refill the window
 
50
  (defmacro refill ()
 
51
    '(progn
 
52
       (setq insn0 (nth 1 point))
 
53
       (setq insn1 (nth 2 point))
 
54
       (setq insn2 (nth 3 point))))
 
55
 
 
56
  ;; delete the first instruction in the window
 
57
  (defmacro del-0 ()
 
58
    '(progn
 
59
       (rplacd point (nthcdr 2 point))
 
60
       (setq insn0 insn1)
 
61
       (setq insn1 insn2)
 
62
       (setq insn2 (nth 3 point))))
 
63
 
 
64
  ;; delete the second instruction in the window
 
65
  (defmacro del-1 ()
 
66
    '(progn
 
67
       (rplacd (cdr point) (nthcdr 3 point))
 
68
       (setq insn1 insn2)
 
69
       (setq insn2 (nth 3 point))))
 
70
 
 
71
  ;; delete the third instruction in the window
 
72
  (defmacro del-2 ()
 
73
    '(progn
 
74
       (rplacd (nthcdr 2 point) (nthcdr 4 point))
 
75
       (setq insn2 (nth 3 point))))
 
76
 
 
77
  ;; delete the first two instructions in the window
 
78
  (defmacro del-0-1 ()
 
79
    '(progn
 
80
       (rplacd point (nthcdr 3 point))
 
81
       (setq insn0 insn2)
 
82
       (setq insn1 (nth 2 point))
 
83
       (setq insn2 (nth 3 point))))
 
84
 
 
85
  ;; delete the second two instructions in the window
 
86
  (defmacro del-1-2 ()
 
87
    '(progn
 
88
       (rplacd (cdr point) (nthcdr 4 point))
 
89
       (setq insn1 (nth 2 point))
 
90
       (setq insn2 (nth 3 point))))
 
91
 
 
92
  ;; delete all instructions in the window
 
93
  (defmacro del-0-1-2 ()
 
94
    '(progn
 
95
       (rplacd point (nthcdr 4 point))
 
96
       (refill)))
 
97
 
 
98
  ;; debugging
 
99
  (defmacro before ()
 
100
    `(format standard-error "before: [%S %S %S]\n"
 
101
             (nth 1 point) (nth 2 point) (nth 3 point)))
 
102
  (defmacro after ()
 
103
    `(format standard-error "after: [%S %S %S]\n"
 
104
             (nth 1 point) (nth 2 point) (nth 3 point)))
 
105
 
 
106
  ;; run the optimiser over CODE-STRING, modifying and returning it
 
107
  ;; returns (CODE . EXTRA-STACK)
 
108
  (defun peephole-optimizer (code-string)
 
109
    (let ((keep-going t)
 
110
          (extra-stack 0)
 
111
          point insn0 insn1 insn2 tem)
 
112
      ;; add an extra cons cell so we can always refer to the
 
113
      ;; cdr of the intsruction _before_ insn0, this makes it
 
114
      ;; easy to delete instructions
 
115
      (setq code-string (cons 'start code-string))
 
116
      (while keep-going
 
117
        (setq keep-going nil)
 
118
        (setq point code-string)
 
119
        (refill)
 
120
        (while insn0
 
121
          ;;(format standard-error "iter: %S\n\n" code-string)
 
122
          (cond
 
123
           ;; <side-effect-free w/ stack+1>; pop --> <deleted>
 
124
           ;; <side-effect-free w/ stack+0>; pop --> pop
 
125
           ;; <side-effect-free w/ stack-1>; pop --> pop; pop
 
126
           ((and (eq (car insn1) 'pop)
 
127
                 (memq (car insn0) byte-side-effect-free-insns))
 
128
            (setq tem (aref byte-insn-stack-delta (bytecode-ref (car insn0))))
 
129
            (cond ((= tem 1)
 
130
                   (del-0-1)
 
131
                   (setq keep-going t))
 
132
                  ((= tem 0)
 
133
                   (del-0)
 
134
                   (setq keep-going t))
 
135
                  ((= tem -1)
 
136
                   (rplaca insn0 'pop)
 
137
                   (rplacd insn0 nil)
 
138
                   (setq keep-going t))))
 
139
 
 
140
           ;; {push,dup}; setn #X; refn #X
 
141
           ;;    --> {push,dup}; setn #X; {push, dup}
 
142
           ;; {push,dup}; bind X; refn #0
 
143
           ;;    --> {push,dup}; bind X; {push, dup}
 
144
           ;; {push,dup}; slot-set #X; slot-ref #X
 
145
           ;;    --> {push,dup}; slot-set #X; {push, dup}
 
146
           ((and (or (and (eq (car insn1) 'setn) (eq (car insn2) 'refn)
 
147
                          (eq (cadr insn1) (cadr insn2)))
 
148
                     (and (eq (car insn1) 'bind) (eq (car insn2) 'refn)
 
149
                          (eq (cadr insn2) 0))
 
150
                     (and (eq (car insn1) 'slot-set) (eq (car insn2) 'slot-ref)
 
151
                          (eq (cadr insn1) (cadr insn2))))
 
152
                 (or (eq (car insn0) 'dup) (eq (car insn0) 'push)))
 
153
            (rplaca insn2 (car insn0))
 
154
            (rplacd insn2 (cdr insn0))
 
155
            (setq keep-going t))
 
156
 
 
157
           ;; setn #X; refn #X --> dup; setn #X
 
158
           ;; bind; refn #0 --> dup; bind
 
159
           ;; slot-set #X; slot-ref #X --> dup; slot-set #X
 
160
           ((or (and (eq (car insn0) 'setn)
 
161
                     (eq (car insn1) 'refn)
 
162
                     (eq (cadr insn0) (cadr insn1)))
 
163
                (and (eq (car insn0) 'bind)
 
164
                     (eq (car insn1) 'refn)
 
165
                     (eql (cadr insn1) 0))
 
166
                (and (eq (car insn0) 'slot-set)
 
167
                     (eq (car insn1) 'slot-ref)
 
168
                     (eq (cadr insn0) (cadr insn1))))
 
169
            (rplaca insn1 (car insn0))
 
170
            (rplacd insn1 (cdr insn0))
 
171
            (rplaca insn0 'dup)
 
172
            (rplacd insn0 nil)
 
173
            ;; this might require extra stack space
 
174
            (setq extra-stack 1)
 
175
            (setq keep-going t))
 
176
 
 
177
           ;; dup; {<varset>,<varbind>} X; pop --> {<varset>,<varbind>} X
 
178
           ((and (eq (car insn0) 'dup)
 
179
                 (or (memq (car insn1) byte-varset-insns)
 
180
                     (memq (car insn1) byte-varbind-insns))
 
181
                 (eq (car insn2) 'pop))
 
182
            (rplaca insn2 (car insn1))
 
183
            (rplacd insn2 (cdr insn1))
 
184
            (del-0-1)
 
185
            (setq keep-going t))
 
186
 
 
187
           ;; <varref> X; <varref> X --> <varref> X; dup
 
188
           ((and (memq (car insn0) byte-varref-insns)
 
189
                 (eq (car insn1) (car insn0))
 
190
                 (eq (cadr insn0) (cadr insn1)))
 
191
            (rplaca insn1 'dup)
 
192
            (rplacd insn1 nil)
 
193
            (setq keep-going t))
 
194
 
 
195
           ;; <varref> X; <varset> X --> deleted
 
196
           ((or (and (eq (car insn0) 'refn)
 
197
                     (eq (car insn1) 'setn)
 
198
                     (eql (cadr insn0) (cadr insn1)))
 
199
                (and (eq (car insn0) 'refg)
 
200
                     (eq (car insn1) 'setg)
 
201
                     (eq (cadr insn0) (cadr insn1)))
 
202
                (and (eq (car insn0) 'slot-ref)
 
203
                     (eq (car insn1) 'slot-set)
 
204
                     (eq (cadr insn0) (cadr insn1))))
 
205
            (del-0-1)
 
206
            (setq keep-going t))
 
207
 
 
208
           ;; c?r; c?r --> c??r
 
209
           ((and (memq (car insn0) '(car cdr))
 
210
                 (memq (car insn1) '(car cdr)))
 
211
            (rplaca insn1 (if (eq (car insn0) 'car)
 
212
                              (if (eq (car insn1) 'car) 'caar 'cdar)
 
213
                            (if (eq (car insn1) 'car) 'cadr 'cddr)))
 
214
            (del-0)
 
215
            (setq keep-going t))
 
216
 
 
217
           ;; test-scm; scm-test --> deleted
 
218
           ;; test-scm-f; scm-test --> deleted
 
219
           ;; [ these are only possible because scm-test is only used
 
220
           ;;   for `cond' tests, not for its actual value ]
 
221
           ((and (memq (car insn0) '(test-scm test-scm-f))
 
222
                 (eq (car insn1) 'scm-test))
 
223
            (del-0-1)
 
224
            (setq keep-going t))
 
225
 
 
226
           ;; push 1; sub --> dec
 
227
           ;; push -1; sub --> inc
 
228
           ;; push 1; add --> inc
 
229
           ;; push -1; add --> dec
 
230
           ;; [ XXX these and more should be handled at a higher level ]
 
231
           ((and (eq (car insn0) 'push)
 
232
                 (memq (car insn1) '(sub add))
 
233
                 (memql (cadr insn0) '(1 -1)))
 
234
            (let ((new (if (eql (cadr insn0) 1)
 
235
                           (if (eq (car insn1) 'sub) 'dec 'inc)
 
236
                         (if (eq (car insn1) 'sub) 'inc 'dec))))
 
237
              (rplaca insn1 new)
 
238
              (del-0)
 
239
              (setq keep-going t)))
 
240
 
 
241
           ;; push 0; {add,sub} --> <deleted>
 
242
           ((and (equal insn0 '(push 0)) (memq (car insn1) '(add sub)))
 
243
            (del-0-1)
 
244
            (setq keep-going t))
 
245
 
 
246
           ;; push 0; num-eq --> zerop
 
247
           ((and (equal insn0 '(push 0)) (eq (car insn1) 'num-eq))
 
248
            (rplaca insn1 'zerop)
 
249
            (del-0)
 
250
            (setq keep-going t))
 
251
 
 
252
           ;; zerop; not --> not-zero-p
 
253
           ((and (eq (car insn0) 'zerop) (eq (car insn1) 'not))
 
254
            (rplaca insn1 'not-zero-p)
 
255
            (del-0)
 
256
            (setq keep-going t))
 
257
 
 
258
           ;; jmp X; X: --> X:
 
259
           ((and (eq (car insn0) 'jmp) (eq (cadr insn0) insn1))
 
260
            (del-0)
 
261
            (setq keep-going t))
 
262
 
 
263
           ;; {jn,jt} X; X: --> pop; X:
 
264
           ((and (memq (car insn0) '(jn jt)) (eq (cadr insn0) insn1))
 
265
            (rplaca insn0 'pop)
 
266
            (rplacd insn0 nil)
 
267
            (setq keep-going t))
 
268
 
 
269
           ;; {jpt,jpn} X; pop --> {jt,jn} X
 
270
           ((and (memq (car insn0) '(jpt jpn)) (eq (car insn1) 'pop))
 
271
            (rplaca insn0 (if (eq (car insn0) 'jpt) 'jt 'jn))
 
272
            (del-1)
 
273
            (setq keep-going t))
 
274
 
 
275
           ;; not; {jn,jt} X --> {jt,jn} X
 
276
           ((and (eq (car insn0) 'not)
 
277
                 (memq (car insn1) '(jn jt)))
 
278
            (rplaca insn1 (if (eq (car insn1) 'jn) 'jt 'jn))
 
279
            (del-0)
 
280
            (setq keep-going t))
 
281
 
 
282
           ;; jt X; (push ()) --> jpt X
 
283
           ((and (eq (car insn0) 'jt) (equal insn1 '(push ())))
 
284
            (rplaca insn0 'jpt)
 
285
            (del-1)
 
286
            (setq keep-going t))
 
287
 
 
288
           ;; {jn,jt} X; jmp Y; X: --> {jt,jn} Y; X:
 
289
           ((and (memq (car insn0) '(jn jt))
 
290
                 (eq (car insn1) 'jmp)
 
291
                 (eq (cadr insn0) insn2))
 
292
            (rplaca insn1 (if (eq (car insn0) 'jn) 'jt 'jn))
 
293
            (del-0)
 
294
            (setq keep-going t))
 
295
 
 
296
           ;; (push X); <cond. jump> X; --> whatever
 
297
           ((and (eq (car insn0) 'push)
 
298
                 (memq (car insn1) byte-conditional-jmp-insns))
 
299
            (let*
 
300
                ;; only way to get a nil constant is through `(push ())'
 
301
                ((is-nil (equal insn0 '(push ())))
 
302
                 (is-t (not is-nil)))
 
303
              (cond ((or (and is-nil (eq (car insn1) 'jn))
 
304
                         (and is-t (eq (car insn1) 'jt))
 
305
                         (and is-nil (eq (car insn1) 'jpn))
 
306
                         (and is-t (eq (car insn1) 'jpt)))
 
307
                     ;; nil; jn X --> jmp X
 
308
                     ;; t; jt X --> jmp X
 
309
                     ;; nil; jpn X --> jmp X
 
310
                     ;; t; jpt X --> jmp X
 
311
                     (rplaca insn1 'jmp)
 
312
                     (del-0))
 
313
                    ((or (and is-nil (eq (car insn1) 'jt))
 
314
                         (and is-t (eq (car insn1) 'jn))
 
315
                         (and is-t (eq (car insn1) 'jnp))
 
316
                         (and is-nil (eq (car insn1) 'jtp)))
 
317
                     ;; nil; jt X --> <deleted>
 
318
                     ;; t; jn X --> <deleted>
 
319
                     ;; t; jnp X --> <deleted>
 
320
                     ;; nil; jtp X --> <deleted>
 
321
                     (del-0-1))
 
322
                    ((or (and is-nil (eq (car insn1) 'jnp))
 
323
                         (and is-t (eq (car insn1) 'jtp)))
 
324
                     ;; nil; jnp X --> nil; jmp X
 
325
                     ;; t; jtp X --> t; jmp X
 
326
                     (rplaca insn1 'jmp))
 
327
                    ((or (and is-t (eq (car insn1) 'jpn))
 
328
                         (and is-nil (eq (car insn1) 'jpt)))
 
329
                     ;; t; jpn X --> t
 
330
                     ;; nil; jpt X --> nil
 
331
                     (del-1))
 
332
                    (t (error "Unhandled contional jump case")))
 
333
              (setq keep-going t)))
 
334
 
 
335
           ;; <varref-and-error-free-op>; unbind ---> unbind; op
 
336
           ((and (eq (car insn1) 'unbind)
 
337
                 (memq (car insn0) byte-varref-free-insns))
 
338
            (let
 
339
                ((op (car insn0))
 
340
                 (arg (cdr insn0)))
 
341
              (rplaca insn0 (car insn1))
 
342
              (rplacd insn0 (cdr insn1))
 
343
              (rplaca insn1 op)
 
344
              (rplacd insn1 arg)
 
345
              (setq keep-going t)))
 
346
 
 
347
           ;; <varbind> X; unbind --> pop; unbind
 
348
           ((and (memq (car insn0) byte-varbind-insns)
 
349
                 (eq (car insn1) 'unbind))
 
350
            (rplaca insn0 'pop)
 
351
            (rplacd insn0 nil)
 
352
            (setq keep-going t))
 
353
 
 
354
           ;; init-bind; unbind --> deleted
 
355
           ((and (eq (car insn0) 'init-bind) (eq (car insn1) 'unbind))
 
356
            (del-0-1)
 
357
            (setq keep-going t))
 
358
 
 
359
           ;; init-bind; {return,unbindall} --> {return,unbindall}
 
360
           ((and (eq (car insn0) 'init-bind)
 
361
                 (memq (car insn1) '(return unbindall)))
 
362
            (del-0)
 
363
            (setq keep-going t))
 
364
 
 
365
           ;; unbind; return --> return
 
366
           ((and (eq (car insn0) 'unbind) (eq (car insn1) 'return))
 
367
            (del-0)
 
368
            (setq keep-going t))
 
369
 
 
370
           ;; <varref> X; dup... ; <varref> X --> <varref> X; dup...; dup
 
371
           ((and (memq (car insn0) byte-varref-insns)
 
372
                 (eq (car insn1) 'dup))
 
373
            (let
 
374
                ((tem (nthcdr 2 point)))
 
375
              (while (eq (car (car tem)) 'dup)
 
376
                (setq tem (cdr tem)))
 
377
              (when (equal (car tem) insn0)
 
378
                (rplaca (car tem) 'dup)
 
379
                (rplacd (car tem) nil)
 
380
                (setq keep-going t))))
 
381
 
 
382
           ;; X: Y: --> X:  [s/X/Y/]
 
383
           ((and (symbolp insn0) (symbolp insn1))
 
384
            (let loop ((rest (cdr code-string)))
 
385
              (when rest
 
386
                (when (and (eq (cadar rest) insn1)
 
387
                           (or (memq (caar rest) byte-jmp-insns)
 
388
                               (eq (caar rest) 'push-label)))
 
389
                  (rplaca (cdar rest) insn0))
 
390
                (loop (cdr rest))))
 
391
            (del-1)
 
392
            (setq keep-going t))
 
393
 
 
394
           ;; [unused] X: --> deleted
 
395
           ((and (symbolp insn0)
 
396
                 (let loop ((rest (cdr code-string)))
 
397
                   (cond ((null rest) t)
 
398
                         ((and (eq (cadar rest) insn0)
 
399
                               (or (memq (caar rest) byte-jmp-insns)
 
400
                                   (eq (caar rest) 'push-label))) nil)
 
401
                         (t (loop (cdr rest))))))
 
402
            (del-0)
 
403
            (setq keep-going t))
 
404
 
 
405
           ;; jmp X; ... Y: --> jmp X; Y:
 
406
           ;; return; ... Y: --> return; Y:
 
407
           ((and (memq (car insn0) '(jmp ejmp return))
 
408
                 insn1 (not (symbolp insn1)))
 
409
            (setq tem (nthcdr 2 point))
 
410
            (while (and tem (not (symbolp (car tem))))
 
411
              (setq tem (cdr tem)))
 
412
            (unless (eq tem (nthcdr 2 point))
 
413
              (rplacd (cdr point) tem)
 
414
              (refill)
 
415
              (setq keep-going t)))
 
416
 
 
417
           ;; j* X; ... X: jmp Y --> j* Y; ... X: jmp Y
 
418
           ((and (memq (car insn0) byte-jmp-insns)
 
419
                 (setq tem (or (memq (cadr insn0) (cdr code-string))
 
420
                               (error "Can't find jump destination: %s, %s"
 
421
                                      insn0 (cdr code-string))))
 
422
                 (setq tem (car (cdr tem)))
 
423
                 (eq (car tem) 'jmp)
 
424
                 (not (eq (cadr insn0) (cadr tem))))
 
425
            (rplacd insn0 (cdr tem))
 
426
            (setq keep-going t))
 
427
 
 
428
           ;; jmp X; ... X: return --> return; ... X: return
 
429
           ((and (eq (car insn0) 'jmp)
 
430
                 (setq tem (or (memq (cadr insn0) (cdr code-string))
 
431
                               (error "Can't find jump destination: %s, %s"
 
432
                                      insn0 (cdr code-string))))
 
433
                 (setq tem (car (cdr tem)))
 
434
                 (eq (car tem) 'return))
 
435
            (rplaca insn0 'return)
 
436
            (rplacd insn0 nil)
 
437
            (setq keep-going t))
 
438
 
 
439
           ;; {jnp,jtp} X; ... X: <cond. jmp> Y --> whatever
 
440
           ((and (memq (car insn0) '(jnp jtp))
 
441
                 (setq tem (cdr (or (memq (cadr insn0) (cdr code-string))
 
442
                                    (error "Can't find jump destination: %s, %s"
 
443
                                           insn0 (cdr code-string)))))
 
444
                 (car tem)
 
445
                 (memq (car (car tem)) byte-conditional-jmp-insns))
 
446
            (let
 
447
                ((jmp (car tem))
 
448
                 need-new-label)
 
449
              (if (eq (car insn0) 'jtp)
 
450
                  (cond
 
451
                   ((memq (car jmp) '(jpt jt))
 
452
                    ;; jtp X; ... X: jpt Y --> jt Y; ...
 
453
                    ;; jtp X; ... X: jt Y --> jt Y; ...
 
454
                    (rplaca insn0 'jt))
 
455
                   ((eq (car jmp) 'jpn)
 
456
                    ;; jtp X; ... X: jpn Y --> jpt Z; ... X: jpn Y; Z:
 
457
                    (rplaca insn0 'jpt)
 
458
                    (setq need-new-label t))
 
459
                   ((memq (car jmp) '(jn jnp))
 
460
                    ;; jtp X; ... X: jn Y --> jt Z; ... X: jpn Y; Z:
 
461
                    ;; jtp X; ... X: jnp Y --> jt Z; ... X: jpn Y; Z:
 
462
                    (rplaca insn0 'jt)
 
463
                    (setq need-new-label t))
 
464
                   ((eq (car jmp) 'jtp)
 
465
                    ;; jtp X; ... X: jtp Y --> jtp Y; ...
 
466
                    (rplaca insn0 'jtp)))
 
467
                (cond
 
468
                 ((eq (car jmp) 'jpt)
 
469
                  ;; jnp X; ... X: jpt Y --> jn Z; ... X: jpt Y; Z:
 
470
                  (rplaca insn0 'jnp)
 
471
                  (setq need-new-label t))
 
472
                 ((memq (car jmp) '(jpn jn))
 
473
                  ;; jnp X; ... X: jpn Y --> jn Y ...
 
474
                  ;; jnp X; ... X: jn Y --> jn Y ...
 
475
                  (rplaca insn0 'jn))
 
476
                 ((memq (car jmp) '(jt jtp))
 
477
                  ;; jnp X; ... X: jt Y --> jn Z; ... X: jt Y; Z:
 
478
                  ;; jnp X; ... X: jtp Y --> jn Z; ... X: jt Y; Z:
 
479
                  (rplaca insn0 'jn)
 
480
                  (setq need-new-label t))
 
481
                 ((eq (car jmp) 'jnp)
 
482
                  ;; jnp X; ... X: jnp Y --> jnp Y ...
 
483
                  (rplaca insn0 'jnp))))
 
484
              (if (not need-new-label)
 
485
                  (rplaca (cdr insn0) (cadr jmp))
 
486
                ;; add label `Z:' following the second jump
 
487
                (let ((label (cons (gensym) (cdr tem))))
 
488
                  (rplaca (cdr insn0) (car label))
 
489
                  (rplacd tem label)))
 
490
              (setq keep-going t)))
 
491
 
 
492
           ;; {jpt,jpn} X; jmp Y; X: --> {jnp,jtp} Y; X:
 
493
           ;; {jtp,jnp} X; jmp Y; X: --> {jpn,jpt} Y; X:
 
494
           ((and (eq (car insn1) 'jmp)
 
495
                 (memq (car insn0) '(jpt jpn jtp jnp))
 
496
                 (eq (cadr insn0) insn2))
 
497
            (rplaca insn1 (case (car insn0)
 
498
                            ((jpt) 'jnp)
 
499
                            ((jpn) 'jtp)
 
500
                            ((jtp) 'jpn)
 
501
                            ((jnp) 'jpt)))
 
502
            (del-0)
 
503
            (setq keep-going t))
 
504
 
 
505
           ;; <const>; jmp X; ... X: <cond. jmp> Y --> whatever
 
506
           ;;
 
507
           ;; [ this should be handled already, by (1) changing the
 
508
           ;;   first jump, then by (2) dereferencing the constant ]
 
509
 
 
510
           ;; jmp X: Y: ... X: <cond. jmp> Y --> ???
 
511
 
 
512
           )
 
513
          ;; shift in the next instruction
 
514
          (shift)))
 
515
 
 
516
      ;; now do one last pass, looking for simple things
 
517
      (setq point code-string)
 
518
      (refill)
 
519
      (while insn0
 
520
        (cond
 
521
         ;; push X; {<varset>,<varbind>} Y; push X
 
522
         ;;   --> push X; dup; {<varset>,<varbind>} Y
 
523
         ((and (eq (car insn0) 'push)
 
524
               (or (memq (car insn1) byte-varset-insns)
 
525
                   (memq (car insn1) byte-varbind-insns))
 
526
               (equal insn0 insn2))
 
527
          (rplaca insn2 (car insn1))
 
528
          (rplacd insn2 (cdr insn1))
 
529
          (rplaca insn1 'dup)
 
530
          (rplacd insn1 nil)
 
531
          (setq extra-stack 1)
 
532
          (setq keep-going t))
 
533
 
 
534
         ;; push X; {dup,push X}... --> push X; dup...
 
535
         ;; <varref> X; {dup,<varref> X}... --> <varref> X; dup...
 
536
         ((or (eq (car insn0) 'push)
 
537
              (memq (car insn0) byte-varref-insns))
 
538
          (setq tem (nthcdr 2 point))
 
539
          (while (or (eq (caar tem) 'dup)
 
540
                     (equal (car tem) insn0))
 
541
            (rplaca (car tem) 'dup)
 
542
            (rplacd (car tem) nil)
 
543
            (setq tem (cdr tem)))))
 
544
        (shift))
 
545
 
 
546
      ;; drop the extra cons we added
 
547
      (cons (cdr code-string) extra-stack))))