/* Build CFG */
checkpoint = zend_arena_checkpoint(ctx->arena);
- if (zend_build_cfg(&ctx->arena, op_array, ZEND_CFG_SPLIT_AT_LIVE_RANGES, &cfg, NULL) != SUCCESS) {
+ if (zend_build_cfg(&ctx->arena, op_array, ZEND_CFG_SPLIT_AT_LIVE_RANGES, &cfg) != SUCCESS) {
zend_arena_release(&ctx->arena, checkpoint);
return;
}
int removed_ops = 0;
/* DCE of CV operations that changes arguments may affect vararg functions. */
- zend_bool has_varargs = ssa->cfg.vararg;
+ zend_bool has_varargs = (ssa->cfg.flags & ZEND_FUNC_VARARG) != 0;
context ctx;
ctx.ssa = ssa;
# include "ssa_integrity.c"
#endif
-int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, uint32_t *flags)
+int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa)
{
uint32_t build_flags;
/* Build SSA */
memset(ssa, 0, sizeof(zend_ssa));
- if (zend_build_cfg(&ctx->arena, op_array,
- ZEND_CFG_NO_ENTRY_PREDECESSORS, &ssa->cfg, flags) != SUCCESS) {
+ if (zend_build_cfg(&ctx->arena, op_array, ZEND_CFG_NO_ENTRY_PREDECESSORS, &ssa->cfg) != SUCCESS) {
return FAILURE;
}
- if (*flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) {
+ if ((ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
/* TODO: we can't analyze functions with indirect variable access ??? */
return FAILURE;
}
}
/* Identify reducible and irreducible loops */
- if (zend_cfg_identify_loops(op_array, &ssa->cfg, flags) != SUCCESS) {
+ if (zend_cfg_identify_loops(op_array, &ssa->cfg) != SUCCESS) {
return FAILURE;
}
if (ctx->debug_level & ZEND_DUMP_DFA_PHI) {
build_flags |= ZEND_SSA_DEBUG_PHI_PLACEMENT;
}
- if (zend_build_ssa(&ctx->arena, ctx->script, op_array, build_flags, ssa, flags) != SUCCESS) {
+ if (zend_build_ssa(&ctx->arena, ctx->script, op_array, build_flags, ssa) != SUCCESS) {
return FAILURE;
}
void zend_optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
void *checkpoint = zend_arena_checkpoint(ctx->arena);
- uint32_t flags = 0;
zend_ssa ssa;
- if (zend_dfa_analyze_op_array(op_array, ctx, &ssa, &flags) != SUCCESS) {
+ if (zend_dfa_analyze_op_array(op_array, ctx, &ssa) != SUCCESS) {
zend_arena_release(&ctx->arena, checkpoint);
return;
}
} else {
succ->flags |= ZEND_BB_FOLLOW;
- if (cfg->split_at_calls) {
+ if ((cfg->flags & ZEND_CFG_STACKLESS)) {
if (opcode == ZEND_INCLUDE_OR_EVAL ||
opcode == ZEND_GENERATOR_CREATE ||
opcode == ZEND_YIELD ||
succ->flags |= ZEND_BB_ENTRY;
}
}
- if (cfg->split_at_recv) {
+ if ((cfg->flags & ZEND_CFG_RECV_ENTRY)) {
if (opcode == ZEND_RECV ||
opcode == ZEND_RECV_INIT) {
succ->flags |= ZEND_BB_RECV_ENTRY;
b = blocks + block_map[live_range->end];
b->flags |= ZEND_BB_KILL_VAR;
if (!(b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE))) {
- if (cfg->split_at_live_ranges) {
+ if ((cfg->flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES)) {
changed = 1;
zend_mark_reachable(op_array->opcodes, cfg, b);
} else {
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) /* {{{ */
+int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg) /* {{{ */
{
uint32_t flags = 0;
uint32_t i;
zval *zv;
zend_bool extra_entry_block = 0;
- cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0;
- cfg->split_at_calls = (build_flags & ZEND_CFG_STACKLESS) != 0;
- cfg->split_at_recv = (build_flags & ZEND_CFG_RECV_ENTRY) != 0;
+ cfg->flags = build_flags & (ZEND_CFG_SPLIT_AT_LIVE_RANGES|ZEND_CFG_STACKLESS|ZEND_CFG_RECV_ENTRY);
cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
BB_START(0);
for (i = 0; i < op_array->last; i++) {
zend_op *opline = op_array->opcodes + i;
- switch(opline->opcode) {
+ switch (opline->opcode) {
case ZEND_RECV:
case ZEND_RECV_INIT:
if (build_flags & ZEND_CFG_RECV_ENTRY) {
case ZEND_FUNC_GET_ARGS:
flags |= ZEND_FUNC_VARARG;
break;
+ case ZEND_EXT_NOP:
+ case ZEND_EXT_STMT:
+ case ZEND_EXT_FCALL_BEGIN:
+ case ZEND_EXT_FCALL_END:
+ flags |= ZEND_FUNC_HAS_EXTENDED_INFO;
+ break;
}
}
extra_entry_block = 1;
}
- if (cfg->split_at_live_ranges) {
+ if ((cfg->flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES)) {
for (j = 0; j < op_array->last_live_range; j++) {
BB_START(op_array->live_range[j].start);
BB_START(op_array->live_range[j].end);
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
zend_mark_reachable_blocks(op_array, cfg, 0);
- cfg->dynamic = (flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0;
- cfg->vararg = (flags & ZEND_FUNC_VARARG) != 0;
-
- if (func_flags) {
- *func_flags |= flags;
- }
+ cfg->flags |= flags;
return SUCCESS;
}
*b = tmp;
}
-int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32_t *flags) /* {{{ */
+int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */
{
int i, j, k, n;
int time;
free_alloca(sorted_blocks, sorted_blocks_use_heap);
free_alloca(entry_times, tree_use_heap);
ZEND_WORKLIST_FREE_ALLOCA(&work, list_use_heap);
- *flags |= flag;
+
+ cfg->flags |= flag;
return SUCCESS;
}
zend_basic_block *blocks; /* array of basic blocks */
int *predecessors;
uint32_t *map;
- unsigned int split_at_live_ranges : 1;
- unsigned int split_at_calls : 1;
- unsigned int split_at_recv : 1;
- unsigned int dynamic : 1; /* accesses varables by name */
- unsigned int vararg : 1; /* uses func_get_args() */
+ uint32_t flags;
} zend_cfg;
/* Build Flags */
BEGIN_EXTERN_C()
-int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg, uint32_t *func_flags);
+int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg);
void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg);
int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg);
int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg);
-int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32_t *flags);
+int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg);
END_EXTERN_C()
if (func_flags & ZEND_FUNC_NO_LOOPS) {
fprintf(stderr, ", no_loops");
}
+ if (func_flags & ZEND_FUNC_HAS_EXTENDED_INFO) {
+ fprintf(stderr, ", extended_info");
+ }
//TODO: this is useful only for JIT???
#if 0
if (info->flags & ZEND_JIT_FUNC_NO_IN_MEM_CVS) {
if (op_array->last_live_range) {
fprintf(stderr, "LIVE RANGES:\n");
for (i = 0; i < op_array->last_live_range; i++) {
- if (cfg->split_at_live_ranges) {
+ if ((cfg->flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES)) {
fprintf(stderr, " %u: BB%u - BB%u ",
EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
cfg->map[op_array->live_range[i].start],
#include "zend_ssa.h"
/* func flags */
-#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0)
+#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) /* accesses varables by name */
#define ZEND_FUNC_HAS_CALLS (1<<1)
-#define ZEND_FUNC_VARARG (1<<2)
+#define ZEND_FUNC_VARARG (1<<2) /* uses func_get_args() */
#define ZEND_FUNC_NO_LOOPS (1<<3)
#define ZEND_FUNC_IRREDUCIBLE (1<<4)
#define ZEND_FUNC_RECURSIVE (1<<7)
#define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8)
#define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9)
+#define ZEND_FUNC_HAS_EXTENDED_INFO (1<<10)
/* The following flags are valid only for return values of internal functions
* returned by zend_get_func_info()
for (i = 0; i < call_graph.op_arrays_count; i++) {
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (func_info) {
- zend_dfa_analyze_op_array(call_graph.op_arrays[i], &ctx, &func_info->ssa, &func_info->flags);
+ zend_dfa_analyze_op_array(call_graph.op_arrays[i], &ctx, &func_info->ssa);
+ func_info->flags = func_info->ssa.cfg.flags;
}
}
void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx);
-int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, uint32_t *flags);
+int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa);
void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map);
void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_nop_removal(zend_op_array *op_array);
}
/* }}} */
-int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags) /* {{{ */
+int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa) /* {{{ */
{
zend_basic_block *blocks = ssa->cfg.blocks;
zend_ssa_block *ssa_blocks;
/* Mark indirectly accessed variables */
for (i = 0; i < op_array->last_var; i++) {
- if (ssa->cfg.dynamic) {
+ if ((ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
ssa_vars[i].alias = SYMTABLE_ALIAS;
} else if (zend_string_equals_literal(op_array->vars[i], "php_errormsg")) {
ssa_vars[i].alias = PHP_ERRORMSG_ALIAS;
BEGIN_EXTERN_C()
-int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags);
+int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa);
int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa);
int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var);