]> granicus.if.org Git - php/commitdiff
Range inference cleanup
authorNikita Popov <nikic@php.net>
Tue, 8 Nov 2016 19:41:27 +0000 (20:41 +0100)
committerNikita Popov <nikic@php.net>
Thu, 10 Nov 2016 13:55:40 +0000 (14:55 +0100)
Replace inline #ifdefs with some macros. Fix build if NEG_RANGE is
disabled. Fix some typos. Add some comments.

ext/opcache/Optimizer/zend_inference.c

index 1fff94ea19352f0d9a9dde1d7a17eb9166bcdbbf..a25a0cef769ad5a67645c997da4329bbc9123044 100644 (file)
 #include "zend_call_graph.h"
 #include "zend_worklist.h"
 
-//#define LOG_SSA_RANGE
-//#define LOG_NEG_RANGE
+/* The used range inference algorithm is described in:
+ *     V. Campos, R. Rodrigues, I. de Assis Costa and F. Pereira.
+ *     "Speed and Precision in Range Analysis", SBLP'12.
+ *
+ * There are a couple degrees of freedom, we use:
+ *  * Propagation on SCCs.
+ *  * e-SSA for live range splitting.
+ *  * Only intra-procedural inference.
+ *  * Widening with warmup passes, but without jump sets.
+ */
+
+/* Whether to handle symbolic range constraints */
 #define SYM_RANGE
+
+/* Whether to handle negative range constraints */
 #define NEG_RANGE
-#define RANGE_WARMAP_PASSES 16
+
+/* Number of warmup passes to use prior to widening */
+#define RANGE_WARMUP_PASSES 16
+
+/* Logging for range inference in general */
+#if 0
+#define LOG_SSA_RANGE(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define LOG_SSA_RANGE(...)
+#endif
+
+/* Logging for negative range constraints */
+#if 0
+#define LOG_NEG_RANGE(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define LOG_NEG_RANGE(...)
+#endif
 
 #define CHECK_SCC_VAR(var2) \
        do { \
@@ -167,14 +195,14 @@ int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
        root = do_alloca(sizeof(int) * ssa->vars_count, root_use_heap);
        ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
 
-       /* Find SCCs */
+       /* Find SCCs using Tarjan's algorithm. */
        for (j = 0; j < ssa->vars_count; j++) {
                if (!ssa->vars[j].no_val && dfs[j] < 0) {
                        zend_ssa_check_scc_var(op_array, ssa, j, &index, dfs, root, &stack);
                }
        }
 
-       /* Revert SCC order */
+       /* Revert SCC order. This results in a topological order. */
        for (j = 0; j < ssa->vars_count; j++) {
                if (ssa->vars[j].scc >= 0) {
                        ssa->vars[j].scc = ssa->sccs - (ssa->vars[j].scc + 1);
@@ -490,56 +518,41 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
                        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;
-                                       tmp->max = ssa->var_info[p->sources[0]].range.max;
-                                       tmp->overflow = ssa->var_info[p->sources[0]].range.overflow;
+                                       *tmp = ssa->var_info[p->sources[0]].range;
                                } else if (narrowing) {
                                        tmp->underflow = 1;
                                        tmp->min = ZEND_LONG_MIN;
                                        tmp->max = ZEND_LONG_MAX;
                                        tmp->overflow = 1;
                                }
+
 #ifdef NEG_RANGE
                                if (constraint->min_ssa_var < 0 &&
-                                   constraint->min_ssa_var < 0 &&
+                                   constraint->max_ssa_var < 0 &&
                                    ssa->var_info[p->ssa_var].has_range) {
-#ifdef LOG_NEG_RANGE
-                                       fprintf(stderr, "%s() #%d [%ld..%ld] -> [%ld..%ld]?\n",
-                                               op_array->function_name,
+                                       LOG_NEG_RANGE("%s() #%d [%ld..%ld] -> [%ld..%ld]?\n",
+                                               ZSTR_VAL(op_array->function_name),
                                                p->ssa_var,
                                                ssa->var_info[p->ssa_var].range.min,
                                                ssa->var_info[p->ssa_var].range.max,
                                                tmp->min,
                                                tmp->max);
-#endif
                                        if (constraint->negative == NEG_USE_LT &&
                                            tmp->max >= constraint->range.min) {
                                                tmp->overflow = 0;
                                                tmp->max = constraint->range.min - 1;
-#ifdef LOG_NEG_RANGE
-                                               fprintf(stderr, "  => [%ld..%ld]\n",
-                                                       tmp->min,
-                                                       tmp->max);
-#endif
+                                               LOG_NEG_RANGE("  => [%ld..%ld]\n", tmp->min, tmp->max);
                                        } else if (constraint->negative == NEG_USE_GT &&
                                                   tmp->min <= constraint->range.max) {
                                                tmp->underflow = 0;
                                                tmp->min = constraint->range.max + 1;
-#ifdef LOG_NEG_RANGE
-                                               fprintf(stderr, "  => [%ld..%ld]\n",
-                                                       tmp->min,
-                                                       tmp->max);
-#endif
+                                               LOG_NEG_RANGE("  => [%ld..%ld]\n", tmp->min, tmp->max);
                                        }
                                }
 #endif
                        } else if (ssa->var_info[p->sources[0]].has_range) {
                                /* intersection */
-                               tmp->underflow = ssa->var_info[p->sources[0]].range.underflow;
-                               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;
+                               *tmp = ssa->var_info[p->sources[0]].range;
                                if (constraint->min_ssa_var < 0) {
                                        tmp->underflow = constraint->range.underflow && tmp->underflow;
                                        tmp->min = MAX(constraint->range.min, tmp->min);
@@ -1694,9 +1707,7 @@ void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int
        ssa->var_info[var].range.min = min;
        ssa->var_info[var].range.max = max;
        ssa->var_info[var].range.overflow = overflow;
-#ifdef LOG_SSA_RANGE
-       fprintf(stderr, "  change range (init      SCC %2d) %2d [%s%ld..%ld%s]\n", ssa->vars[var].scc, var, (underflow?"-- ":""), min, max, (overflow?" ++":""));
-#endif
+       LOG_SSA_RANGE("  change range (init      SCC %2d) %2d [%s%ld..%ld%s]\n", ssa->vars[var].scc, var, (underflow?"-- ":""), min, max, (overflow?" ++":""));
 }
 
 int zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r)
@@ -1733,9 +1744,7 @@ static int zend_ssa_range_widening(const zend_op_array *op_array, zend_ssa *ssa,
 
        if (zend_inference_calc_range(op_array, ssa, var, 1, 0, &tmp)) {
                if (zend_inference_widening_meet(&ssa->var_info[var], &tmp)) {
-#ifdef LOG_SSA_RANGE
-                       fprintf(stderr, "  change range (widening  SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
-#endif
+                       LOG_SSA_RANGE("  change range (widening  SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
                        return 1;
                }
        }
@@ -1780,9 +1789,7 @@ static int zend_ssa_range_narrowing(const zend_op_array *op_array, zend_ssa *ssa
 
        if (zend_inference_calc_range(op_array, ssa, var, 0, 1, &tmp)) {
                if (zend_inference_narrowing_meet(&ssa->var_info[var], &tmp)) {
-#ifdef LOG_SSA_RANGE
-                       fprintf(stderr, "  change range (narrowing SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
-#endif
+                       LOG_SSA_RANGE("  change range (narrowing SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
                        return 1;
                }
        }
@@ -1815,19 +1822,17 @@ static int zend_check_inner_cycles(const zend_op_array *op_array, zend_ssa *ssa,
 static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ssa, int *scc_var, int *next_scc_var, int scc)
 {
        int worklist_len = zend_bitset_len(ssa->vars_count);
-       zend_bitset worklist;
-       zend_bitset visited;
        int j, n;
        zend_ssa_range tmp;
+       ALLOCA_FLAG(use_heap);
+       zend_bitset worklist = do_alloca(sizeof(zend_ulong) * worklist_len * 2, use_heap);
+       zend_bitset visited = worklist + worklist_len;
 #ifdef NEG_RANGE
        int has_inner_cycles = 0;
-       ALLOCA_FLAG(use_heap);
 
-       worklist = do_alloca(sizeof(zend_ulong) * worklist_len * 2, use_heap);
-       visited = worklist + worklist_len;
        memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
        memset(visited, 0, sizeof(zend_ulong) * worklist_len);
-       j= scc_var[scc];
+       j = scc_var[scc];
        while (j >= 0) {
                if (!zend_bitset_in(visited, j) &&
                    zend_check_inner_cycles(op_array, ssa, worklist, visited, j)) {
@@ -1840,7 +1845,7 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
 
        memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
 
-       for (n = 0; n < RANGE_WARMAP_PASSES; n++) {
+       for (n = 0; n < RANGE_WARMUP_PASSES; n++) {
                j= scc_var[scc];
                while (j >= 0) {
                        if (ssa->vars[j].scc_entry) {
@@ -1869,9 +1874,7 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
                                        if (tmp.min == ssa->var_info[j].range.min &&
                                            tmp.max == ssa->var_info[j].range.max) {
                                                if (constraint->negative == NEG_INIT) {
-#ifdef LOG_NEG_RANGE
-                                                       fprintf(stderr, "#%d INVARIANT\n", j);
-#endif
+                                                       LOG_NEG_RANGE("#%d INVARIANT\n", j);
                                                        constraint->negative = NEG_INVARIANT;
                                                }
                                        } else if (tmp.min == ssa->var_info[j].range.min &&
@@ -1879,15 +1882,11 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
                                                   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
+                                                       LOG_NEG_RANGE("#%d LT\n", j);
                                                        constraint->negative = NEG_USE_LT;
 //???NEG
                                                } else if (constraint->negative == NEG_USE_GT) {
-#ifdef LOG_NEG_RANGE
-                                                       fprintf(stderr, "#%d UNKNOWN\n", j);
-#endif
+                                                       LOG_NEG_RANGE("#%d UNKNOWN\n", j);
                                                        constraint->negative = NEG_UNKNOWN;
                                                }
                                        } else if (tmp.max == ssa->var_info[j].range.max &&
@@ -1895,29 +1894,21 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
                                                   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
+                                                       LOG_NEG_RANGE("#%d GT\n", j);
                                                        constraint->negative = NEG_USE_GT;
 //???NEG
                                                } else if (constraint->negative == NEG_USE_LT) {
-#ifdef LOG_NEG_RANGE
-                                                       fprintf(stderr, "#%d UNKNOWN\n", j);
-#endif
+                                                       LOG_NEG_RANGE("#%d UNKNOWN\n", j);
                                                        constraint->negative = NEG_UNKNOWN;
                                                }
                                        } else {
-#ifdef LOG_NEG_RANGE
-                                               fprintf(stderr, "#%d UNKNOWN\n", j);
-#endif
+                                               LOG_NEG_RANGE("#%d UNKNOWN\n", j);
                                                constraint->negative = NEG_UNKNOWN;
                                        }
                                }
 #endif
                                if (zend_inference_narrowing_meet(&ssa->var_info[j], &tmp)) {
-#ifdef LOG_SSA_RANGE
-                                       fprintf(stderr, "  change range (warmup %d  SCC %2d) %2d [%s%ld..%ld%s]\n", n, scc, j, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
-#endif
+                                       LOG_SSA_RANGE("  change range (warmup %2d SCC %2d) %2d [%s%ld..%ld%s]\n", n, scc, j, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
                                        zend_bitset_incl(visited, j);
                                        FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR_1);
                                }
@@ -1945,9 +1936,7 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
        next_scc_var = (int*)(worklist + worklist_len);
        scc_var = next_scc_var + ssa->vars_count;
 
-#ifdef LOG_SSA_RANGE
-       fprintf(stderr, "Range Inference\n");
-#endif
+       LOG_SSA_RANGE("Range Inference\n");
 
        /* Create linked lists of SSA variables for each SCC */
        memset(scc_var, -1, sizeof(int) * ssa->sccs);
@@ -1977,7 +1966,7 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
                                j = next_scc_var[j];
                        } while (j >= 0);
 
-#if RANGE_WARMAP_PASSES > 0
+#if RANGE_WARMUP_PASSES > 0
                        zend_infer_ranges_warmup(op_array, ssa, scc_var, next_scc_var, scc);
                        j = scc_var[scc];
                        do {