root/eaccelerator/tags/0.9.4/optimize.c

Revision 133, 115.4 kB (checked in by zoeloelip, 3 years ago)

Fixed optimizer bug with php 5.0.5

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 eAccelerator                                      |
6    | http://eaccelerator.sourceforge.net                                  |
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(s): Dmitry Stogov <dstogov@users.sourceforge.net>             |
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_ASSIGN_DIM:
264              case ZEND_DECLARE_CLASS:
265              case ZEND_DECLARE_INHERITED_CLASS:
266 #endif
267               break;
268             default:
269               if (end->op1.op_type == IS_CONST) {
270                 zval_dtor(&end->op1.u.constant);
271               }
272               if (end->op2.op_type == IS_CONST) {
273                 zval_dtor(&end->op2.u.constant);
274               }
275               SET_TO_NOP(end);
276           }
277         } else if (end->result.op_type == IS_VAR &&
278                    (end->result.u.EA.type & EXT_TYPE_UNUSED) != 0 &&
279 #ifdef ZEND_ENGINE_2
280                    end->opcode != ZEND_RECV && end->opcode != ZEND_RECV_INIT &&
281 #endif
282                    used[VAR_NUM(end->result.u.var)]) {
283           end->result.u.EA.type &= ~EXT_TYPE_UNUSED;
284         }
285         if ((end->result.op_type == IS_VAR &&
286 #ifdef ZEND_ENGINE_2
287             (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
288              (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
289 #else
290             (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
291 #endif
292             (end->result.op_type == IS_TMP_VAR)) {
293           switch (end->opcode) {
294             case ZEND_RECV:
295             case ZEND_RECV_INIT:
296             case ZEND_ADD_ARRAY_ELEMENT:
297               used[VAR_NUM(end->result.u.var)] = 1;
298               break;
299             default:
300               used[VAR_NUM(end->result.u.var)] = 0;
301            }
302         }
303         if (end->op1.op_type == IS_VAR || end->op1.op_type == IS_TMP_VAR) {
304           used[VAR_NUM(end->op1.u.var)] = 1;
305         }
306         if (end->op2.op_type == IS_VAR || end->op2.op_type == IS_TMP_VAR) {
307           used[VAR_NUM(end->op2.u.var)] = 1;
308         }
309 #ifdef ZEND_ENGINE_2
310         if (end->opcode == ZEND_DECLARE_INHERITED_CLASS) {
311           used[VAR_NUM(end->extended_value)] = 1;
312         }
313 #endif
314       }
315       p = p->next;
316     }
317     free_alloca(used);
318   }
319 /*
320   while (1) {
321     int change = 0;
322     p = bb;
323     while (p != NULL) {
324       int n = SET_SIZE(op_array->T);
325       while (n-- > 0) {
326         unsigned int old_in = p->in[n];
327         p->out[n] = 0;
328         if (p->jmp_1   != NULL) p->out[n] |= p->jmp_1->in[n];
329         if (p->jmp_2   != NULL) p->out[n] |= p->jmp_2->in[n];
330         if (p->jmp_ext != NULL) p->out[n] |= p->jmp_ext->in[n];
331         if (p->follow  != NULL) p->out[n] |= p->follow->in[n];
332         p->in[n] = p->use[n] | (p->out[n] & ~p->def[n]);
333         if (old_in != p->in[n]) change = 1;
334       }
335       p = p->next;
336     }
337     if (!change) break;
338   }
339 */
340 }
341
342 /* Adds FROM as predcessor of TO */
343 #define BB_ADD_PRED(TO,FROM) { \
344                                BBlink *q = (TO)->pred; \
345                                while (q != NULL) { \
346                                  if (q->bb == (FROM)) break; \
347                                  q = q->next; \
348                                } \
349                                if (q == NULL) { \
350                                  q = emalloc(sizeof(*q)); \
351                                  q->bb = (FROM); \
352                                  q->next = (TO)->pred; \
353                                  (TO)->pred = q; \
354                                } \
355                              }
356
357 /* Removes FROM from predcessors of TO */
358 #define BB_DEL_PRED(TO,FROM) { \
359                                BBlink *q = (TO)->pred; \
360                                if (q != NULL) { \
361                                  if (q->bb == (FROM)) { \
362                                    (TO)->pred = q->next; \
363                                    efree(q); \
364                                  } else { \
365                                    while (q->next != NULL) { \
366                                      if (q->next->bb == (FROM)) { \
367                                        BBlink *r = q->next; \
368                                        q->next = q->next->next; \
369                                        efree(r); \
370                                        break; \
371                                      } \
372                                      q = q->next; \
373                                    } \
374                                  } \
375                                } \
376                              }
377
378 #define RM_BB(p) do {if (p->pred == NULL && p != bb) rm_bb(p);} while (0)
379
380 static void mark_used_bb(BB* bb)
381 {
382   if (bb->used) return;
383   bb->used = 1;
384   if (bb->jmp_1 != NULL) {
385     mark_used_bb(bb->jmp_1);
386     BB_ADD_PRED(bb->jmp_1, bb);
387   }
388   if (bb->jmp_2 != NULL) {
389     mark_used_bb(bb->jmp_2);
390     BB_ADD_PRED(bb->jmp_2, bb);
391   }
392   if (bb->jmp_ext != NULL) {
393     mark_used_bb(bb->jmp_ext);
394     BB_ADD_PRED(bb->jmp_ext, bb);
395   }
396   if (bb->follow != NULL) {
397     mark_used_bb(bb->follow);
398     BB_ADD_PRED(bb->follow, bb);
399   }
400 }
401
402 static void mark_used_bb2(BB* bb)
403 {
404   if (bb->used) return;
405   bb->used = 1;
406   if (bb->jmp_1 != NULL) {
407     mark_used_bb2(bb->jmp_1);
408   }
409   if (bb->jmp_2 != NULL) {
410     mark_used_bb2(bb->jmp_2);
411   }
412   if (bb->jmp_ext != NULL) {
413     mark_used_bb2(bb->jmp_ext);
414   }
415   if (bb->follow != NULL) {
416     mark_used_bb2(bb->follow);
417   }
418 }
419
420 static void rm_bb(BB* bb)
421 {
422   if (bb->used == 0) {
423     return;
424   }
425   bb->used = 0;
426   if (bb->jmp_1 != NULL) {
427     BB_DEL_PRED(bb->jmp_1, bb);
428   }
429   if (bb->jmp_2 != NULL) {
430     BB_DEL_PRED(bb->jmp_2, bb);
431   }
432   if (bb->jmp_ext != NULL) {
433     BB_DEL_PRED(bb->jmp_ext, bb);
434   }
435   if (bb->follow != NULL) {
436     BB_DEL_PRED(bb->follow, bb);
437   }
438 }
439
440 static void del_bb(BB* bb)
441 {
442   zend_op* op = bb->start;
443   zend_op* end = op + bb->len;
444
445   rm_bb(bb);
446   while (op < end) {
447     --end;
448     if (end->op1.op_type == IS_CONST) {
449       zval_dtor(&end->op1.u.constant);
450     }
451     if (end->op2.op_type == IS_CONST) {
452       zval_dtor(&end->op2.u.constant);
453     }
454     SET_TO_NOP(end);
455   }
456   bb->len  = 0;
457   bb->used = 0;
458 }
459
460 static void replace_bb(BB* src, BB* dst)
461 {
462   BBlink* p = src->pred;
463   while (p != NULL) {
464     BBlink* q = p->next;
465     if (p->bb->jmp_1   == src) {
466       p->bb->jmp_1 = dst;
467       BB_ADD_PRED(dst,p->bb);
468     }
469     if (p->bb->jmp_2   == src) {
470       p->bb->jmp_2 = dst;
471       BB_ADD_PRED(dst,p->bb);
472     }
473     if (p->bb->jmp_ext == src) {
474       p->bb->jmp_ext = dst;
475       BB_ADD_PRED(dst,p->bb);
476     }
477     if (p->bb->follow  == src) {
478       p->bb->follow = dst;
479       BB_ADD_PRED(dst,p->bb);
480     }
481     efree(p);
482     p = q;
483   }
484   src->pred = NULL;
485 }
486
487 static void optimize_jmp(BB* bb, zend_op_array* op_array)
488 {
489   BB* p;
490
491   while(1) {
492     int ok = 1;
493
494     /* Remove Unused Basic Blocks */
495     p = bb;
496     while (p->next != NULL) {
497       if (p->next->used && p->next->pred) {
498         p = p->next;
499       } else {
500         del_bb(p->next);
501         p->next = p->next->next;
502         ok = 0;
503       }
504     }
505
506     /* Clear leading NOP(s) */
507     p = bb;
508     while (p != NULL) {
509       if (p->used) {
510         while (p->len > 0 && p->start->opcode ==ZEND_NOP) {
511           p->start++;
512           p->len--;
513         }
514         if (p->len == 0 && p != bb) {
515           if (p->follow) {
516             replace_bb(p, p->follow);
517           }
518           rm_bb(p);
519           p->used = 0;
520           ok = 0;
521         }
522       }
523       p = p->next;
524     }
525
526     /* JMP optimization */
527     p = bb;
528     while (p != NULL) {
529       while (p->next != NULL && (!p->next->used || p->next->pred == NULL)) {
530         del_bb(p->next);
531         p->next = p->next->next;
532         ok = 0;
533       }
534       if (p->used && p->len > 0) {
535         zend_op* op = &p->start[p->len-1];
536
537         switch (op->opcode) {
538           case ZEND_JMP:
539 jmp:
540             /* L1: JMP L1+1  => NOP
541             */
542             if (p->jmp_1 == p->next) {
543               p->follow = p->jmp_1;
544               p->jmp_1   = NULL;
545               SET_TO_NOP(op);
546               --(p->len);
547               ok = 0;
548               break;
549             }
550             /*     JMP L1  =>  JMP L2
551                    ...         ...
552                L1: JMP L2      JMP L2
553             */
554             while (p->jmp_1->len == 1 &&
555                 p->jmp_1->start->opcode == ZEND_JMP &&
556                 p->jmp_1 != p) {
557               BB* x_p = p->jmp_1;
558               BB_DEL_PRED(p->jmp_1, p);
559               RM_BB(x_p);
560               p->jmp_1 = x_p->jmp_1;
561               BB_ADD_PRED(p->jmp_1, p);
562               ok = 0;
563             }
564             break;
565           case ZEND_JMPZNZ:
566 jmp_znz:
567             /* JMPZNZ  ?,L1,L1  =>  JMP L1
568             */
569             if (p->jmp_ext == p->jmp_2) {
570               op->opcode = ZEND_JMP;
571               op->extended_value = 0;
572               op->op1.op_type = IS_UNUSED;
573               op->op2.op_type = IS_UNUSED;
574               p->jmp_1 = p->jmp_2;
575               p->jmp_2 = NULL;
576               p->jmp_ext = NULL;
577               ok = 0;
578               goto jmp;
579             } else if (op->op1.op_type == IS_CONST) {
580               /* JMPZNZ  0,L1,L2  =>  JMP L1
581               */
582               if (!zend_is_true(&op->op1.u.constant)) {
583                 op->opcode = ZEND_JMP;
584                 op->extended_value = 0;
585                 op->op1.op_type = IS_UNUSED;
586                 op->op2.op_type = IS_UNUSED;
587                 if (p->jmp_ext != p->jmp_2) {
588                   BB_DEL_PRED(p->jmp_ext, p);
589                   RM_BB(p->jmp_ext);
590                 }
591                 p->jmp_1   = p->jmp_2;
592                 p->jmp_2   = NULL;
593                 p->jmp_ext = NULL;
594                 p->follow  = NULL;
595                 ok = 0;
596                 goto jmp;
597               /* JMPZNZ  1,L1,L2  =>  JMP L2
598               */
599               } else {
600                 op->opcode = ZEND_JMP;
601                 op->extended_value = 0;
602                 op->op1.op_type = IS_UNUSED;
603                 op->op2.op_type = IS_UNUSED;
604                 if (p->jmp_ext != p->jmp_2) {
605                   BB_DEL_PRED(p->jmp_2, p);
606                   RM_BB(p->jmp_2);
607                 }
608                 p->jmp_1   = p->jmp_ext;
609                 p->jmp_2   = NULL;
610                 p->jmp_ext = NULL;
611                 p->follow  = NULL;
612                 ok = 0;
613                 goto jmp;
614               }
615             /* L1: JMPZNZ ?,L2,L1+1  => JMPZ ?,L2
616             */
617             } else if (p->jmp_ext == p->next) {
618               op->opcode = ZEND_JMPZ;
619               op->extended_value = 0;
620               p->follow = p->jmp_ext;
621               p->jmp_ext = NULL;
622               ok = 0;
623               goto jmp_z;
624             /* L1: JMPZNZ ?,L1+1,L2  => JMPNZ ?,L2
625             */
626             } else if (p->jmp_2 == p->next) {
627               op->opcode = ZEND_JMPNZ;
628               op->extended_value = 0;
629               p->follow = p->jmp_2;
630               p->jmp_2  = p->jmp_ext;
631               p->jmp_ext = NULL;
632               ok = 0;
633               goto jmp_nz;
634             } else if (p->jmp_2->len == 1 &&
635                        op->op1.op_type == IS_TMP_VAR) {
636             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
637                    ...                  ...
638                L1: JMPZ   $x,L3         JMPZ   $x,L3
639             */
640             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
641                    ...                  ...
642                L1: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
643             */
644             if        ((p->jmp_2->start->opcode == ZEND_JMPZ ||
645                         p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
646                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
647                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
648               if (p->jmp_2 != p->jmp_ext) {
649                 BB_DEL_PRED(p->jmp_2, p);
650                 RM_BB(p->jmp_2);
651               }
652               p->jmp_2 = p->jmp_2->jmp_2;
653               BB_ADD_PRED(p->jmp_2, p);
654               ok = 0;
655               goto jmp_znz;
656             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1+1,L2
657                    ...                  ...
658                L1: JMPNZ  $x,L3         JMPNZ  $x,L3
659             */
660             } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
661                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
662                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
663               if (p->jmp_2 != p->jmp_ext) {
664                 BB_DEL_PRED(p->jmp_2, p);
665                 RM_BB(p->jmp_2);
666               }
667               p->jmp_2 = p->jmp_2->follow;
668               BB_ADD_PRED(p->jmp_2, p);
669               ok = 0;
670               goto jmp_znz;
671             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L3
672                    ...                  ...
673                L2: JMPNZ  $x,L3         JMPNZ  $x,L3
674             */
675             } else if (p->jmp_ext->start->opcode == ZEND_JMPNZ &&
676                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
677                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
678               if (p->jmp_2 != p->jmp_ext) {
679                 BB_DEL_PRED(p->jmp_ext, p);
680                 RM_BB(p->jmp_ext);
681               }
682               p->jmp_ext = p->jmp_ext->jmp_2;
683               BB_ADD_PRED(p->jmp_ext, p);
684               ok = 0;
685               goto jmp_znz;
686             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L4
687                    ...                  ...
688                L2: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
689             */
690             } else if (p->jmp_ext->start->opcode == ZEND_JMPZNZ &&
691                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
692                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
693               if (p->jmp_2 != p->jmp_ext) {
694                 BB_DEL_PRED(p->jmp_ext, p);
695                 RM_BB(p->jmp_ext);
696               }
697               p->jmp_ext = p->jmp_ext->jmp_ext;
698               BB_ADD_PRED(p->jmp_ext, p);
699               ok = 0;
700               goto jmp_znz;
701             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L2+1
702                    ...                  ...
703                L2: JMPZ   $x,L3         JMPZ   $x,L3
704             */
705             } else if (p->jmp_ext->start->opcode == ZEND_JMPZ &&
706                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
707                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
708               if (p->jmp_2 != p->jmp_ext) {
709                 BB_DEL_PRED(p->jmp_ext, p);
710                 RM_BB(p->jmp_ext);
711               }
712               p->jmp_ext = p->jmp_ext->follow;
713               BB_ADD_PRED(p->jmp_ext, p);
714               ok = 0;
715               goto jmp_znz;
716             }
717             }
718             while (p->jmp_2->len == 1 && p->jmp_2->start->opcode == ZEND_JMP) {
719               BB* x_p = p->jmp_2;
720               if (p->jmp_2 != p->jmp_ext) {
721                 BB_DEL_PRED(p->jmp_2, p);
722                 RM_BB(x_p);
723               }
724               p->jmp_2 = x_p->jmp_1;
725               BB_ADD_PRED(p->jmp_2, p);
726               ok = 0;
727             }
728             while (p->jmp_ext->len == 1 && p->jmp_ext->start->opcode == ZEND_JMP) {
729               BB* x_p = p->jmp_ext;
730               if (p->jmp_2 != p->jmp_ext) {
731                 BB_DEL_PRED(p->jmp_ext, p);
732                 RM_BB(x_p);
733               }
734               p->jmp_ext = x_p->jmp_1;
735               BB_ADD_PRED(p->jmp_ext, p);
736               ok = 0;
737             }
738             break;
739           case ZEND_JMPZ:
740 jmp_z:
741             /* L1: JMPZ  ?,L1+1  =>  NOP
742             */
743             if (p->follow == p->jmp_2) {
744               p->jmp_2   = NULL;
745               SET_TO_NOP(op);
746               --(p->len);
747               ok = 0;
748               break;
749             } else if (op->op1.op_type == IS_CONST) {
750               /* JMPZ  0,L1  =>  JMP L1
751               */
752               if (!zend_is_true(&op->op1.u.constant)) {
753                 op->opcode = ZEND_JMP;
754                 op->op1.op_type = IS_UNUSED;
755                 op->op2.op_type = IS_UNUSED;
756                 if (p->follow != p->jmp_2) {
757                   BB_DEL_PRED(p->follow, p);
758                   RM_BB(p->follow);
759                 }
760                 p->jmp_1  = p->jmp_2;
761                 p->jmp_2  = NULL;
762                 p->follow = NULL;
763                 ok = 0;
764                 goto jmp;
765               /* JMPZ  1,L1  =>  NOP
766               */
767               } else {
768                 if (p->follow != p->jmp_2) {
769                   BB_DEL_PRED(p->jmp_2, p);
770                   RM_BB(p->jmp_2);
771                 }
772                 p->jmp_2   = NULL;
773                 SET_TO_NOP(op);
774                 --(p->len);
775                 ok = 0;
776                 break;
777               }
778             /* JMPZ ?,L1  =>  JMPZNZ  ?,L1,L2
779                JMP  L2        JMP     L2
780             */
781             } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
782               BB* x_p = p->follow;
783               op->opcode = ZEND_JMPZNZ;
784               if (p->jmp_2 != p->follow) {
785                 BB_DEL_PRED(p->follow, p);
786                 RM_BB(x_p);
787               }
788               p->follow = NULL;
789               p->jmp_ext = x_p->jmp_1;
790               BB_ADD_PRED(p->jmp_ext, p);
791               ok = 0;
792               goto jmp_znz;
793             } else if (p->jmp_2->len == 1 &&
794                        op->op1.op_type == IS_TMP_VAR) {
795             /*     JMPZ $x,L1  =>  JMPZ $x,L2
796                    ...             ...
797                L1: JMPZ $x,L2      JMPZ $x,L2
798                ----------------------------------------
799                    JMPZ   $x,L1     =>  JMPZ  $x,L2
800                    ...                   ...
801                L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
802             */
803             if       ((p->jmp_2->start->opcode == ZEND_JMPZ ||
804                        p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
805                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
806                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
807               if (p->jmp_2 != p->follow) {
808                 BB_DEL_PRED(p->jmp_2, p);
809                 RM_BB(p->jmp_2);
810               }
811               p->jmp_2 = p->jmp_2->jmp_2;
812               BB_ADD_PRED(p->jmp_2, p);
813               ok = 0;
814               goto jmp_z;
815             /*     JMPZ  $x,L1  =>  JMPZ  $x,L1+1
816                    ...              ...
817                L1: JMPNZ $x,L2      JMPNZ $x,L2
818             */
819             } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
820                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
821                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
822               if (p->jmp_2 != p->follow) {
823                 BB_DEL_PRED(p->jmp_2, p);
824                 RM_BB(p->jmp_2);
825               }
826               p->jmp_2 = p->jmp_2->follow;
827               BB_ADD_PRED(p->jmp_2, p);
828               ok = 0;
829               goto jmp_z;
830             }
831             }
832             goto jmp_2;
833           case ZEND_JMPNZ:
834 jmp_nz:
835             /* L1: JMPNZ  ?,L1+1  =>  NOP
836             */
837             if (p->follow == p->jmp_2) {
838               p->jmp_2   = NULL;
839               SET_TO_NOP(op);
840               --(p->len);
841               ok = 0;
842               break;
843             } else if (op->op1.op_type == IS_CONST) {
844               /* JMPNZ  1,L1  =>  JMP L1
845               */
846               if (zend_is_true(&op->op1.u.constant)) {
847                 op->opcode = ZEND_JMP;
848                 op->op1.op_type = IS_UNUSED;
849                 op->op2.op_type = IS_UNUSED;
850                 if (p->follow != p->jmp_2) {
851                   BB_DEL_PRED(p->follow, p);
852                   RM_BB(p->follow);
853                 }
854                 p->jmp_1  = p->jmp_2;
855                 p->jmp_2  = NULL;
856                 p->follow = NULL;
857                 ok = 0;
858                 goto jmp;
859               /* JMPNZ  0,L1  =>  NOP
860               */
861               } else {
862                 if (p->follow != p->jmp_2) {
863                   BB_DEL_PRED(p->jmp_2, p);
864                   RM_BB(p->jmp_2);
865                 }
866                 p->jmp_2   = NULL;
867                 SET_TO_NOP(op);
868                 --(p->len);
869                 ok = 0;
870                 break;
871               }
872             /* JMPNZ ?,L1  =>  JMPZNZ  ?,L2,L1
873                JMP   L2        JMP     L2
874             */
875             } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
876               BB* x_p = p->follow;
877               op->opcode = ZEND_JMPZNZ;
878               if (p->jmp_2 != p->follow) {
879                 BB_DEL_PRED(p->follow, p);
880                 RM_BB(p->follow);
881               }
882               p->follow = NULL;
883               p->jmp_ext = p->jmp_2;
884               p->jmp_2 = x_p->jmp_1;
885               BB_ADD_PRED(p->jmp_2, p);
886               ok = 0;
887               goto jmp_znz;
888             /*     JMPNZ $x,L1  =>  JMPNZ $x,L2
889                    ...              ...
890                L1: JMPNZ $x,L2      JMPNZ $x,L2
891             */
892             } else if (p->jmp_2->len == 1 &&
893                        op->op1.op_type == IS_TMP_VAR) {
894             if        (p->jmp_2->start->opcode == ZEND_JMPNZ &&
895                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
896                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
897               if (p->jmp_2 != p->follow) {
898                 BB_DEL_PRED(p->jmp_2, p);
899                 RM_BB(p->jmp_2);
900               }
901               p->jmp_2 = p->jmp_2->jmp_2;
902               BB_ADD_PRED(p->jmp_2, p);
903               ok = 0;
904               goto jmp_nz;
905             /*     JMPNZ  $x,L1  =>  JMPNZ  $x,L1+1
906                    ...               ...
907                L1: JMPZ   $x,L2      JMPZ $x,L2
908             */
909             } else if (p->jmp_2->start->opcode == ZEND_JMPZ &&
910                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
911                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
912               if (p->jmp_2 != p->follow) {
913                 BB_DEL_PRED(p->jmp_2, p);
914                 RM_BB(p->jmp_2);
915               }
916               p->jmp_2 = p->jmp_2->follow;
917               BB_ADD_PRED(p->jmp_2, p);
918               ok = 0;
919               goto jmp_nz;
920             /*     JMPNZ  $x,L1     =>  JMPNZ  $x,L3
921                    ...                   ...
922                L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
923             */
924             } else if (p->jmp_2->start->opcode == ZEND_JMPZNZ &&
925                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
926                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
927               if (p->jmp_2 != p->follow) {
928                 BB_DEL_PRED(p->jmp_2, p);
929                 RM_BB(p->jmp_2);
930               }
931               p->jmp_2 = p->jmp_2->jmp_ext;
932               BB_ADD_PRED(p->jmp_2, p);
933               ok = 0;
934               goto jmp_nz;
935             }
936             }
937             goto jmp_2;
938           case ZEND_JMPZ_EX:
939 jmp_z_ex:
940             /* L1: JMPZ_EX  $x,L1+1,$x  =>  NOP
941             */
942             if (p->follow == p->jmp_2 &&
943                 op->op1.op_type == IS_TMP_VAR &&
944                 op->result.op_type == IS_TMP_VAR &&
945                 op->op1.u.var == op->result.u.var) {
946               p->jmp_2   = NULL;
947               SET_TO_NOP(op);
948               --(p->len);
949               ok = 0;
950               break;
951             /* L1: JMPZ_EX  $x,L1+1,$y  =>  BOOL $x,$y
952             */
953             } else if (p->follow == p->jmp_2) {
954               p->jmp_2   = NULL;
955               op->opcode = ZEND_BOOL;
956               op->op2.op_type = IS_UNUSED;
957               ok = 0;
958               break;
959             } else if (p->jmp_2->len == 1 &&
960                        op->result.op_type == IS_TMP_VAR) {
961             /*     JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
962                    ...                  ...
963                L1: JMPZ    $x,L2        JMPZ    $x,L2
964                ------------------------------------------
965                    JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
966                    ...                  ...
967                L1: JMPZNZ  $x,L2,L3     JMPZNZ  $x,L2,L3
968                ------------------------------------------
969                    JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
970                    ...                  ...
971                L1: JMPZ_EX $x,L2,$x     JMPZ_EX $x,L2,$x
972             */
973             if       (((p->jmp_2->start->opcode == ZEND_JMPZ ||
974                          p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
975                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
976                         op->result.u.var == p->jmp_2->start->op1.u.var) ||
977                        (p->jmp_2->start->opcode == ZEND_JMPZ_EX &&
978                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
979