source: trunk/optimizer.c @ 312

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

optimizer: finished building of basic blocks

File size: 7.9 KB
Line 
1#if 0
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     fall;
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(int *jmpout_op1, int *jmpout_op2, int *jmpout_ext, zend_bool *fall, zend_op *opline) /* {{{ */
105{
106    /* break=will fall */
107    switch (opline->opcode) {
108    case ZEND_RETURN:
109    case ZEND_EXIT:
110        return SUCCESS; /* no fall */
111
112    case ZEND_JMP:
113        *jmpout_op1 = opline->op1.u.opline_num;
114        return SUCCESS; /* no fall */
115
116    case ZEND_JMPZNZ:
117        *jmpout_ext = opline->extended_value;
118        *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        *jmpout_op2 = opline->op2.u.opline_num;
134        break;
135
136    default:
137        return FAILURE;
138    }
139
140    *fall = 1;
141    return SUCCESS;
142}
143/* }}} */
144
145/*
146 * basic block functions
147 */
148
149static bb_t *bb_new_ex(zend_op *opcodes, int count) /* {{{ */
150{
151    bb_t *bb = (bb_t *) ecalloc(sizeof(bb_t), 1);
152
153    bb->jmpout_op1 = BBID_INVALID;
154    bb->jmpout_op2 = BBID_INVALID;
155    bb->jmpout_ext = BBID_INVALID;
156    bb->fall       = BBID_INVALID;
157
158    if (opcodes) {
159        bb->alloc   = 0;
160        bb->size    = bb->count = count;
161        bb->opcodes = opcodes;
162    }
163    else {
164        bb->alloc   = 1;
165        bb->size    = bb->count = 8;
166        bb->opcodes = ecalloc(sizeof(zend_op), bb->size);
167    }
168
169    return bb;
170}
171/* }}} */
172#define bb_new() bb_new_ex(NULL, 0)
173static void bb_destroy(bb_t *bb) /* {{{ */
174{
175    if (bb->alloc) {
176        efree(bb->opcodes);
177    }
178    efree(bb);
179}
180/* }}} */
181#ifdef DEBUG
182static void bb_print(bb_t *bb, zend_op *opcodes) /* {{{ */
183{
184    fprintf(stderr,
185            "%3d %3d %3d"
186            " %c%c"
187            " %3d %3d %3d %3d\r\n"
188            , bb->id, bb->count, bb->opcodes - opcodes
189            , bb->used ? 'U' : ' ', bb->alloc ? 'A' : ' '
190            , bb->jmpout_op1, bb->jmpout_op2, bb->jmpout_ext, bb->fall
191            );
192}
193/* }}} */
194#endif
195
196#define bbs_get(bbs, n) xc_stack_get(bbs, n)
197static void bbs_destroy(bbs_t *bbs) /* {{{ */
198{
199    bb_t *bb;
200    while (xc_stack_count(bbs)) {
201        bb = (bb_t *) xc_stack_pop(bbs);
202        bb_destroy(bb);
203    }
204}
205/* }}} */
206#ifdef DEBUG
207static void bbs_print(bbs_t *bbs, zend_op *opcodes) /* {{{ */
208{
209    int i;
210    for (i = 0; i < xc_stack_count(bbs); i ++) {
211        bb_print(bbs_get(bbs, i), opcodes);
212    }
213}
214/* }}} */
215#endif
216#define bbs_init(bbs) xc_stack_init_ex(bbs, 16)
217static bb_t *bbs_add_bb(bbs_t *bbs, bb_t *bb) /* {{{ */
218{
219    bb->id = (bbid_t) xc_stack_count(bbs);
220    xc_stack_push(bbs, (void *) bb);
221    return bb;
222}
223/* }}} */
224static bb_t *bbs_new_bb_ex(bbs_t *bbs, zend_op *opcodes, int count) /* {{{ */
225{
226    return bbs_add_bb(bbs, bb_new_ex(opcodes, count));
227}
228/* }}} */
229static int bbs_build_from(bbs_t *bbs, zend_op *opcodes, int count) /* {{{ */
230{
231    int i, prev;
232    bb_t *pbb;
233    bbid_t id;
234    int jmpout_op1, jmpout_op2, jmpout_ext;
235    zend_bool fall;
236    bbid_t *bbids          = do_alloca(count * sizeof(bbid_t));
237    zend_bool *markjmpins  = do_alloca(count * sizeof(zend_bool));
238    zend_bool *markjmpouts = do_alloca(count * sizeof(zend_bool));
239
240    /* {{{ mark jmpin/jumpout */
241    memset(markjmpins,  0, count * sizeof(zend_bool));
242    memset(markjmpouts, 0, count * sizeof(zend_bool));
243
244    for (i = 0; i < count; i ++) {
245        jmpout_op1 = jmpout_op2 = jmpout_ext = -1;
246        fall = 0;
247        if (op_get_jmpout(&jmpout_op1, &jmpout_op2, &jmpout_ext, &fall, &opcodes[i]) == SUCCESS) {
248            markjmpouts[i] = 1;
249
250            if (jmpout_op1 != -1) {
251                markjmpins[jmpout_op1] = 1;
252            }
253            if (jmpout_op2 != -1) {
254                markjmpins[jmpout_op2] = 1;
255            }
256            if (jmpout_ext != -1) {
257                markjmpins[jmpout_ext] = 1;
258            }
259        }
260    }
261    /* }}} */
262    /* {{{ fill opcodes with newly allocated id */
263    for (i = 0; i < count; i ++) {
264        bbids[i] = BBID_INVALID;
265    }
266
267    prev = 0;
268    id = 0;
269    for (i = 1; i < count; i ++) {
270        if (markjmpins[i] || markjmpouts[i - 1]) {
271            for (; prev < i; prev ++) {
272                bbids[prev] = id;
273            }
274            id ++;
275            prev = i;
276        }
277    }
278
279    if (prev < count) {
280        for (; prev < i; prev ++) {
281            bbids[prev] = id;
282        }
283    }
284    /* }}} */
285    /* {{{ create basic blocks */
286    prev = 0;
287    id = 0;
288    for (i = 1; i < count; i ++) {
289        if (id == bbids[i]) {
290            continue;
291        }
292        id = bbids[i];
293
294        pbb = bbs_new_bb_ex(bbs, opcodes + prev, i - prev);
295        jmpout_op1 = jmpout_op2 = jmpout_ext = -1;
296        fall = 0;
297        if (op_get_jmpout(&jmpout_op1, &jmpout_op2, &jmpout_ext, &fall, &opcodes[prev]) == SUCCESS) {
298            if (jmpout_op1 != -1) {
299                pbb->jmpout_op1 = bbids[jmpout_op1];
300                assert(pbb->jmpout_op1 != BBID_INVALID);
301            }
302            if (jmpout_op2 != -1) {
303                pbb->jmpout_op2 = bbids[jmpout_op2];
304                assert(pbb->jmpout_op2 != BBID_INVALID);
305            }
306            if (jmpout_ext != -1) {
307                pbb->jmpout_ext = bbids[jmpout_ext];
308                assert(pbb->jmpout_ext != BBID_INVALID);
309            }
310            if (fall && i + 1 < count) {
311                pbb->fall = bbids[i + 1];
312                assert(pbb->fall != BBID_INVALID);
313            }
314        }
315        prev = i + 1;
316    }
317    assert(prev == count);
318    /* }}} */
319
320    free_alloca(bbids);
321    free_alloca(markjmpins);
322    free_alloca(markjmpouts);
323    return SUCCESS;
324}
325/* }}} */
326
327/*
328 * optimize
329 */
330static int xc_optimize_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
331{
332    bbs_t bbs;
333
334    if (op_array->type != ZEND_USER_FUNCTION) {
335        return 0;
336    }
337    xc_undo_pass_two(op_array TSRMLS_CC);
338#ifdef DEBUG
339#   if 0
340    TRACE("optimize file: %s", op_array->filename);
341    xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
342#   endif
343#endif
344
345    if (op_array_convert_switch(op_array) == SUCCESS) {
346        bbs_init(&bbs);
347        if (bbs_build_from(&bbs, op_array->opcodes, op_array->last) == SUCCESS) {
348#ifdef DEBUG
349            bbs_print(&bbs, op_array->opcodes);
350#endif
351        }
352        bbs_destroy(&bbs);
353    }
354
355#ifdef DEBUG
356#   if 0
357    TRACE("%s", "after compiles");
358    xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
359#   endif
360#endif
361    xc_redo_pass_two(op_array TSRMLS_CC);
362    return 0;
363}
364/* }}} */
365void xc_optimize(zend_op_array *op_array TSRMLS_DC) /* {{{ */
366{
367    xc_compile_result_t cr;
368
369    xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
370
371    xc_apply_op_array(&cr, (apply_func_t) xc_undo_pass_two TSRMLS_CC);
372    xc_apply_op_array(&cr, (apply_func_t) xc_optimize_op_array TSRMLS_CC);
373    xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);
374
375    xc_compile_result_free(&cr);
376}
377/* }}} */
Note: See TracBrowser for help on using the repository browser.