Merge def and gen sets

For live-variable analysis it does not matter if def includes
variables that are previously use in the same block, the data flow
equations still have the same result. As such there is no need to
compute separate gen & def sets.

I'm keeping the name "def", because use of "gen" in this context is
pretty confusing (gen is usually the use set, not the def set).
This commit is contained in:
Nikita Popov 2016-04-21 23:12:28 +02:00
parent 261eb5cc89
commit a5944f8dd5
4 changed files with 28 additions and 46 deletions

View file

@ -25,21 +25,19 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
int set_size;
zend_basic_block *blocks = cfg->blocks;
int blocks_count = cfg->blocks_count;
zend_bitset tmp, gen, def, use, in, out;
zend_bitset tmp, def, use, in, out;
zend_op *opline;
uint32_t k, var_num;
int j;
/* FIXME: can we use "gen" instead of "def" for flow analyzing? */
set_size = dfg->size;
tmp = dfg->tmp;
gen = dfg->gen;
def = dfg->def;
use = dfg->use;
in = dfg->in;
out = dfg->out;
/* Collect "gen", "def" and "use" sets */
/* Collect "def" and "use" sets */
for (j = 0; j < blocks_count; j++) {
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
@ -84,6 +82,9 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
goto op1_def;
}
goto op1_use;
case ZEND_UNSET_VAR:
ZEND_ASSERT(opline->extended_value & ZEND_QUICK_SET);
/* break missing intentionally */
case ZEND_ASSIGN:
case ZEND_ASSIGN_REF:
case ZEND_BIND_GLOBAL:
@ -92,17 +93,6 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
case ZEND_SEND_REF:
case ZEND_SEND_VAR_NO_REF:
case ZEND_FE_RESET_RW:
op1_def:
if (!DFG_ISSET(use, set_size, j, var_num)) {
// FIXME: include into "use" to ...?
DFG_SET(use, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
}
DFG_SET(gen, set_size, j, var_num);
break;
case ZEND_UNSET_VAR:
ZEND_ASSERT(opline->extended_value & ZEND_QUICK_SET);
/* break missing intentionally */
case ZEND_ASSIGN_ADD:
case ZEND_ASSIGN_SUB:
case ZEND_ASSIGN_MUL:
@ -132,7 +122,11 @@ op1_def:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_VERIFY_RETURN_TYPE:
DFG_SET(gen, set_size, j, var_num);
op1_def:
// FIXME: include into "use" too ...?
DFG_SET(use, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
break;
default:
op1_use:
if (!DFG_ISSET(def, set_size, j, var_num)) {
@ -142,9 +136,9 @@ op1_use:
} else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(opline->op1.var);
if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
DFG_SET(gen, set_size, j, var_num);
}
if (!DFG_ISSET(def, set_size, j, var_num)) {
DFG_SET(use, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
} else if (!DFG_ISSET(def, set_size, j, var_num)) {
DFG_SET(use, set_size, j, var_num);
}
}
@ -165,12 +159,9 @@ op1_use:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
op2_def:
if (!DFG_ISSET(use, set_size, j, var_num)) {
// FIXME: include into "use" to ...?
DFG_SET(use, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
}
DFG_SET(gen, set_size, j, var_num);
// FIXME: include into "use" too ...?
DFG_SET(use, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
break;
default:
op2_use:
@ -182,10 +173,7 @@ op2_use:
} else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(opline->op2.var);
if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
if (!DFG_ISSET(use, set_size, j, var_num)) {
DFG_SET(def, set_size, j, var_num);
}
DFG_SET(gen, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
} else {
if (!DFG_ISSET(def, set_size, j, var_num)) {
DFG_SET(use, set_size, j, var_num);
@ -194,10 +182,7 @@ op2_use:
}
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(opline->result.var);
if (!DFG_ISSET(use, set_size, j, var_num)) {
DFG_SET(def, set_size, j, var_num);
}
DFG_SET(gen, set_size, j, var_num);
DFG_SET(def, set_size, j, var_num);
}
}
}

View file

@ -26,7 +26,6 @@ typedef struct _zend_dfg {
int vars;
uint32_t size;
zend_bitset tmp;
zend_bitset gen;
zend_bitset def;
zend_bitset use;
zend_bitset in;

View file

@ -1143,7 +1143,6 @@ void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zen
for (j = 0; j < cfg->blocks_count; j++) {
fprintf(stderr, " BB%d:\n", j);
zend_dump_var_set(op_array, "gen", DFG_BITSET(dfg->gen, dfg->size, j));
zend_dump_var_set(op_array, "def", DFG_BITSET(dfg->def, dfg->size, j));
zend_dump_var_set(op_array, "use", DFG_BITSET(dfg->use, dfg->size, j));
zend_dump_var_set(op_array, "in ", DFG_BITSET(dfg->in, dfg->size, j));

View file

@ -765,7 +765,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
zend_ssa_block *ssa_blocks;
int blocks_count = ssa->cfg.blocks_count;
uint32_t set_size;
zend_bitset tmp, gen, in;
zend_bitset tmp, def, in;
int *var = NULL;
int i, j, k, changed;
zend_dfg dfg;
@ -784,8 +784,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
dfg.size = set_size = zend_bitset_len(dfg.vars);
dfg.tmp = do_alloca((set_size * sizeof(zend_ulong)) * (blocks_count * 5 + 1), dfg_use_heap);
memset(dfg.tmp, 0, (set_size * sizeof(zend_ulong)) * (blocks_count * 5 + 1));
dfg.gen = dfg.tmp + set_size;
dfg.def = dfg.gen + set_size * blocks_count;
dfg.def = dfg.tmp + set_size;
dfg.use = dfg.def + set_size * blocks_count;
dfg.in = dfg.use + set_size * blocks_count;
dfg.out = dfg.in + set_size * blocks_count;
@ -800,10 +799,10 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
}
tmp = dfg.tmp;
gen = dfg.gen;
def = dfg.def;
in = dfg.in;
/* SSA construction, Step 1: Propagate "gen" sets in merge points */
/* SSA construction, Step 1: Propagate "def" sets in merge points */
do {
changed = 0;
for (j = 0; j < blocks_count; j++) {
@ -811,16 +810,16 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
continue;
}
if (j >= 0 && (blocks[j].predecessors_count > 1 || j == 0)) {
zend_bitset_copy(tmp, gen + (j * set_size), set_size);
zend_bitset_copy(tmp, def + (j * set_size), set_size);
for (k = 0; k < blocks[j].predecessors_count; k++) {
i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k];
while (i != -1 && i != blocks[j].idom) {
zend_bitset_union_with_intersection(tmp, tmp, gen + (i * set_size), in + (j * set_size), set_size);
zend_bitset_union_with_intersection(tmp, tmp, def + (i * set_size), in + (j * set_size), set_size);
i = blocks[i].idom;
}
}
if (!zend_bitset_equal(gen + (j * set_size), tmp, set_size)) {
zend_bitset_copy(gen + (j * set_size), tmp, set_size);
if (!zend_bitset_equal(def + (j * set_size), tmp, set_size)) {
zend_bitset_copy(def + (j * set_size), tmp, set_size);
changed = 1;
}
}
@ -850,7 +849,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
for (k = 0; k < blocks[j].predecessors_count; k++) {
i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k];
while (i != -1 && i != blocks[j].idom) {
zend_bitset_union_with_intersection(tmp, tmp, gen + (i * set_size), in + (j * set_size), set_size);
zend_bitset_union_with_intersection(tmp, tmp, def + (i * set_size), in + (j * set_size), set_size);
i = blocks[i].idom;
}
}
@ -907,7 +906,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
if (p) {
if (p->pi >= 0) {
if (zend_bitset_in(in + (j * set_size), p->var) &&
!zend_bitset_in(gen + (i * set_size), p->var)) {
!zend_bitset_in(def + (i * set_size), p->var)) {
zend_bitset_incl(tmp, p->var);
}
} else {