]> granicus.if.org Git - php/commitdiff
Use union for pi constraints
authorNikita Popov <nikic@php.net>
Tue, 7 Jun 2016 19:16:29 +0000 (21:16 +0200)
committerNikita Popov <nikic@php.net>
Mon, 13 Jun 2016 17:03:57 +0000 (19:03 +0200)
This will make it easier to extend pi constraints without impacting
structure sizes.

ext/opcache/Optimizer/zend_dump.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_ssa.c
ext/opcache/Optimizer/zend_ssa.h

index 7c225bbbe8618a9a51ed8330f0423ec94dab7010..17f5437c9592e78c6d468066f23afc87963b5ebc 100644 (file)
@@ -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<BB%d>(", 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;
index cb8540c64bb9c512d7639298296b1422a3bb1bb2..865fb9c3382a676a65c98a72f0a739dcbecd7e73 100644 (file)
@@ -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) {
index fc55acf5275607fed79257cf1f4294f203c9da4a..9e585f4536781283c190e89ecad37e771f030d48 100644 (file)
@@ -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;
index 1bb43052f7c8c39fd50718543bcec5b243d29b0f..02b1183930d679e1961da04dd3943ac8bb6a495c 100644 (file)
@@ -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.