Skip to content

Commit 8c0de53

Browse files
committed
Initial integration of Dead Code Elimination (DCE) and unused variable removing passes, originally developed in https://github.com/nikic/php-src/tree/opt, into DFA optimization pass.
1 parent d1eb5ed commit 8c0de53

11 files changed

+1179
-2
lines changed

ext/opcache/Optimizer/compact_vars.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine, Removing unused variables |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1998-2017 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| license@php.net so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Nikita Popov <nikic@php.net> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#include "ZendAccelerator.h"
20+
#include "Optimizer/zend_optimizer_internal.h"
21+
#include "zend_bitset.h"
22+
23+
/* This pass removes all CVs that are completely unused. It does *not* merge any CVs.
24+
* This pass does not operate on SSA form anymore. */
25+
void zend_optimizer_compact_vars(zend_op_array *op_array) {
26+
int i;
27+
28+
ALLOCA_FLAG(use_heap1);
29+
ALLOCA_FLAG(use_heap2);
30+
uint32_t used_cvs_len = zend_bitset_len(op_array->last_var);
31+
zend_bitset used_cvs = ZEND_BITSET_ALLOCA(used_cvs_len, use_heap1);
32+
uint32_t *cv_map = do_alloca(op_array->last_var * sizeof(uint32_t), use_heap2);
33+
uint32_t num_cvs, tmp_offset;
34+
35+
/* Determine which CVs are used */
36+
zend_bitset_clear(used_cvs, used_cvs_len);
37+
for (i = 0; i < op_array->last; i++) {
38+
zend_op *opline = &op_array->opcodes[i];
39+
if (opline->op1_type == IS_CV) {
40+
zend_bitset_incl(used_cvs, VAR_NUM(opline->op1.var));
41+
}
42+
if (opline->op2_type == IS_CV) {
43+
zend_bitset_incl(used_cvs, VAR_NUM(opline->op2.var));
44+
}
45+
if (opline->result_type == IS_CV) {
46+
zend_bitset_incl(used_cvs, VAR_NUM(opline->result.var));
47+
}
48+
}
49+
50+
num_cvs = 0;
51+
for (i = 0; i < op_array->last_var; i++) {
52+
if (zend_bitset_in(used_cvs, i)) {
53+
cv_map[i] = num_cvs++;
54+
} else {
55+
cv_map[i] = (uint32_t) -1;
56+
}
57+
}
58+
59+
free_alloca(used_cvs, use_heap1);
60+
if (num_cvs == op_array->last_var) {
61+
free_alloca(cv_map, use_heap2);
62+
return;
63+
}
64+
65+
ZEND_ASSERT(num_cvs < op_array->last_var);
66+
tmp_offset = op_array->last_var - num_cvs;
67+
68+
/* Update CV and TMP references in opcodes */
69+
for (i = 0; i < op_array->last; i++) {
70+
zend_op *opline = &op_array->opcodes[i];
71+
if (opline->op1_type == IS_CV) {
72+
opline->op1.var = NUM_VAR(cv_map[VAR_NUM(opline->op1.var)]);
73+
} else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
74+
opline->op1.var -= sizeof(zval) * tmp_offset;
75+
}
76+
if (opline->op2_type == IS_CV) {
77+
opline->op2.var = NUM_VAR(cv_map[VAR_NUM(opline->op2.var)]);
78+
} else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
79+
opline->op2.var -= sizeof(zval) * tmp_offset;
80+
}
81+
if (opline->result_type == IS_CV) {
82+
opline->result.var = NUM_VAR(cv_map[VAR_NUM(opline->result.var)]);
83+
} else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
84+
opline->result.var -= sizeof(zval) * tmp_offset;
85+
}
86+
}
87+
88+
/* Update TMP references in live ranges */
89+
if (op_array->live_range) {
90+
for (i = 0; i < op_array->last_live_range; i++) {
91+
op_array->live_range[i].var -= sizeof(zval) * tmp_offset;
92+
}
93+
}
94+
95+
/* Update CV name table */
96+
{
97+
zend_string **names = safe_emalloc(sizeof(zend_string *), num_cvs, 0);
98+
for (i = 0; i < op_array->last_var; i++) {
99+
if (cv_map[i] != (uint32_t) -1) {
100+
names[cv_map[i]] = op_array->vars[i];
101+
} else {
102+
zend_string_release(op_array->vars[i]);
103+
}
104+
}
105+
efree(op_array->vars);
106+
op_array->vars = names;
107+
}
108+
109+
op_array->last_var = num_cvs;
110+
111+
free_alloca(cv_map, use_heap2);
112+
}

0 commit comments

Comments
 (0)