From: Nikita Popov Date: Tue, 7 Jun 2016 19:16:29 +0000 (+0200) Subject: Use union for pi constraints X-Git-Tag: php-7.1.0alpha3~42^2~15^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9877d8f019cc0c1070fc963419029f4faf00b34a;p=php Use union for pi constraints This will make it easier to extend pi constraints without impacting structure sizes. --- diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 7c225bbbe8..17f5437c95 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -332,14 +332,14 @@ static void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa } } -static void zend_dump_pi_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_pi_constraint *r, uint32_t dump_flags) +static void zend_dump_type_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_type_constraint *constraint, uint32_t dump_flags) { - if (r->type_mask != (uint32_t) -1) { - fprintf(stderr, " TYPE"); - zend_dump_type_info(r->type_mask, NULL, 0, dump_flags); - return; - } + fprintf(stderr, " TYPE"); + zend_dump_type_info(constraint->type_mask, NULL, 0, dump_flags); +} +static void zend_dump_range_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_range_constraint *r, uint32_t dump_flags) +{ if (r->range.underflow && r->range.overflow) { return; } @@ -773,7 +773,11 @@ static void zend_dump_block_header(const zend_cfg *cfg, const zend_op_array *op_ fprintf(stderr, " = Pi(", p->pi); zend_dump_ssa_var(op_array, ssa, p->sources[0], 0, p->var, dump_flags); fprintf(stderr, " &"); - zend_dump_pi_constraint(op_array, ssa, &p->constraint, dump_flags); + if (p->has_range_constraint) { + zend_dump_range_constraint(op_array, ssa, &p->constraint.range, dump_flags); + } else { + zend_dump_type_constraint(op_array, ssa, &p->constraint.type, dump_flags); + } fprintf(stderr, ")\n"); } p = p->next; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index cb8540c64b..865fb9c338 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -486,8 +486,9 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->min = ZEND_LONG_MAX; tmp->max = ZEND_LONG_MIN; tmp->overflow = 0; - if (p->pi >= 0 && p->constraint.type_mask == (uint32_t) -1) { - if (p->constraint.negative) { + if (p->pi >= 0 && p->has_range_constraint) { + zend_ssa_range_constraint *constraint = &p->constraint.range; + if (constraint->negative) { if (ssa->var_info[p->sources[0]].has_range) { tmp->underflow = ssa->var_info[p->sources[0]].range.underflow; tmp->min = ssa->var_info[p->sources[0]].range.min; @@ -500,8 +501,8 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->overflow = 1; } #ifdef NEG_RANGE - if (p->constraint.min_ssa_var < 0 && - p->constraint.min_ssa_var < 0 && + if (constraint->min_ssa_var < 0 && + constraint->min_ssa_var < 0 && ssa->var_info[p->ssa_var].has_range) { #ifdef LOG_NEG_RANGE fprintf(stderr, "%s() #%d [%ld..%ld] -> [%ld..%ld]?\n", @@ -512,19 +513,19 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->min, tmp->max); #endif - if (p->constraint.negative == NEG_USE_LT && - tmp->max >= p->constraint.range.min) { + if (constraint->negative == NEG_USE_LT && + tmp->max >= constraint->range.min) { tmp->overflow = 0; - tmp->max = p->constraint.range.min - 1; + tmp->max = constraint->range.min - 1; #ifdef LOG_NEG_RANGE fprintf(stderr, " => [%ld..%ld]\n", tmp->min, tmp->max); #endif - } else if (p->constraint.negative == NEG_USE_GT && - tmp->min <= p->constraint.range.max) { + } else if (constraint->negative == NEG_USE_GT && + tmp->min <= constraint->range.max) { tmp->underflow = 0; - tmp->min = p->constraint.range.max + 1; + tmp->min = constraint->range.max + 1; #ifdef LOG_NEG_RANGE fprintf(stderr, " => [%ld..%ld]\n", tmp->min, @@ -539,44 +540,44 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->min = ssa->var_info[p->sources[0]].range.min; tmp->max = ssa->var_info[p->sources[0]].range.max; tmp->overflow = ssa->var_info[p->sources[0]].range.overflow; - if (p->constraint.min_ssa_var < 0) { - tmp->underflow = p->constraint.range.underflow && tmp->underflow; - tmp->min = MAX(p->constraint.range.min, tmp->min); + if (constraint->min_ssa_var < 0) { + tmp->underflow = constraint->range.underflow && tmp->underflow; + tmp->min = MAX(constraint->range.min, tmp->min); #ifdef SYM_RANGE - } else if (narrowing && ssa->var_info[p->constraint.min_ssa_var].has_range) { - tmp->underflow = ssa->var_info[p->constraint.min_ssa_var].range.underflow && tmp->underflow; - tmp->min = MAX(ssa->var_info[p->constraint.min_ssa_var].range.min + p->constraint.range.min, tmp->min); + } else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) { + tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow && tmp->underflow; + tmp->min = MAX(ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min, tmp->min); #endif } - if (p->constraint.max_ssa_var < 0) { - tmp->max = MIN(p->constraint.range.max, tmp->max); - tmp->overflow = p->constraint.range.overflow && tmp->overflow; + if (constraint->max_ssa_var < 0) { + tmp->max = MIN(constraint->range.max, tmp->max); + tmp->overflow = constraint->range.overflow && tmp->overflow; #ifdef SYM_RANGE - } else if (narrowing && ssa->var_info[p->constraint.max_ssa_var].has_range) { - tmp->max = MIN(ssa->var_info[p->constraint.max_ssa_var].range.max + p->constraint.range.max, tmp->max); - tmp->overflow = ssa->var_info[p->constraint.max_ssa_var].range.overflow && tmp->overflow; + } else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) { + tmp->max = MIN(ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max, tmp->max); + tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow && tmp->overflow; #endif } } else if (narrowing) { - if (p->constraint.min_ssa_var < 0) { - tmp->underflow = p->constraint.range.underflow; - tmp->min = p->constraint.range.min; + if (constraint->min_ssa_var < 0) { + tmp->underflow = constraint->range.underflow; + tmp->min = constraint->range.min; #ifdef SYM_RANGE - } else if (narrowing && ssa->var_info[p->constraint.min_ssa_var].has_range) { - tmp->underflow = ssa->var_info[p->constraint.min_ssa_var].range.underflow; - tmp->min = ssa->var_info[p->constraint.min_ssa_var].range.min + p->constraint.range.min; + } else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) { + tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow; + tmp->min = ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min; #endif } else { tmp->underflow = 1; tmp->min = ZEND_LONG_MIN; } - if (p->constraint.max_ssa_var < 0) { - tmp->max = p->constraint.range.max; - tmp->overflow = p->constraint.range.overflow; + if (constraint->max_ssa_var < 0) { + tmp->max = constraint->range.max; + tmp->overflow = constraint->range.overflow; #ifdef SYM_RANGE - } else if (narrowing && ssa->var_info[p->constraint.max_ssa_var].has_range) { - tmp->max = ssa->var_info[p->constraint.max_ssa_var].range.max + p->constraint.range.max; - tmp->overflow = ssa->var_info[p->constraint.max_ssa_var].range.overflow; + } else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) { + tmp->max = ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max; + tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow; #endif } else { tmp->max = ZEND_LONG_MAX; @@ -1825,55 +1826,57 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss ssa->var_info[j].has_range && ssa->vars[j].definition_phi && ssa->vars[j].definition_phi->pi >= 0 && - ssa->vars[j].definition_phi->constraint.type_mask == (uint32_t) -1 && - ssa->vars[j].definition_phi->constraint.negative && - ssa->vars[j].definition_phi->constraint.min_ssa_var < 0 && - ssa->vars[j].definition_phi->constraint.min_ssa_var < 0) { + ssa->vars[j].definition_phi->has_range_constraint && + ssa->vars[j].definition_phi->constraint.range.negative && + ssa->vars[j].definition_phi->constraint.range.min_ssa_var < 0 && + ssa->vars[j].definition_phi->constraint.range.min_ssa_var < 0) { + zend_ssa_range_constraint *constraint = + &ssa->vars[j].definition_phi->constraint.range; if (tmp.min == ssa->var_info[j].range.min && tmp.max == ssa->var_info[j].range.max) { - if (ssa->vars[j].definition_phi->constraint.negative == NEG_INIT) { + if (constraint->negative == NEG_INIT) { #ifdef LOG_NEG_RANGE fprintf(stderr, "#%d INVARIANT\n", j); #endif - ssa->vars[j].definition_phi->constraint.negative = NEG_INVARIANT; + constraint->negative = NEG_INVARIANT; } } else if (tmp.min == ssa->var_info[j].range.min && tmp.max == ssa->var_info[j].range.max + 1 && - tmp.max < ssa->vars[j].definition_phi->constraint.range.min) { - if (ssa->vars[j].definition_phi->constraint.negative == NEG_INIT || - ssa->vars[j].definition_phi->constraint.negative == NEG_INVARIANT) { + tmp.max < constraint->range.min) { + if (constraint->negative == NEG_INIT || + constraint->negative == NEG_INVARIANT) { #ifdef LOG_NEG_RANGE fprintf(stderr, "#%d LT\n", j); #endif - ssa->vars[j].definition_phi->constraint.negative = NEG_USE_LT; + constraint->negative = NEG_USE_LT; //???NEG - } else if (ssa->vars[j].definition_phi->constraint.negative == NEG_USE_GT) { + } else if (constraint->negative == NEG_USE_GT) { #ifdef LOG_NEG_RANGE fprintf(stderr, "#%d UNKNOWN\n", j); #endif - ssa->vars[j].definition_phi->constraint.negative = NEG_UNKNOWN; + constraint->negative = NEG_UNKNOWN; } } else if (tmp.max == ssa->var_info[j].range.max && tmp.min == ssa->var_info[j].range.min - 1 && - tmp.min > ssa->vars[j].definition_phi->constraint.range.max) { - if (ssa->vars[j].definition_phi->constraint.negative == NEG_INIT || - ssa->vars[j].definition_phi->constraint.negative == NEG_INVARIANT) { + tmp.min > constraint->range.max) { + if (constraint->negative == NEG_INIT || + constraint->negative == NEG_INVARIANT) { #ifdef LOG_NEG_RANGE fprintf(stderr, "#%d GT\n", j); #endif - ssa->vars[j].definition_phi->constraint.negative = NEG_USE_GT; + constraint->negative = NEG_USE_GT; //???NEG - } else if (ssa->vars[j].definition_phi->constraint.negative == NEG_USE_LT) { + } else if (constraint->negative == NEG_USE_LT) { #ifdef LOG_NEG_RANGE fprintf(stderr, "#%d UNKNOWN\n", j); #endif - ssa->vars[j].definition_phi->constraint.negative = NEG_UNKNOWN; + constraint->negative = NEG_UNKNOWN; } } else { #ifdef LOG_NEG_RANGE fprintf(stderr, "#%d UNKNOWN\n", j); #endif - ssa->vars[j].definition_phi->constraint.negative = NEG_UNKNOWN; + constraint->negative = NEG_UNKNOWN; } } #endif @@ -3425,8 +3428,8 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script zend_ssa_phi *p = ssa_vars[j].definition_phi; if (p->pi >= 0) { tmp = get_ssa_var_info(ssa, p->sources[0]); - if (p->constraint.type_mask != (uint32_t) -1) { - tmp &= p->constraint.type_mask; + if (!p->has_range_constraint) { + tmp &= p->constraint.type.type_mask; } UPDATE_SSA_TYPE(tmp, j); if (ssa_var_info[p->sources[0]].ce) { diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index fc55acf527..9e585f4536 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -110,16 +110,17 @@ static void pi_range( zend_ssa_phi *phi, int min_var, int max_var, zend_long min, zend_long max, char underflow, char overflow, char negative) /* {{{ */ { - phi->constraint.min_var = min_var; - phi->constraint.max_var = max_var; - phi->constraint.min_ssa_var = -1; - phi->constraint.max_ssa_var = -1; - phi->constraint.range.min = min; - phi->constraint.range.max = max; - phi->constraint.range.underflow = underflow; - phi->constraint.range.overflow = overflow; - phi->constraint.negative = negative ? NEG_INIT : NEG_NONE; - phi->constraint.type_mask = (uint32_t) -1; + zend_ssa_range_constraint *constraint = &phi->constraint.range; + constraint->min_var = min_var; + constraint->max_var = max_var; + constraint->min_ssa_var = -1; + constraint->max_ssa_var = -1; + constraint->range.min = min; + constraint->range.max = max; + constraint->range.underflow = underflow; + constraint->range.overflow = overflow; + constraint->negative = negative ? NEG_INIT : NEG_NONE; + phi->has_range_constraint = 1; } /* }}} */ @@ -137,10 +138,11 @@ static inline void pi_range_max(zend_ssa_phi *phi, int var, zend_long val) { } static void pi_type_mask(zend_ssa_phi *phi, uint32_t type_mask) { - phi->constraint.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN; - phi->constraint.type_mask |= type_mask; + phi->has_range_constraint = 0; + phi->constraint.type.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN; + phi->constraint.type.type_mask |= type_mask; if (type_mask & MAY_BE_NULL) { - phi->constraint.type_mask |= MAY_BE_UNDEF; + phi->constraint.type.type_mask |= MAY_BE_UNDEF; } } static inline void pi_not_type_mask(zend_ssa_phi *phi, uint32_t type_mask) { @@ -741,11 +743,13 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, for (p = ssa_blocks[succ].phis; p; p = p->next) { if (p->pi == n) { /* e-SSA Pi */ - if (p->constraint.min_var >= 0) { - p->constraint.min_ssa_var = var[p->constraint.min_var]; - } - if (p->constraint.max_var >= 0) { - p->constraint.max_ssa_var = var[p->constraint.max_var]; + if (p->has_range_constraint) { + if (p->constraint.range.min_var >= 0) { + p->constraint.range.min_ssa_var = var[p->constraint.range.min_var]; + } + if (p->constraint.range.max_var >= 0) { + p->constraint.range.max_ssa_var = var[p->constraint.range.max_var]; + } } for (j = 0; j < blocks[succ].predecessors_count; j++) { p->sources[j] = var[p->var]; @@ -1021,13 +1025,16 @@ int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_ ssa_vars[phi->sources[0]].phi_use_chain = phi; } } - /* min and max variables can't be used together */ - if (phi->constraint.min_ssa_var >= 0) { - phi->sym_use_chain = ssa_vars[phi->constraint.min_ssa_var].sym_use_chain; - ssa_vars[phi->constraint.min_ssa_var].sym_use_chain = phi; - } else if (phi->constraint.max_ssa_var >= 0) { - phi->sym_use_chain = ssa_vars[phi->constraint.max_ssa_var].sym_use_chain; - ssa_vars[phi->constraint.max_ssa_var].sym_use_chain = phi; + if (phi->has_range_constraint) { + /* min and max variables can't be used together */ + zend_ssa_range_constraint *constraint = &phi->constraint.range; + if (constraint->min_ssa_var >= 0) { + phi->sym_use_chain = ssa_vars[constraint->min_ssa_var].sym_use_chain; + ssa_vars[constraint->min_ssa_var].sym_use_chain = phi; + } else if (constraint->max_ssa_var >= 0) { + phi->sym_use_chain = ssa_vars[constraint->max_ssa_var].sym_use_chain; + ssa_vars[constraint->max_ssa_var].sym_use_chain = phi; + } } } else { int j; diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h index 1bb43052f7..02b1183930 100644 --- a/ext/opcache/Optimizer/zend_ssa.h +++ b/ext/opcache/Optimizer/zend_ssa.h @@ -38,14 +38,22 @@ typedef enum _zend_ssa_negative_lat { } zend_ssa_negative_lat; /* Special kind of SSA Phi function used in eSSA */ -typedef struct _zend_ssa_pi_constraint { +typedef struct _zend_ssa_range_constraint { zend_ssa_range range; /* simple range constraint */ int min_var; int max_var; int min_ssa_var; /* ((min_var>0) ? MIN(ssa_var) : 0) + range.min */ int max_ssa_var; /* ((max_var>0) ? MAX(ssa_var) : 0) + range.max */ zend_ssa_negative_lat negative; - uint32_t type_mask; /* If -1 this is a range constraint */ +} zend_ssa_range_constraint; + +typedef struct _zend_ssa_type_constraint { + uint32_t type_mask; /* If -1 this is a range constraint */ +} zend_ssa_type_constraint; + +typedef union _zend_ssa_pi_constraint { + zend_ssa_range_constraint range; + zend_ssa_type_constraint type; } zend_ssa_pi_constraint; /* SSA Phi - ssa_var = Phi(source0, source1, ...sourceN) */ @@ -57,7 +65,8 @@ struct _zend_ssa_phi { int var; /* Original CV, VAR or TMP variable index */ int ssa_var; /* SSA variable index */ int block; /* current BB index */ - int visited; /* flag to avoid recursive processing */ + int visited : 1; /* flag to avoid recursive processing */ + int has_range_constraint : 1; zend_ssa_phi **use_chains; zend_ssa_phi *sym_use_chain; int *sources; /* Array of SSA IDs that produce this var.