root/eaccelerator/tags/0.9.5-beta2/optimize.c

Revision 199, 117.9 kB (checked in by bart, 3 years ago)

* Fixed typo in optimizer which broke compilation for PHP != 5.1

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