From 431ea10fb2e11d83ea52a8fd7fb52c59b5082d3c Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 5 Sep 2017 14:46:03 +0300 Subject: [PATCH] Remove unused temporary variables --- ext/opcache/Optimizer/compact_vars.c | 87 ++++++++++++++++------------ ext/opcache/tests/opt/dce_001.phpt | 2 +- ext/opcache/tests/opt/dce_002.phpt | 2 +- ext/opcache/tests/opt/dce_003.phpt | 2 +- ext/opcache/tests/opt/dce_004.phpt | 2 +- ext/opcache/tests/opt/dce_005.phpt | 2 +- ext/opcache/tests/opt/sccp_001.phpt | 2 +- ext/opcache/tests/opt/sccp_002.phpt | 2 +- ext/opcache/tests/opt/sccp_003.phpt | 2 +- ext/opcache/tests/opt/sccp_004.phpt | 2 +- ext/opcache/tests/opt/sccp_005.phpt | 2 +- ext/opcache/tests/opt/sccp_007.phpt | 2 +- ext/opcache/tests/opt/sccp_009.phpt | 2 +- ext/opcache/tests/opt/sccp_010.phpt | 2 +- ext/opcache/tests/opt/sccp_011.phpt | 2 +- ext/opcache/tests/opt/sccp_012.phpt | 2 +- ext/opcache/tests/opt/sccp_016.phpt | 2 +- 17 files changed, 66 insertions(+), 53 deletions(-) diff --git a/ext/opcache/Optimizer/compact_vars.c b/ext/opcache/Optimizer/compact_vars.c index c5a9b79553d..016fbfffbca 100644 --- a/ext/opcache/Optimizer/compact_vars.c +++ b/ext/opcache/Optimizer/compact_vars.c @@ -20,84 +20,96 @@ #include "Optimizer/zend_optimizer_internal.h" #include "zend_bitset.h" -/* This pass removes all CVs that are completely unused. It does *not* merge any CVs. +/* This pass removes all CVs and temporaries that are completely unused. It does *not* merge any CVs or TMPs. * This pass does not operate on SSA form anymore. */ void zend_optimizer_compact_vars(zend_op_array *op_array) { int i; ALLOCA_FLAG(use_heap1); ALLOCA_FLAG(use_heap2); - uint32_t used_cvs_len = zend_bitset_len(op_array->last_var); - zend_bitset used_cvs = ZEND_BITSET_ALLOCA(used_cvs_len, use_heap1); - uint32_t *cv_map = do_alloca(op_array->last_var * sizeof(uint32_t), use_heap2); - uint32_t num_cvs, tmp_offset; + uint32_t used_vars_len = zend_bitset_len(op_array->last_var + op_array->T); + zend_bitset used_vars = ZEND_BITSET_ALLOCA(used_vars_len, use_heap1); + uint32_t *vars_map = do_alloca((op_array->last_var + op_array->T) * sizeof(uint32_t), use_heap2); + uint32_t num_cvs, num_tmps; /* Determine which CVs are used */ - zend_bitset_clear(used_cvs, used_cvs_len); + zend_bitset_clear(used_vars, used_vars_len); for (i = 0; i < op_array->last; i++) { zend_op *opline = &op_array->opcodes[i]; - if (opline->op1_type == IS_CV) { - zend_bitset_incl(used_cvs, VAR_NUM(opline->op1.var)); + if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { + zend_bitset_incl(used_vars, VAR_NUM(opline->op1.var)); } - if (opline->op2_type == IS_CV) { - zend_bitset_incl(used_cvs, VAR_NUM(opline->op2.var)); + if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { + zend_bitset_incl(used_vars, VAR_NUM(opline->op2.var)); } - if (opline->result_type == IS_CV) { - zend_bitset_incl(used_cvs, VAR_NUM(opline->result.var)); + if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { + zend_bitset_incl(used_vars, VAR_NUM(opline->result.var)); + if (opline->opcode == ZEND_ROPE_INIT) { + uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); + while (num > 1) { + num--; + zend_bitset_incl(used_vars, VAR_NUM(opline->result.var) + num); + } + } } } num_cvs = 0; for (i = 0; i < op_array->last_var; i++) { - if (zend_bitset_in(used_cvs, i)) { - cv_map[i] = num_cvs++; + if (zend_bitset_in(used_vars, i)) { + vars_map[i] = num_cvs++; } else { - cv_map[i] = (uint32_t) -1; + vars_map[i] = (uint32_t) -1; } } - free_alloca(used_cvs, use_heap1); - if (num_cvs == op_array->last_var) { - free_alloca(cv_map, use_heap2); + num_tmps = 0; + for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) { + if (zend_bitset_in(used_vars, i)) { + vars_map[i] = num_cvs + num_tmps++; + } else { + vars_map[i] = (uint32_t) -1; + } + } + + free_alloca(used_vars, use_heap1); + if (num_cvs == op_array->last_var && num_tmps == op_array->T) { + free_alloca(vars_map, use_heap2); return; } - ZEND_ASSERT(num_cvs < op_array->last_var); - tmp_offset = op_array->last_var - num_cvs; + ZEND_ASSERT(num_cvs <= op_array->last_var); + ZEND_ASSERT(num_tmps <= op_array->T); /* Update CV and TMP references in opcodes */ for (i = 0; i < op_array->last; i++) { zend_op *opline = &op_array->opcodes[i]; - if (opline->op1_type == IS_CV) { - opline->op1.var = NUM_VAR(cv_map[VAR_NUM(opline->op1.var)]); - } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { - opline->op1.var -= sizeof(zval) * tmp_offset; + if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { + opline->op1.var = NUM_VAR(vars_map[VAR_NUM(opline->op1.var)]); } - if (opline->op2_type == IS_CV) { - opline->op2.var = NUM_VAR(cv_map[VAR_NUM(opline->op2.var)]); - } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { - opline->op2.var -= sizeof(zval) * tmp_offset; + if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { + opline->op2.var = NUM_VAR(vars_map[VAR_NUM(opline->op2.var)]); } - if (opline->result_type == IS_CV) { - opline->result.var = NUM_VAR(cv_map[VAR_NUM(opline->result.var)]); - } else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { - opline->result.var -= sizeof(zval) * tmp_offset; + if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { + opline->result.var = NUM_VAR(vars_map[VAR_NUM(opline->result.var)]); } } /* Update TMP references in live ranges */ if (op_array->live_range) { for (i = 0; i < op_array->last_live_range; i++) { - op_array->live_range[i].var -= sizeof(zval) * tmp_offset; + op_array->live_range[i].var = + (op_array->live_range[i].var & ZEND_LIVE_MASK) | + NUM_VAR(vars_map[VAR_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK)]); } } /* Update CV name table */ - { + if (num_cvs != op_array->last_var) { zend_string **names = safe_emalloc(sizeof(zend_string *), num_cvs, 0); for (i = 0; i < op_array->last_var; i++) { - if (cv_map[i] != (uint32_t) -1) { - names[cv_map[i]] = op_array->vars[i]; + if (vars_map[i] != (uint32_t) -1) { + names[vars_map[i]] = op_array->vars[i]; } else { zend_string_release(op_array->vars[i]); } @@ -107,6 +119,7 @@ void zend_optimizer_compact_vars(zend_op_array *op_array) { } op_array->last_var = num_cvs; + op_array->T = num_tmps; - free_alloca(cv_map, use_heap2); + free_alloca(vars_map, use_heap2); } diff --git a/ext/opcache/tests/opt/dce_001.phpt b/ext/opcache/tests/opt/dce_001.phpt index 97011f08038..e41afdafa16 100644 --- a/ext/opcache/tests/opt/dce_001.phpt +++ b/ext/opcache/tests/opt/dce_001.phpt @@ -21,7 +21,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %sdce_001.php:1-8 L0: RETURN int(1) -foo: ; (lines=5, args=4, vars=4, tmps=3) +foo: ; (lines=5, args=4, vars=4, tmps=0) ; (after optimizer) ; %sdce_001.php:2-6 L0: CV0($s1) = RECV 1 diff --git a/ext/opcache/tests/opt/dce_002.phpt b/ext/opcache/tests/opt/dce_002.phpt index 5fb9f47ee7c..6cb50a3f0ba 100644 --- a/ext/opcache/tests/opt/dce_002.phpt +++ b/ext/opcache/tests/opt/dce_002.phpt @@ -24,7 +24,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %sdce_002.php:1-11 L0: RETURN int(1) -foo: ; (lines=5, args=1, vars=2, tmps=1) +foo: ; (lines=5, args=1, vars=2, tmps=0) ; (after optimizer) ; %sdce_002.php:2-9 L0: CV0($a) = RECV 1 diff --git a/ext/opcache/tests/opt/dce_003.phpt b/ext/opcache/tests/opt/dce_003.phpt index 815bf42d534..651a8fea481 100644 --- a/ext/opcache/tests/opt/dce_003.phpt +++ b/ext/opcache/tests/opt/dce_003.phpt @@ -20,7 +20,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %sdce_003.php:1-7 L0: RETURN int(1) -foo: ; (lines=3, args=1, vars=1, tmps=1) +foo: ; (lines=3, args=1, vars=1, tmps=0) ; (after optimizer) ; %sdce_003.php:2-5 L0: CV0($a) = RECV 1 diff --git a/ext/opcache/tests/opt/dce_004.phpt b/ext/opcache/tests/opt/dce_004.phpt index 74eda804e77..3038028294b 100644 --- a/ext/opcache/tests/opt/dce_004.phpt +++ b/ext/opcache/tests/opt/dce_004.phpt @@ -21,7 +21,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %sdce_004.php:1-8 L0: RETURN int(1) -foo: ; (lines=4, args=2, vars=3, tmps=1) +foo: ; (lines=4, args=2, vars=3, tmps=0) ; (after optimizer) ; %sdce_004.php:2-7 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/dce_005.phpt b/ext/opcache/tests/opt/dce_005.phpt index cabd534ee4a..5aa13b3c380 100644 --- a/ext/opcache/tests/opt/dce_005.phpt +++ b/ext/opcache/tests/opt/dce_005.phpt @@ -21,7 +21,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %sdce_005.php:1-8 L0: RETURN int(1) -foo: ; (lines=2, args=1, vars=1, tmps=1) +foo: ; (lines=2, args=1, vars=1, tmps=0) ; (after optimizer) ; %sdce_005.php:4-7 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_001.phpt b/ext/opcache/tests/opt/sccp_001.phpt index 70d2ddce07c..9e629274054 100644 --- a/ext/opcache/tests/opt/sccp_001.phpt +++ b/ext/opcache/tests/opt/sccp_001.phpt @@ -22,7 +22,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_001.php:1-9 L0: RETURN int(1) -foo: ; (lines=1, args=0, vars=0, tmps=1) +foo: ; (lines=1, args=0, vars=0, tmps=0) ; (after optimizer) ; %ssccp_001.php:2-7 L0: RETURN int(4) diff --git a/ext/opcache/tests/opt/sccp_002.phpt b/ext/opcache/tests/opt/sccp_002.phpt index 3b9aae441eb..960888e1fda 100644 --- a/ext/opcache/tests/opt/sccp_002.phpt +++ b/ext/opcache/tests/opt/sccp_002.phpt @@ -27,7 +27,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_002.php:1-14 L0: RETURN int(1) -foo: ; (lines=4, args=1, vars=1, tmps=1) +foo: ; (lines=4, args=1, vars=1, tmps=0) ; (after optimizer) ; %ssccp_002.php:2-12 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_003.phpt b/ext/opcache/tests/opt/sccp_003.phpt index 84c1e5ae971..63e225b4be2 100644 --- a/ext/opcache/tests/opt/sccp_003.phpt +++ b/ext/opcache/tests/opt/sccp_003.phpt @@ -27,7 +27,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_003.php:1-14 L0: RETURN int(1) -foo: ; (lines=3, args=0, vars=0, tmps=1) +foo: ; (lines=3, args=0, vars=0, tmps=0) ; (after optimizer) ; %ssccp_003.php:2-12 L0: ECHO int(1) diff --git a/ext/opcache/tests/opt/sccp_004.phpt b/ext/opcache/tests/opt/sccp_004.phpt index 7a59bfaa38d..e8a7593b65e 100644 --- a/ext/opcache/tests/opt/sccp_004.phpt +++ b/ext/opcache/tests/opt/sccp_004.phpt @@ -30,7 +30,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_004.php:1-17 L0: RETURN int(1) -foo: ; (lines=4, args=1, vars=1, tmps=1) +foo: ; (lines=4, args=1, vars=1, tmps=0) ; (after optimizer) ; %ssccp_004.php:2-15 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_005.phpt b/ext/opcache/tests/opt/sccp_005.phpt index bb639f7ec7d..0ec6e04be54 100644 --- a/ext/opcache/tests/opt/sccp_005.phpt +++ b/ext/opcache/tests/opt/sccp_005.phpt @@ -20,7 +20,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_005.php:1-7 L0: RETURN int(1) -foo: ; (lines=3, args=1, vars=1, tmps=1) +foo: ; (lines=3, args=1, vars=1, tmps=0) ; (after optimizer) ; %ssccp_005.php:2-5 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_007.phpt b/ext/opcache/tests/opt/sccp_007.phpt index 8aeda320118..f9cb4132b10 100644 --- a/ext/opcache/tests/opt/sccp_007.phpt +++ b/ext/opcache/tests/opt/sccp_007.phpt @@ -24,7 +24,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_007.php:1-11 L0: RETURN int(1) -foo: ; (lines=5, args=1, vars=1, tmps=1) +foo: ; (lines=5, args=1, vars=1, tmps=0) ; (after optimizer) ; %ssccp_007.php:2-9 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_009.phpt b/ext/opcache/tests/opt/sccp_009.phpt index 9da9a3bbc1a..78efe458151 100644 --- a/ext/opcache/tests/opt/sccp_009.phpt +++ b/ext/opcache/tests/opt/sccp_009.phpt @@ -21,7 +21,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_009.php:1-8 L0: RETURN int(1) -foo: ; (lines=3, args=1, vars=1, tmps=1) +foo: ; (lines=3, args=1, vars=1, tmps=0) ; (after optimizer) ; %ssccp_009.php:2-6 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_010.phpt b/ext/opcache/tests/opt/sccp_010.phpt index 7d0d5332162..7e91107f41d 100644 --- a/ext/opcache/tests/opt/sccp_010.phpt +++ b/ext/opcache/tests/opt/sccp_010.phpt @@ -28,7 +28,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_010.php:1-15 L0: RETURN int(1) -foo: ; (lines=3, args=0, vars=0, tmps=1) +foo: ; (lines=3, args=0, vars=0, tmps=0) ; (after optimizer) ; %ssccp_010.php:2-13 L0: ECHO int(1) diff --git a/ext/opcache/tests/opt/sccp_011.phpt b/ext/opcache/tests/opt/sccp_011.phpt index 49288deb43f..e679d5f8b86 100644 --- a/ext/opcache/tests/opt/sccp_011.phpt +++ b/ext/opcache/tests/opt/sccp_011.phpt @@ -27,7 +27,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_011.php:1-14 L0: RETURN int(1) -foo: ; (lines=5, args=1, vars=1, tmps=1) +foo: ; (lines=5, args=1, vars=1, tmps=0) ; (after optimizer) ; %ssccp_011.php:2-12 L0: CV0($x) = RECV 1 diff --git a/ext/opcache/tests/opt/sccp_012.phpt b/ext/opcache/tests/opt/sccp_012.phpt index 41db449316c..fb4ee3d897c 100644 --- a/ext/opcache/tests/opt/sccp_012.phpt +++ b/ext/opcache/tests/opt/sccp_012.phpt @@ -30,7 +30,7 @@ $_main: ; (lines=1, args=0, vars=0, tmps=0) ; %ssccp_012.php:1-17 L0: RETURN int(1) -foo: ; (lines=3, args=0, vars=0, tmps=1) +foo: ; (lines=3, args=0, vars=0, tmps=0) ; (after optimizer) ; %ssccp_012.php:2-15 L0: ECHO int(1) diff --git a/ext/opcache/tests/opt/sccp_016.phpt b/ext/opcache/tests/opt/sccp_016.phpt index 18562b019ba..d877e57a719 100644 --- a/ext/opcache/tests/opt/sccp_016.phpt +++ b/ext/opcache/tests/opt/sccp_016.phpt @@ -12,7 +12,7 @@ opcache.opt_debug_level=0x20000 return isset($undef) || php_sapi_name() == php_sapi_name(); ?> --EXPECTF-- -$_main: ; (lines=4, args=0, vars=1, tmps=3) +$_main: ; (lines=4, args=0, vars=1, tmps=1) ; (after optimizer) ; %ssccp_016.php:1-4 L0: T1 = ISSET_ISEMPTY_CV (isset) CV0($undef)