From: Nikita Popov Date: Sat, 27 Feb 2016 14:02:48 +0000 (+0100) Subject: Fix dominator tree construction X-Git-Tag: php-7.1.0alpha1~565 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8d758e7be9fe4a54425f0f7bd71744e22eb7b77f;p=php Fix dominator tree construction The used dominator intersection algorithm assumes a postorder numbering of the CFG. The reversal of our natural numbering is quite similar to postorder, but not the same. In the future we should precompute both preorder/postorder numberings and orderings, as these are useful in many places. --- diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 3e50bb910c..63f14634cb 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -585,16 +585,45 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */ } /* }}} */ +/* Computes a postorder numbering of the CFG */ +static void compute_postnum_recursive( + int *postnum, int *cur, const zend_cfg *cfg, int block_num) /* {{{ */ +{ + zend_basic_block *block = &cfg->blocks[block_num]; + if (postnum[block_num] != -1) { + return; + } + + postnum[block_num] = -2; /* Marker for "currently visiting" */ + if (block->successors[0] >= 0) { + compute_postnum_recursive(postnum, cur, cfg, block->successors[0]); + if (block->successors[1] >= 0) { + compute_postnum_recursive(postnum, cur, cfg, block->successors[1]); + } + } + postnum[block_num] = (*cur)++; +} +/* }}} */ + +/* Computes dominator tree using algorithm from "A Simple, Fast Dominance Algorithm" by + * Cooper, Harvey and Kennedy. */ int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */ { zend_basic_block *blocks = cfg->blocks; int blocks_count = cfg->blocks_count; int j, k, changed; + ALLOCA_FLAG(use_heap) + int *postnum = do_alloca(sizeof(int) * cfg->blocks_count, use_heap); + memset(postnum, -1, sizeof(int) * cfg->blocks_count); + j = 0; + compute_postnum_recursive(postnum, &j, cfg, 0); + /* FIXME: move declarations */ blocks[0].idom = 0; do { changed = 0; + /* Iterating in RPO here would converge faster */ for (j = 1; j < blocks_count; j++) { int idom = -1; @@ -612,8 +641,8 @@ int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cf if (blocks[pred].idom >= 0) { while (idom != pred) { - while (pred > idom) pred = blocks[pred].idom; - while (idom > pred) idom = blocks[idom].idom; + while (postnum[pred] < postnum[idom]) pred = blocks[pred].idom; + while (postnum[idom] < postnum[pred]) idom = blocks[idom].idom; } } } @@ -664,6 +693,7 @@ int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cf blocks[j].level = level; } + free_alloca(postnum, use_heap); return SUCCESS; } /* }}} */