root/eaccelerator/tags/start/optimize.c

Revision 5, 115.1 kB (checked in by anonymous, 4 years ago)

This commit was manufactured by cvs2svn to create branch 'eAccelerator'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | Turck MMCache for PHP Version 4                                      |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
6    | http://www.turcksoft.com                                             |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
26    +----------------------------------------------------------------------+
27    $Id$
28 */
29
30 #include "eaccelerator.h"
31
32 #ifdef HAVE_EACCELERATOR
33 #ifdef WITH_EACCELERATOR_OPTIMIZER
34
35 #include "zend.h"
36 #include "zend_API.h"
37 #include "zend_constants.h"
38 #include "opcodes.h"
39
40 typedef unsigned int* set;
41
42 struct _BBlink;
43
44 typedef struct _BB {
45   zend_op*        start;
46   int             len;
47   int             used;
48   /*
49    * HOESH: To protect merging. Primary
50    * it abblies to try & catch blocks.
51    * ZEND_ENGINE_2 specific, but can take place
52    */
53   int             protect_merge;
54   struct _BB*     jmp_1;
55   struct _BB*     jmp_2;
56   struct _BB*     jmp_ext;
57   struct _BB*     follow;
58   struct _BBlink* pred;  // Gonna be a chain of BBs
59   struct _BB*     next;
60 } BB;
61
62 typedef struct _BBlink {
63   struct _BB*     bb;
64   struct _BBlink* next;
65 } BBlink;
66
67 #if 0
68 static void dump_bb(BB* bb, zend_op_array *op_array) {
69   BB* p = bb;
70   BBlink *q;
71   zend_printf("<pre>%s:%s\n", op_array->filename, op_array->function_name);
72   while (p != NULL) {
73     zend_printf("  bb%u start=%u len=%d used=%d\n",
74                  (unsigned int)(p-bb),
75                  (unsigned int)(p->start-op_array->opcodes),
76                  p->len,
77                  p->used);
78     if (p->jmp_1) {
79       zend_printf("    jmp_1 bb%u start=%u  len=%d used=%d\n",
80                   (unsigned int)(p->jmp_1-bb),
81                   (unsigned int)(p->jmp_1->start-op_array->opcodes),
82                   p->jmp_1->len,
83                   p->jmp_1->used);
84     }
85     if (p->jmp_2) {
86       zend_printf("    jmp_2 bb%u start=%u  len=%d used=%d\n",
87                   (unsigned int)(p->jmp_2-bb),
88                   (unsigned int)(p->jmp_2->start-op_array->opcodes),
89                   p->jmp_2->len,
90                   p->jmp_2->used);
91     }
92     if (p->jmp_ext) {
93       zend_printf("    jmp_ext bb%u start=%u  len=%d used=%d\n",
94                   (unsigned int)(p->jmp_ext-bb),
95                   (unsigned int)(p->jmp_ext->start-op_array->opcodes),
96                   p->jmp_ext->len,
97                   p->jmp_ext->used);
98     }
99     if (p->follow) {
100       zend_printf("    follow bb%u start=%u  len=%d used=%d\n",
101                   (unsigned int)(p->follow-bb),
102                   (unsigned int)(p->follow->start-op_array->opcodes),
103                   p->follow->len,
104                   p->follow->used);
105     }
106     q = p->pred;
107     while (q != NULL) {
108       zend_printf("    pred bb%u start=%u  len=%d used=%d (",
109                   (unsigned int)(q->bb-bb),
110                   (unsigned int)(q->bb->start-op_array->opcodes),
111                   q->bb->len,
112                   q->bb->used);
113       if (q->bb->jmp_1 == p) {
114         zend_printf("jmp_1 ");
115       }
116       if (q->bb->jmp_2 == p) {
117         zend_printf("jmp_2 ");
118       }
119       if (q->bb->jmp_ext == p) {
120         zend_printf("jmp_ext ");
121       }
122       if (q->bb->follow == p) {
123         zend_printf("follow ");
124       }
125       zend_printf(")\n");
126       q = q->next;
127     }
128     p = p->next;
129   }
130   zend_printf("</pre><hr>\n");
131   fflush(stdout);
132 }
133 #endif
134
135 #define SET_TO_NOP(op) \
136   (op)->opcode = ZEND_NOP; \
137   (op)->op1.op_type = IS_UNUSED; \
138   (op)->op2.op_type = IS_UNUSED; \
139   (op)->result.op_type = IS_UNUSED;
140
141 static void compute_live_var(BB* bb, zend_op_array* op_array, char* global)
142 {
143   BB* p = bb;
144   memset(global, 0, op_array->T * sizeof(char));
145   if (p != NULL && p->next != NULL) {
146     int bb_count = 0;
147     char *def     = do_alloca(op_array->T * sizeof(char));
148 #if 0
149     zend_printf("<hr>%s::%s<br>", op_array->filename, op_array->function_name);
150 #endif
151     while (p != NULL) {
152       zend_op* op = p->start;
153       zend_op* end = op + p->len;
154       memset(def, 0, op_array->T * sizeof(char));
155       while (op < end) {
156         if ((op->op1.op_type == IS_VAR || op->op1.op_type == IS_TMP_VAR) &&
157             !def[VAR_NUM(op->op1.u.var)] && !global[VAR_NUM(op->op1.u.var)]) {
158           global[VAR_NUM(op->op1.u.var)] = 1;
159         }
160         if ((op->op2.op_type == IS_VAR || op->op2.op_type == IS_TMP_VAR) &&
161             !def[VAR_NUM(op->op2.u.var)] && !global[VAR_NUM(op->op2.u.var)]) {
162 #ifdef ZEND_ENGINE_2
163           if (op->opcode != ZEND_OP_DATA) {
164             global[VAR_NUM(op->op2.u.var)] = 1;
165           }
166 #else
167           global[VAR_NUM(op->op2.u.var)] = 1;
168 #endif
169         }
170 #ifdef ZEND_ENGINE_2
171         if (op->opcode == ZEND_DECLARE_INHERITED_CLASS &&
172             !def[VAR_NUM(op->extended_value)] &&
173             !global[VAR_NUM(op->extended_value)]) {
174           global[VAR_NUM(op->extended_value)] = 1;
175         }
176 #endif
177         if ((op->result.op_type == IS_VAR &&
178 #ifdef ZEND_ENGINE_2
179              (op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT ||
180               (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
181 #else
182              (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
183 #endif
184             (op->result.op_type == IS_TMP_VAR)) {
185           if (!def[VAR_NUM(op->result.u.var)] && !global[VAR_NUM(op->result.u.var)]) {
186             switch (op->opcode) {
187               case ZEND_RECV:
188               case ZEND_RECV_INIT:
189               case ZEND_ADD_ARRAY_ELEMENT:
190                 global[VAR_NUM(op->result.u.var)] = 1;
191              }
192           }
193           def[VAR_NUM(op->result.u.var)] = 1;
194         }
195         op++;
196       }
197       p = p->next;
198       bb_count++;
199     }
200     free_alloca(def);
201   }
202   {
203     char *used = do_alloca(op_array->T * sizeof(char));
204     p = bb;
205     while (p != NULL) {
206       zend_op* op = p->start;
207       zend_op* end = op + p->len;
208       memset(used, 0, op_array->T * sizeof(char));
209       while (op < end) {
210         end--;
211         if (((end->result.op_type == IS_VAR &&
212 #ifdef ZEND_ENGINE_2
213              (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
214               (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
215 #else
216              (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
217 #endif
218              (end->result.op_type == IS_TMP_VAR)) &&
219             !global[VAR_NUM(end->result.u.var)] && !used[VAR_NUM(end->result.u.var)]) {
220            switch(end->opcode) {
221              case ZEND_JMPZ_EX:
222                end->opcode = ZEND_JMPZ;
223                end->result.op_type = IS_UNUSED;
224                break;
225              case ZEND_JMPNZ_EX:
226                end->opcode = ZEND_JMPNZ;
227                end->result.op_type = IS_UNUSED;
228                break;
229              case ZEND_ASSIGN_ADD:
230              case ZEND_ASSIGN_SUB:
231              case ZEND_ASSIGN_MUL:
232              case ZEND_ASSIGN_DIV:
233              case ZEND_ASSIGN_MOD:
234              case ZEND_ASSIGN_SL:
235              case ZEND_ASSIGN_SR:
236              case ZEND_ASSIGN_CONCAT:
237              case ZEND_ASSIGN_BW_OR:
238              case ZEND_ASSIGN_BW_AND:
239              case ZEND_ASSIGN_BW_XOR:
240              case ZEND_PRE_INC:
241              case ZEND_PRE_DEC:
242              case ZEND_POST_INC:
243              case ZEND_POST_DEC:
244              case ZEND_ASSIGN:
245              case ZEND_ASSIGN_REF:
246              case ZEND_DO_FCALL:
247              case ZEND_DO_FCALL_BY_NAME:
248                if (end->result.op_type == IS_VAR) {
249                  end->result.u.EA.type |= EXT_TYPE_UNUSED;
250                }
251                break;
252              case ZEND_UNSET_VAR:
253              case ZEND_UNSET_DIM_OBJ:
254                end->result.op_type = IS_UNUSED;
255                break;
256              case ZEND_RECV:
257              case ZEND_RECV_INIT:
258              /*case ZEND_ADD_ARRAY_ELEMENT:*/
259              case ZEND_INCLUDE_OR_EVAL:
260              case ZEND_JMP_NO_CTOR:
261              case ZEND_FE_FETCH:
262 #ifdef ZEND_ENGINE_2
263              case ZEND_DECLARE_CLASS:
264              case ZEND_DECLARE_INHERITED_CLASS:
265 #endif
266               break;
267             default:
268               if (end->op1.op_type == IS_CONST) {
269                 zval_dtor(&end->op1.u.constant);
270               }
271               if (end->op2.op_type == IS_CONST) {
272                 zval_dtor(&end->op2.u.constant);
273               }
274               SET_TO_NOP(end);
275           }
276         } else if (end->result.op_type == IS_VAR &&
277                    (end->result.u.EA.type & EXT_TYPE_UNUSED) != 0 &&
278 #ifdef ZEND_ENGINE_2
279                    end->opcode != ZEND_RECV && end->opcode != ZEND_RECV_INIT &&
280 #endif
281                    used[VAR_NUM(end->result.u.var)]) {
282           end->result.u.EA.type &= ~EXT_TYPE_UNUSED;
283         }
284         if ((end->result.op_type == IS_VAR &&
285 #ifdef ZEND_ENGINE_2
286             (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
287              (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
288 #else
289             (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
290 #endif
291             (end->result.op_type == IS_TMP_VAR)) {
292           switch (end->opcode) {
293             case ZEND_RECV:
294             case ZEND_RECV_INIT:
295             case ZEND_ADD_ARRAY_ELEMENT:
296               used[VAR_NUM(end->result.u.var)] = 1;
297               break;
298             default:
299               used[VAR_NUM(end->result.u.var)] = 0;
300            }
301         }
302         if (end->op1.op_type == IS_VAR || end->op1.op_type == IS_TMP_VAR) {
303           used[VAR_NUM(end->op1.u.var)] = 1;
304         }
305         if (end->op2.op_type == IS_VAR || end->op2.op_type == IS_TMP_VAR) {
306           used[VAR_NUM(end->op2.u.var)] = 1;
307         }
308 #ifdef ZEND_ENGINE_2
309         if (end->opcode == ZEND_DECLARE_INHERITED_CLASS) {
310           used[VAR_NUM(end->extended_value)] = 1;
311         }
312 #endif
313       }
314       p = p->next;
315     }
316     free_alloca(used);
317   }
318 /*
319   while (1) {
320     int change = 0;
321     p = bb;
322     while (p != NULL) {
323       int n = SET_SIZE(op_array->T);
324       while (n-- > 0) {
325         unsigned int old_in = p->in[n];
326         p->out[n] = 0;
327         if (p->jmp_1   != NULL) p->out[n] |= p->jmp_1->in[n];
328         if (p->jmp_2   != NULL) p->out[n] |= p->jmp_2->in[n];
329         if (p->jmp_ext != NULL) p->out[n] |= p->jmp_ext->in[n];
330         if (p->follow  != NULL) p->out[n] |= p->follow->in[n];
331         p->in[n] = p->use[n] | (p->out[n] & ~p->def[n]);
332         if (old_in != p->in[n]) change = 1;
333       }
334       p = p->next;
335     }
336     if (!change) break;
337   }
338 */
339 }
340
341 /* Adds FROM as predcessor of TO */
342 #define BB_ADD_PRED(TO,FROM) { \
343                                BBlink *q = (TO)->pred; \
344                                while (q != NULL) { \
345                                  if (q->bb == (FROM)) break; \
346                                  q = q->next; \
347                                } \
348                                if (q == NULL) { \
349                                  q = emalloc(sizeof(*q)); \
350                                  q->bb = (FROM); \
351                                  q->next = (TO)->pred; \
352                                  (TO)->pred = q; \
353                                } \
354                              }
355
356 /* Removes FROM from predcessors of TO */
357 #define BB_DEL_PRED(TO,FROM) { \
358                                BBlink *q = (TO)->pred; \
359                                if (q != NULL) { \
360                                  if (q->bb == (FROM)) { \
361                                    (TO)->pred = q->next; \
362                                    efree(q); \
363                                  } else { \
364                                    while (q->next != NULL) { \
365                                      if (q->next->bb == (FROM)) { \
366                                        BBlink *r = q->next; \
367                                        q->next = q->next->next; \
368                                        efree(r); \
369                                        break; \
370                                      } \
371                                      q = q->next; \
372                                    } \
373                                  } \
374                                } \
375                              }
376
377 #define RM_BB(p) do {if (p->pred == NULL && p != bb) rm_bb(p);} while (0)
378
379 static void mark_used_bb(BB* bb)
380 {
381   if (bb->used) return;
382   bb->used = 1;
383   if (bb->jmp_1 != NULL) {
384     mark_used_bb(bb->jmp_1);
385     BB_ADD_PRED(bb->jmp_1, bb);
386   }
387   if (bb->jmp_2 != NULL) {
388     mark_used_bb(bb->jmp_2);
389     BB_ADD_PRED(bb->jmp_2, bb);
390   }
391   if (bb->jmp_ext != NULL) {
392     mark_used_bb(bb->jmp_ext);
393     BB_ADD_PRED(bb->jmp_ext, bb);
394   }
395   if (bb->follow != NULL) {
396     mark_used_bb(bb->follow);
397     BB_ADD_PRED(bb->follow, bb);
398   }
399 }
400
401 static void mark_used_bb2(BB* bb)
402 {
403   if (bb->used) return;
404   bb->used = 1;
405   if (bb->jmp_1 != NULL) {
406     mark_used_bb2(bb->jmp_1);
407   }
408   if (bb->jmp_2 != NULL) {
409     mark_used_bb2(bb->jmp_2);
410   }
411   if (bb->jmp_ext != NULL) {
412     mark_used_bb2(bb->jmp_ext);
413   }
414   if (bb->follow != NULL) {
415     mark_used_bb2(bb->follow);
416   }
417 }
418
419 static void rm_bb(BB* bb)
420 {
421   if (bb->used == 0) {
422     return;
423   }
424   bb->used = 0;
425   if (bb->jmp_1 != NULL) {
426     BB_DEL_PRED(bb->jmp_1, bb);
427   }
428   if (bb->jmp_2 != NULL) {
429     BB_DEL_PRED(bb->jmp_2, bb);
430   }
431   if (bb->jmp_ext != NULL) {
432     BB_DEL_PRED(bb->jmp_ext, bb);
433   }
434   if (bb->follow != NULL) {
435     BB_DEL_PRED(bb->follow, bb);
436   }
437 }
438
439 static void del_bb(BB* bb)
440 {
441   zend_op* op = bb->start;
442   zend_op* end = op + bb->len;
443
444   rm_bb(bb);
445   while (op < end) {
446     --end;
447     if (end->op1.op_type == IS_CONST) {
448       zval_dtor(&end->op1.u.constant);
449     }
450     if (end->op2.op_type == IS_CONST) {
451       zval_dtor(&end->op2.u.constant);
452     }
453     SET_TO_NOP(end);
454   }
455   bb->len  = 0;
456   bb->used = 0;
457 }
458
459 static void replace_bb(BB* src, BB* dst)
460 {
461   BBlink* p = src->pred;
462   while (p != NULL) {
463     BBlink* q = p->next;
464     if (p->bb->jmp_1   == src) {
465       p->bb->jmp_1 = dst;
466       BB_ADD_PRED(dst,p->bb);
467     }
468     if (p->bb->jmp_2   == src) {
469       p->bb->jmp_2 = dst;
470       BB_ADD_PRED(dst,p->bb);
471     }
472     if (p->bb->jmp_ext == src) {
473       p->bb->jmp_ext = dst;
474       BB_ADD_PRED(dst,p->bb);
475     }
476     if (p->bb->follow  == src) {
477       p->bb->follow = dst;
478       BB_ADD_PRED(dst,p->bb);
479     }
480     efree(p);
481     p = q;
482   }
483   src->pred = NULL;
484 }
485
486 static void optimize_jmp(BB* bb, zend_op_array* op_array)
487 {
488   BB* p;
489
490   while(1) {
491     int ok = 1;
492
493     /* Remove Unused Basic Blocks */
494     p = bb;
495     while (p->next != NULL) {
496       if (p->next->used && p->next->pred) {
497         p = p->next;
498       } else {
499         del_bb(p->next);
500         p->next = p->next->next;
501         ok = 0;
502       }
503     }
504
505     /* Clear leading NOP(s) */
506     p = bb;
507     while (p != NULL) {
508       if (p->used) {
509         while (p->len > 0 && p->start->opcode ==ZEND_NOP) {
510           p->start++;
511           p->len--;
512         }
513         if (p->len == 0 && p != bb) {
514           if (p->follow) {
515             replace_bb(p, p->follow);
516           }
517           rm_bb(p);
518           p->used = 0;
519           ok = 0;
520         }
521       }
522       p = p->next;
523     }
524
525     /* JMP optimization */
526     p = bb;
527     while (p != NULL) {
528       while (p->next != NULL && (!p->next->used || p->next->pred == NULL)) {
529         del_bb(p->next);
530         p->next = p->next->next;
531         ok = 0;
532       }
533       if (p->used && p->len > 0) {
534         zend_op* op = &p->start[p->len-1];
535
536         switch (op->opcode) {
537           case ZEND_JMP:
538 jmp:
539             /* L1: JMP L1+1  => NOP
540             */
541             if (p->jmp_1 == p->next) {
542               p->follow = p->jmp_1;
543               p->jmp_1   = NULL;
544               SET_TO_NOP(op);
545               --(p->len);
546               ok = 0;
547               break;
548             }
549             /*     JMP L1  =>  JMP L2
550                    ...         ...
551                L1: JMP L2      JMP L2
552             */
553             while (p->jmp_1->len == 1 &&
554                 p->jmp_1->start->opcode == ZEND_JMP &&
555                 p->jmp_1 != p) {
556               BB* x_p = p->jmp_1;
557               BB_DEL_PRED(p->jmp_1, p);
558               RM_BB(x_p);
559               p->jmp_1 = x_p->jmp_1;
560               BB_ADD_PRED(p->jmp_1, p);
561               ok = 0;
562             }
563             break;
564           case ZEND_JMPZNZ:
565 jmp_znz:
566             /* JMPZNZ  ?,L1,L1  =>  JMP L1
567             */
568             if (p->jmp_ext == p->jmp_2) {
569               op->opcode = ZEND_JMP;
570               op->extended_value = 0;
571               op->op1.op_type = IS_UNUSED;
572               op->op2.op_type = IS_UNUSED;
573               p->jmp_1 = p->jmp_2;
574               p->jmp_2 = NULL;
575               p->jmp_ext = NULL;
576               ok = 0;
577               goto jmp;
578             } else if (op->op1.op_type == IS_CONST) {
579               /* JMPZNZ  0,L1,L2  =>  JMP L1
580               */
581               if (!zend_is_true(&op->op1.u.constant)) {
582                 op->opcode = ZEND_JMP;
583                 op->extended_value = 0;
584                 op->op1.op_type = IS_UNUSED;
585                 op->op2.op_type = IS_UNUSED;
586                 if (p->jmp_ext != p->jmp_2) {
587                   BB_DEL_PRED(p->jmp_ext, p);
588                   RM_BB(p->jmp_ext);
589                 }
590                 p->jmp_1   = p->jmp_2;
591                 p->jmp_2   = NULL;
592                 p->jmp_ext = NULL;
593                 p->follow  = NULL;
594                 ok = 0;
595                 goto jmp;
596               /* JMPZNZ  1,L1,L2  =>  JMP L2
597               */
598               } else {
599                 op->opcode = ZEND_JMP;
600                 op->extended_value = 0;
601                 op->op1.op_type = IS_UNUSED;
602                 op->op2.op_type = IS_UNUSED;
603                 if (p->jmp_ext != p->jmp_2) {
604                   BB_DEL_PRED(p->jmp_2, p);
605                   RM_BB(p->jmp_2);
606                 }
607                 p->jmp_1   = p->jmp_ext;
608                 p->jmp_2   = NULL;
609                 p->jmp_ext = NULL;
610                 p->follow  = NULL;
611                 ok = 0;
612                 goto jmp;
613               }
614             /* L1: JMPZNZ ?,L2,L1+1  => JMPZ ?,L2
615             */
616             } else if (p->jmp_ext == p->next) {
617               op->opcode = ZEND_JMPZ;
618               op->extended_value = 0;
619               p->follow = p->jmp_ext;
620               p->jmp_ext = NULL;
621               ok = 0;
622               goto jmp_z;
623             /* L1: JMPZNZ ?,L1+1,L2  => JMPNZ ?,L2
624             */
625             } else if (p->jmp_2 == p->next) {
626               op->opcode = ZEND_JMPNZ;
627               op->extended_value = 0;
628               p->follow = p->jmp_2;
629               p->jmp_2  = p->jmp_ext;
630               p->jmp_ext = NULL;
631               ok = 0;
632               goto jmp_nz;
633             } else if (p->jmp_2->len == 1 &&
634                        op->op1.op_type == IS_TMP_VAR) {
635             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
636                    ...                  ...
637                L1: JMPZ   $x,L3         JMPZ   $x,L3
638             */
639             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
640                    ...                  ...
641                L1: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
642             */
643             if        ((p->jmp_2->start->opcode == ZEND_JMPZ ||
644                         p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
645                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
646                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
647               if (p->jmp_2 != p->jmp_ext) {
648                 BB_DEL_PRED(p->jmp_2, p);
649                 RM_BB(p->jmp_2);
650               }
651               p->jmp_2 = p->jmp_2->jmp_2;
652               BB_ADD_PRED(p->jmp_2, p);
653               ok = 0;
654               goto jmp_znz;
655             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1+1,L2
656                    ...                  ...
657                L1: JMPNZ  $x,L3         JMPNZ  $x,L3
658             */
659             } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
660                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
661                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
662               if (p->jmp_2 != p->jmp_ext) {
663                 BB_DEL_PRED(p->jmp_2, p);
664                 RM_BB(p->jmp_2);
665               }
666               p->jmp_2 = p->jmp_2->follow;
667               BB_ADD_PRED(p->jmp_2, p);
668               ok = 0;
669               goto jmp_znz;
670             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L3
671                    ...                  ...
672                L2: JMPNZ  $x,L3         JMPNZ  $x,L3
673             */
674             } else if (p->jmp_ext->start->opcode == ZEND_JMPNZ &&
675                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
676                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
677               if (p->jmp_2 != p->jmp_ext) {
678                 BB_DEL_PRED(p->jmp_ext, p);
679                 RM_BB(p->jmp_ext);
680               }
681               p->jmp_ext = p->jmp_ext->jmp_2;
682               BB_ADD_PRED(p->jmp_ext, p);
683               ok = 0;
684               goto jmp_znz;
685             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L4
686                    ...                  ...
687                L2: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
688             */
689             } else if (p->jmp_ext->start->opcode == ZEND_JMPZNZ &&
690                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
691                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
692               if (p->jmp_2 != p->jmp_ext) {
693                 BB_DEL_PRED(p->jmp_ext, p);
694                 RM_BB(p->jmp_ext);
695               }
696               p->jmp_ext = p->jmp_ext->jmp_ext;
697               BB_ADD_PRED(p->jmp_ext, p);
698               ok = 0;
699               goto jmp_znz;
700             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L2+1
701                    ...                  ...
702                L2: JMPZ   $x,L3         JMPZ   $x,L3
703             */
704             } else if (p->jmp_ext->start->opcode == ZEND_JMPZ &&
705                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
706                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
707               if (p->jmp_2 != p->jmp_ext) {
708                 BB_DEL_PRED(p->jmp_ext, p);
709                 RM_BB(p->jmp_ext);
710               }
711               p->jmp_ext = p->jmp_ext->follow;
712               BB_ADD_PRED(p->jmp_ext, p);
713               ok = 0;
714               goto jmp_znz;
715             }
716             }
717             while (p->jmp_2->len == 1 && p->jmp_2->start->opcode == ZEND_JMP) {
718               BB* x_p = p->jmp_2;
719               if (p->jmp_2 != p->jmp_ext) {
720                 BB_DEL_PRED(p->jmp_2, p);
721                 RM_BB(x_p);
722               }
723               p->jmp_2 = x_p->jmp_1;
724               BB_ADD_PRED(p->jmp_2, p);
725               ok = 0;
726             }
727             while (p->jmp_ext->len == 1 && p->jmp_ext->start->opcode == ZEND_JMP) {
728               BB* x_p = p->jmp_ext;
729               if (p->jmp_2 != p->jmp_ext) {
730                 BB_DEL_PRED(p->jmp_ext, p);
731                 RM_BB(x_p);
732               }
733               p->jmp_ext = x_p->jmp_1;
734               BB_ADD_PRED(p->jmp_ext, p);
735               ok = 0;
736             }
737             break;
738           case ZEND_JMPZ:
739 jmp_z:
740             /* L1: JMPZ  ?,L1+1  =>  NOP
741             */
742             if (p->follow == p->jmp_2) {
743               p->jmp_2   = NULL;
744               SET_TO_NOP(op);
745               --(p->len);
746               ok = 0;
747               break;
748             } else if (op->op1.op_type == IS_CONST) {
749               /* JMPZ  0,L1  =>  JMP L1
750               */
751               if (!zend_is_true(&op->op1.u.constant)) {
752                 op->opcode = ZEND_JMP;
753                 op->op1.op_type = IS_UNUSED;
754                 op->op2.op_type = IS_UNUSED;
755                 if (p->follow != p->jmp_2) {
756                   BB_DEL_PRED(p->follow, p);
757                   RM_BB(p->follow);
758                 }
759                 p->jmp_1  = p->jmp_2;
760                 p->jmp_2  = NULL;
761                 p->follow = NULL;
762                 ok = 0;
763                 goto jmp;
764               /* JMPZ  1,L1  =>  NOP
765               */
766               } else {
767                 if (p->follow != p->jmp_2) {
768                   BB_DEL_PRED(p->jmp_2, p);
769                   RM_BB(p->jmp_2);
770                 }
771                 p->jmp_2   = NULL;
772                 SET_TO_NOP(op);
773                 --(p->len);
774                 ok = 0;
775                 break;
776               }
777             /* JMPZ ?,L1  =>  JMPZNZ  ?,L1,L2
778                JMP  L2        JMP     L2
779             */
780             } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
781               BB* x_p = p->follow;
782               op->opcode = ZEND_JMPZNZ;
783               if (p->jmp_2 != p->follow) {
784                 BB_DEL_PRED(p->follow, p);
785                 RM_BB(x_p);
786               }
787               p->follow = NULL;
788               p->jmp_ext = x_p->jmp_1;
789               BB_ADD_PRED(p->jmp_ext, p);
790               ok = 0;
791               goto jmp_znz;
792             } else if (p->jmp_2->len == 1 &&
793                        op->op1.op_type == IS_TMP_VAR) {
794             /*     JMPZ $x,L1  =>  JMPZ $x,L2
795                    ...             ...
796                L1: JMPZ $x,L2      JMPZ $x,L2
797                ----------------------------------------
798                    JMPZ   $x,L1     =>  JMPZ  $x,L2
799                    ...                   ...
800                L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
801             */
802             if       ((p->jmp_2->start->opcode == ZEND_JMPZ ||
803                        p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
804                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
805                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
806               if (p->jmp_2 != p->follow) {
807                 BB_DEL_PRED(p->jmp_2, p);
808                 RM_BB(p->jmp_2);
809               }
810               p->jmp_2 = p->jmp_2->jmp_2;
811               BB_ADD_PRED(p->jmp_2, p);
812               ok = 0;
813               goto jmp_z;
814             /*     JMPZ  $x,L1  =>  JMPZ  $x,L1+1
815                    ...              ...
816                L1: JMPNZ $x,L2      JMPNZ $x,L2
817             */
818             } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
819                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
820                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
821               if (p->jmp_2 != p->follow) {
822                 BB_DEL_PRED(p->jmp_2, p);
823                 RM_BB(p->jmp_2);
824               }
825               p->jmp_2 = p->jmp_2->follow;
826               BB_ADD_PRED(p->jmp_2, p);
827               ok = 0;
828               goto jmp_z;
829             }
830             }
831             goto jmp_2;
832           case ZEND_JMPNZ:
833 jmp_nz:
834             /* L1: JMPNZ  ?,L1+1  =>  NOP
835             */
836             if (p->follow == p->jmp_2) {
837               p->jmp_2   = NULL;
838               SET_TO_NOP(op);
839               --(p->len);
840               ok = 0;
841               break;
842             } else if (op->op1.op_type == IS_CONST) {
843               /* JMPNZ  1,L1  =>  JMP L1
844               */
845               if (zend_is_true(&op->op1.u.constant)) {
846                 op->opcode = ZEND_JMP;
847                 op->op1.op_type = IS_UNUSED;
848                 op->op2.op_type = IS_UNUSED;
849                 if (p->follow != p->jmp_2) {
850                   BB_DEL_PRED(p->follow, p);
851                   RM_BB(p->follow);
852                 }
853                 p->jmp_1  = p->jmp_2;
854                 p->jmp_2  = NULL;
855                 p->follow = NULL;
856                 ok = 0;
857                 goto jmp;
858               /* JMPNZ  0,L1  =>  NOP
859               */
860               } else {
861                 if (p->follow != p->jmp_2) {
862                   BB_DEL_PRED(p->jmp_2, p);
863                   RM_BB(p->jmp_2);
864                 }
865                 p->jmp_2   = NULL;
866                 SET_TO_NOP(op);
867                 --(p->len);
868                 ok = 0;
869                 break;
870               }
871             /* JMPNZ ?,L1  =>  JMPZNZ  ?,L2,L1
872                JMP   L2        JMP     L2
873             */
874             } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
875               BB* x_p = p->follow;
876               op->opcode = ZEND_JMPZNZ;
877               if (p->jmp_2 != p->follow) {
878                 BB_DEL_PRED(p->follow, p);
879                 RM_BB(p->follow);
880               }
881               p->follow = NULL;
882               p->jmp_ext = p->jmp_2;
883               p->jmp_2 = x_p->jmp_1;
884               BB_ADD_PRED(p->jmp_2, p);
885               ok = 0;
886               goto jmp_znz;
887             /*     JMPNZ $x,L1  =>  JMPNZ $x,L2
888                    ...              ...
889                L1: JMPNZ $x,L2      JMPNZ $x,L2
890             */
891             } else if (p->jmp_2->len == 1 &&
892                        op->op1.op_type == IS_TMP_VAR) {
893             if        (p->jmp_2->start->opcode == ZEND_JMPNZ &&
894                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
895                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
896               if (p->jmp_2 != p->follow) {
897                 BB_DEL_PRED(p->jmp_2, p);
898                 RM_BB(p->jmp_2);
899               }
900               p->jmp_2 = p->jmp_2->jmp_2;
901               BB_ADD_PRED(p->jmp_2, p);
902               ok = 0;
903               goto jmp_nz;
904             /*     JMPNZ  $x,L1  =>  JMPNZ  $x,L1+1
905                    ...               ...
906                L1: JMPZ   $x,L2      JMPZ $x,L2
907             */
908             } else if (p->jmp_2->start->opcode == ZEND_JMPZ &&
909                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
910                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
911               if (p->jmp_2 != p->follow) {
912                 BB_DEL_PRED(p->jmp_2, p);
913                 RM_BB(p->jmp_2);
914               }
915               p->jmp_2 = p->jmp_2->follow;
916               BB_ADD_PRED(p->jmp_2, p);
917               ok = 0;
918               goto jmp_nz;
919             /*     JMPNZ  $x,L1     =>  JMPNZ  $x,L3
920                    ...                   ...
921                L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
922             */
923             } else if (p->jmp_2->start->opcode == ZEND_JMPZNZ &&
924                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
925                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
926               if (p->jmp_2 != p->follow) {
927                 BB_DEL_PRED(p->jmp_2, p);
928                 RM_BB(p->jmp_2);
929               }
930               p->jmp_2 = p->jmp_2->jmp_ext;
931               BB_ADD_PRED(p->jmp_2, p);
932               ok = 0;
933               goto jmp_nz;
934             }
935             }
936             goto jmp_2;
937           case ZEND_JMPZ_EX:
938 jmp_z_ex:
939             /* L1: JMPZ_EX  $x,L1+1,$x  =>  NOP
940             */
941             if (p->follow == p->jmp_2 &&
942                 op->op1.op_type == IS_TMP_VAR &&
943                 op->result.op_type == IS_TMP_VAR &&
944                 op->op1.u.var == op->result.u.var) {
945               p->jmp_2   = NULL;
946               SET_TO_NOP(op);
947               --(p->len);
948               ok = 0;
949               break;
950             /* L1: JMPZ_EX  $x,L1+1,$y  =>  BOOL $x,$y
951             */
952             } else if (p->follow == p->jmp_2) {
953               p->jmp_2   = NULL;
954               op->opcode = ZEND_BOOL;
955               op->op2.op_type = IS_UNUSED;
956               ok = 0;
957               break;
958             } else if (p->jmp_2->len == 1 &&
959                        op->result.op_type == IS_TMP_VAR) {
960             /*     JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
961                    ...                  ...
962                L1: JMPZ    $x,L2        JMPZ    $x,L2
963                ------------------------------------------
964                    JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
965                    ...                  ...
966                L1: JMPZNZ  $x,L2,L3     JMPZNZ  $x,L2,L3
967                ------------------------------------------
968                    JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
969                    ...                  ...
970                L1: JMPZ_EX $x,L2,$x     JMPZ_EX $x,L2,$x
971             */
972             if       (((p->jmp_2->start->opcode == ZEND_JMPZ ||
973                          p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
974                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
975                         op->result.u.var == p->jmp_2->start->op1.u.var) ||
976                        (p->jmp_2->start->opcode == ZEND_JMPZ_EX &&
977                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
978                         p->jmp_2->start->result.op_type == IS_TMP_VAR &