summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/entry_block_with_predecessors.phpt33
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c3
-rw-r--r--ext/opcache/Optimizer/zend_cfg.c45
-rw-r--r--ext/opcache/Optimizer/zend_cfg.h1
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) ? \