source: trunk/optimizer.c @ 308

Last change on this file since 308 was 308, checked in by moo, 8 years ago

basic works on optimizer

File size: 6.3 KB
Line 
1#if 1
2#define DEBUG
3#endif
4
5#include "utils.h"
6#include "optimizer.h"
7/* the "vector" stack */
8#include "stack.h"
9
10#ifdef DEBUG
11#   include "processor.h"
12#endif
13
14typedef int bbid_t;
15enum {
16    BBID_INVALID = -1,
17};
18/* {{{ basic block */
19typedef struct _bb_t {
20    bbid_t     id;
21    zend_bool  used;
22
23    zend_bool  alloc;
24    zend_op   *opcodes;
25    int        count;
26    int        size;
27
28    bbid_t     jmpout_op1;
29    bbid_t     jmpout_op2;
30    bbid_t     jmpout_ext;
31    bbid_t     follow;
32} bb_t;
33/* }}} */
34
35/* basic blocks */
36typedef xc_stack_t bbs_t;
37
38/* oparray help functions */
39static int op_array_convert_switch(zend_op_array *op_array) /* {{{ */
40{
41    int i;
42
43    if (op_array->brk_cont_array == NULL) {
44        return SUCCESS;
45    }
46
47    for (i = 0; i < op_array->last; i ++) {
48        zend_op *opline = &op_array->opcodes[i];
49        zend_brk_cont_element *jmp_to;
50        int array_offset, nest_levels, original_nest_levels;
51
52        if (opline->opcode != ZEND_BRK && opline->opcode != ZEND_CONT) {
53            continue;
54        }
55        if (opline->op2.op_type != IS_CONST
56         || opline->op2.u.constant.type != IS_LONG) {
57            return FAILURE;
58        }
59
60        nest_levels = opline->op2.u.constant.value.lval;
61        original_nest_levels = nest_levels;
62
63        array_offset = opline->op1.u.opline_num;
64        do {
65            if (array_offset == -1) {
66                /* this is a runtime error in ZE
67                zend_error(E_ERROR, "Cannot break/continue %d level%s", original_nest_levels, (original_nest_levels == 1) ? "" : "s");
68                */
69                return FAILURE;
70            }
71            jmp_to = &op_array->brk_cont_array[array_offset];
72            if (nest_levels > 1) {
73                zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
74
75                switch (brk_opline->opcode) {
76                case ZEND_SWITCH_FREE:
77                    break;
78                case ZEND_FREE:
79                    break;
80                }
81            }
82            array_offset = jmp_to->parent;
83        } while (--nest_levels > 0);
84
85        /* rewrite to jmp */
86        if (opline->opcode == ZEND_BRK) {
87            opline->op1.u.opline_num = jmp_to->brk;
88        }
89        else {
90            opline->op1.u.opline_num = jmp_to->cont;
91        }
92        opline->op2.op_type = IS_UNUSED;
93        opline->opcode = ZEND_JMP;
94    }
95
96    if (op_array->brk_cont_array != NULL) {
97        efree(op_array->brk_cont_array);
98        op_array->brk_cont_array = NULL;
99    }
100    op_array->last_brk_cont = 0;
101    return SUCCESS;
102}
103/* }}} */
104static int op_get_jmpout(bb_t *bb, zend_op *opcodes, zend_op *opline) /* {{{ */
105{
106    /* break=have follow */
107    switch (opline->opcode) {
108    case ZEND_RETURN:
109    case ZEND_EXIT:
110        break;
111
112    case ZEND_JMP:
113        bb->jmpout_op1 = opline->op1.u.opline_num;
114        return SUCCESS; /* no follow */
115
116    case ZEND_JMPZNZ:
117        bb->jmpout_ext = opline->extended_value;
118        bb->jmpout_op2 = opline->op2.u.opline_num;
119        break;
120
121    case ZEND_JMPZ:
122    case ZEND_JMPNZ:
123    case ZEND_JMPZ_EX:
124    case ZEND_JMPNZ_EX:
125#ifndef ZEND_ENGINE_2_1
126        /* Pre-PHP 5.1 only */
127    case ZEND_JMP_NO_CTOR:
128#else       
129    case ZEND_NEW:
130    case ZEND_FE_RESET:
131#endif     
132    case ZEND_FE_FETCH:
133        bb->jmpout_op2 = opline->op2.u.opline_num;
134        break;
135
136    default:
137        return FAILURE;
138    }
139
140    return SUCCESS;
141}
142/* }}} */
143
144/*
145 * basic block functions
146 */
147
148static bb_t *bb_new_ex(zend_op *opcodes, int count) /* {{{ */
149{
150    bb_t *bb = (bb_t *) ecalloc(sizeof(bb_t), 1);
151
152    bb->jmpout_op1 = BBID_INVALID;
153    bb->jmpout_op2 = BBID_INVALID;
154    bb->jmpout_ext = BBID_INVALID;
155    bb->follow     = BBID_INVALID;
156
157    if (opcodes) {
158        bb->alloc   = 0;
159        bb->size    = bb->count = count;
160        bb->opcodes = opcodes;
161    }
162    else {
163        bb->alloc   = 1;
164        bb->size    = bb->count = 8;
165        bb->opcodes = ecalloc(sizeof(zend_op), bb->size);
166    }
167
168    return bb;
169}
170/* }}} */
171#define bb_new() bb_new_ex(NULL, 0)
172static void bb_destroy(bb_t *bb) /* {{{ */
173{
174    if (bb->alloc) {
175        efree(bb->opcodes);
176    }
177    efree(bb);
178}
179/* }}} */
180#define bbs_get(bbs, n) xc_stack_get(bbs, n)
181static void bbs_destroy(bbs_t *bbs) /* {{{ */
182{
183    bb_t *bb;
184    while (xc_stack_count(bbs)) {
185        bb = (bb_t *) xc_stack_pop(bbs);
186        bb_destroy(bb);
187    }
188}
189/* }}} */
190#define bbs_init(bbs) xc_stack_init_ex(bbs, 16)
191static bb_t *bbs_add_bb(bbs_t *bbs, bb_t *bb) /* {{{ */
192{
193    bb->id = (bbid_t) xc_stack_count(bbs);
194    xc_stack_push(bbs, (void *) bb);
195    return bb;
196}
197/* }}} */
198static bb_t *bbs_new_bb_ex(bbs_t *bbs, zend_op *opcodes, int count) /* {{{ */
199{
200    return bbs_add_bb(bbs, bb_new_ex(opcodes, count));
201}
202/* }}} */
203static int bbs_build_from(bbs_t *bbs, zend_op *opcodes, int count) /* {{{ */
204{
205    int i, prev;
206    bb_t bb, *pbb;
207    zend_bool *markjmpins  = do_alloca(count);
208    zend_bool *markjmpouts = do_alloca(count);
209
210    memset(markjmpins,  0, sizeof(zend_bool));
211    memset(markjmpouts, 0, sizeof(zend_bool));
212
213    for (i = 0; i < count; i ++) {
214        /* BBID_INVALID=invalidate line
215         * bb.jmpout_op1 bb.jmpout_op2 bb.jmpout_ext bb.follow means opline number here, not basicblock id
216         */
217        bb.jmpout_op1 = bb.jmpout_op2 = BBID_INVALID;
218        bb.jmpout_ext = bb.follow     = BBID_INVALID;
219        if (op_get_jmpout(&bb, opcodes, &opcodes[i]) == SUCCESS) {
220            markjmpouts[i] = 1;
221
222            if (bb.jmpout_op1 != BBID_INVALID) {
223                markjmpins[bb.jmpout_op1] = 1;
224            }
225            if (bb.jmpout_op2 != BBID_INVALID) {
226                markjmpins[bb.jmpout_op2] = 1;
227            }
228            if (bb.jmpout_ext != BBID_INVALID) {
229                markjmpins[bb.jmpout_ext] = 1;
230            }
231
232            if (i < count && bb.follow != BBID_INVALID) {
233                markjmpins[i + 1] = 1;
234            }
235        }
236    }
237
238    prev = 0;
239    for (i = 1; i < count; i ++) {
240        if (markjmpins[i]) {
241            pbb = bbs_new_bb_ex(bbs, opcodes + prev, i - prev);
242            op_get_jmpout(pbb, opcodes, &opcodes[prev]);
243            prev = i;
244        }
245    }
246
247    if (prev != count - 1) {
248        pbb = bbs_new_bb_ex(bbs, opcodes + prev, count - prev);
249    }
250
251    return SUCCESS;
252}
253/* }}} */
254
255/*
256 * optimize
257 */
258static int xc_optimize_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
259{
260    bbs_t bbs;
261
262    if (op_array->type != ZEND_USER_FUNCTION) {
263        return 0;
264    }
265    xc_undo_pass_two(op_array TSRMLS_CC);
266#ifdef DEBUG
267    TRACE("optimize file: %s", op_array->filename);
268    xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
269#endif
270
271    if (op_array_convert_switch(op_array)) {
272        bbs_init(&bbs);
273        if (bbs_build_from(&bbs, op_array->opcodes, op_array->last)) {
274        }
275        bbs_destroy(&bbs);
276    }
277
278#ifdef DEBUG
279    TRACE("%s", "after compiles");
280    xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
281#endif
282    xc_redo_pass_two(op_array TSRMLS_CC);
283    return 0;
284}
285/* }}} */
286void xc_optimize(zend_op_array *op_array TSRMLS_DC) /* {{{ */
287{
288    xc_compile_result_t cr;
289
290    xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
291
292    xc_apply_op_array(&cr, (apply_func_t) xc_undo_pass_two TSRMLS_CC);
293    xc_apply_op_array(&cr, (apply_func_t) xc_optimize_op_array TSRMLS_CC);
294    xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);
295
296    xc_compile_result_free(&cr);
297}
298/* }}} */
Note: See TracBrowser for help on using the repository browser.