diff options
-rw-r--r-- | Zend/tests/entry_block_with_predecessors.phpt | 33 | ||||
-rw-r--r-- | ext/opcache/Optimizer/dfa_pass.c | 3 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_cfg.c | 45 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_cfg.h | 1 |
4 files changed, 69 insertions, 13 deletions
diff --git a/Zend/tests/entry_block_with_predecessors.phpt b/Zend/tests/entry_block_with_predecessors.phpt new file mode 100644 index 0000000000..ffc3147f1c --- /dev/null +++ b/Zend/tests/entry_block_with_predecessors.phpt @@ -0,0 +1,33 @@ +--TEST-- +For SSA form the entry block should have no predecessors +--FILE-- +<?php + +function test() { + while (true) { + var_dump($a + 1); + $a = 1; + if (@$i++) { + break; + } + } +} + +function test2() { + while (true) { + $a = 42; + if (@$i++ > 1) { + break; + } + $a = new stdClass; + } +} + +test(); +test2(); + +?> +--EXPECTF-- +Notice: Undefined variable: a in %s on line %d +int(1) +int(2) diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index f7cae772fb..3be638eb92 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -43,7 +43,8 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, /* Build SSA */ memset(ssa, 0, sizeof(zend_ssa)); - if (zend_build_cfg(&ctx->arena, op_array, 0, &ssa->cfg, flags) != SUCCESS) { + if (zend_build_cfg(&ctx->arena, op_array, + ZEND_CFG_NO_ENTRY_PREDECESSORS, &ssa->cfg, flags) != SUCCESS) { return FAILURE; } diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 2bf43fe9c5..9701f58606 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -240,9 +240,22 @@ static void record_successor(zend_basic_block *blocks, int pred, int n, int succ blocks[pred].successors[n] = succ; } +static void initialize_block(zend_basic_block *block) { + block->flags = 0; + block->successors[0] = -1; + block->successors[1] = -1; + block->predecessors_count = 0; + block->predecessor_offset = -1; + block->idom = -1; + block->loop_header = -1; + block->level = -1; + block->children = -1; + block->next_child = -1; +} + #define BB_START(i) do { \ if (!block_map[i]) { blocks_count++;} \ - block_map[i] = 1; \ + block_map[i]++; \ } while (0) int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg, uint32_t *func_flags) /* {{{ */ @@ -255,6 +268,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b int blocks_count = 0; zend_basic_block *blocks; zval *zv; + zend_bool extra_entry_block = 0; cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0; cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t)); @@ -407,6 +421,12 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } } + /* If the entry block has predecessors, we may need to split it */ + if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS) + && op_array->last > 0 && block_map[0] > 1) { + extra_entry_block = 1; + } + if (cfg->split_at_live_ranges) { for (j = 0; j < op_array->last_live_range; j++) { BB_START(op_array->live_range[j].start); @@ -429,6 +449,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } } + blocks_count += extra_entry_block; cfg->blocks_count = blocks_count; /* Build CFG, Step 2: Build Array of Basic Blocks */ @@ -437,23 +458,23 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b return FAILURE; } - for (i = 0, blocks_count = -1; i < op_array->last; i++) { + blocks_count = -1; + + if (extra_entry_block) { + initialize_block(&blocks[0]); + blocks[0].start = 0; + blocks[0].len = 0; + blocks_count++; + } + + for (i = 0; i < op_array->last; i++) { if (block_map[i]) { if (blocks_count >= 0) { blocks[blocks_count].len = i - blocks[blocks_count].start; } blocks_count++; - blocks[blocks_count].flags = 0; + initialize_block(&blocks[blocks_count]); blocks[blocks_count].start = i; - blocks[blocks_count].successors[0] = -1; - blocks[blocks_count].successors[1] = -1; - blocks[blocks_count].predecessors_count = 0; - blocks[blocks_count].predecessor_offset = -1; - blocks[blocks_count].idom = -1; - blocks[blocks_count].loop_header = -1; - blocks[blocks_count].level = -1; - blocks[blocks_count].children = -1; - blocks[blocks_count].next_child = -1; } block_map[i] = blocks_count; } diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h index 244a2ade97..da908fdbe3 100644 --- a/ext/opcache/Optimizer/zend_cfg.h +++ b/ext/opcache/Optimizer/zend_cfg.h @@ -96,6 +96,7 @@ typedef struct _zend_cfg { #define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28) #define ZEND_SSA_RC_INFERENCE (1<<27) #define ZEND_CFG_SPLIT_AT_LIVE_RANGES (1<<26) +#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25) #define CRT_CONSTANT_EX(op_array, node, rt_constants) \ ((rt_constants) ? \ |