root/eaccelerator/trunk/optimize.c

Revision 352, 116.4 kB (checked in by bart, 1 month ago)

optimize.c: In php 5.3 this field is const
ea_restore.c: strings comparison can't be done like that, stupid me

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