/src/php-src/Zend/Optimizer/zend_ssa.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine, SSA - Static Single Assignment Form | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright (c) 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 | | | https://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: Dmitry Stogov <dmitry@php.net> | |
16 | | +----------------------------------------------------------------------+ |
17 | | */ |
18 | | |
19 | | #ifndef ZEND_SSA_H |
20 | | #define ZEND_SSA_H |
21 | | |
22 | | #include "zend_optimizer.h" |
23 | | #include "zend_cfg.h" |
24 | | |
25 | | typedef struct _zend_ssa_range { |
26 | | zend_long min; |
27 | | zend_long max; |
28 | | bool underflow; |
29 | | bool overflow; |
30 | | } zend_ssa_range; |
31 | | |
32 | | typedef enum _zend_ssa_negative_lat { |
33 | | NEG_NONE = 0, |
34 | | NEG_INIT = 1, |
35 | | NEG_INVARIANT = 2, |
36 | | NEG_USE_LT = 3, |
37 | | NEG_USE_GT = 4, |
38 | | NEG_UNKNOWN = 5 |
39 | | } zend_ssa_negative_lat; |
40 | | |
41 | | /* Special kind of SSA Phi function used in eSSA */ |
42 | | typedef struct _zend_ssa_range_constraint { |
43 | | zend_ssa_range range; /* simple range constraint */ |
44 | | int min_var; |
45 | | int max_var; |
46 | | int min_ssa_var; /* ((min_var>0) ? MIN(ssa_var) : 0) + range.min */ |
47 | | int max_ssa_var; /* ((max_var>0) ? MAX(ssa_var) : 0) + range.max */ |
48 | | zend_ssa_negative_lat negative; |
49 | | } zend_ssa_range_constraint; |
50 | | |
51 | | typedef struct _zend_ssa_type_constraint { |
52 | | uint32_t type_mask; /* Type mask to intersect with */ |
53 | | zend_class_entry *ce; /* Class entry for instanceof constraints */ |
54 | | } zend_ssa_type_constraint; |
55 | | |
56 | | typedef union _zend_ssa_pi_constraint { |
57 | | zend_ssa_range_constraint range; |
58 | | zend_ssa_type_constraint type; |
59 | | } zend_ssa_pi_constraint; |
60 | | |
61 | | /* SSA Phi - ssa_var = Phi(source0, source1, ...sourceN) */ |
62 | | typedef struct _zend_ssa_phi zend_ssa_phi; |
63 | | struct _zend_ssa_phi { |
64 | | zend_ssa_phi *next; /* next Phi in the same BB */ |
65 | | int pi; /* if >= 0 this is actually a e-SSA Pi */ |
66 | | zend_ssa_pi_constraint constraint; /* e-SSA Pi constraint */ |
67 | | int var; /* Original CV, VAR or TMP variable index */ |
68 | | int ssa_var; /* SSA variable index */ |
69 | | int block; /* current BB index */ |
70 | | bool has_range_constraint; |
71 | | zend_ssa_phi **use_chains; |
72 | | zend_ssa_phi *sym_use_chain; |
73 | | int *sources; /* Array of SSA IDs that produce this var. |
74 | | As many as this block has |
75 | | predecessors. */ |
76 | | }; |
77 | | |
78 | | typedef struct _zend_ssa_block { |
79 | | zend_ssa_phi *phis; |
80 | | } zend_ssa_block; |
81 | | |
82 | | typedef struct _zend_ssa_op { |
83 | | int op1_use; |
84 | | int op2_use; |
85 | | int result_use; |
86 | | int op1_def; |
87 | | int op2_def; |
88 | | int result_def; |
89 | | int op1_use_chain; |
90 | | int op2_use_chain; |
91 | | int res_use_chain; |
92 | | } zend_ssa_op; |
93 | | |
94 | | typedef enum _zend_ssa_alias_kind { |
95 | | NO_ALIAS, |
96 | | SYMTABLE_ALIAS, |
97 | | HTTP_RESPONSE_HEADER_ALIAS |
98 | | } zend_ssa_alias_kind; |
99 | | |
100 | | typedef enum _zend_ssa_escape_state { |
101 | | ESCAPE_STATE_UNKNOWN, |
102 | | ESCAPE_STATE_NO_ESCAPE, |
103 | | ESCAPE_STATE_FUNCTION_ESCAPE, |
104 | | ESCAPE_STATE_GLOBAL_ESCAPE |
105 | | } zend_ssa_escape_state; |
106 | | |
107 | | typedef struct _zend_ssa_var { |
108 | | int var; /* original var number; op.var for CVs and following numbers for VARs and TMP_VARs */ |
109 | | int scc; /* strongly connected component */ |
110 | | int definition; /* opcode that defines this value */ |
111 | | int use_chain; /* uses of this value, linked through opN_use_chain */ |
112 | | zend_ssa_phi *definition_phi; /* phi that defines this value */ |
113 | | zend_ssa_phi *phi_use_chain; /* uses of this value in Phi, linked through use_chain */ |
114 | | zend_ssa_phi *sym_use_chain; /* uses of this value in Pi constraints */ |
115 | | bool no_val : 1; /* value doesn't matter (used as op1 in ZEND_ASSIGN) */ |
116 | | bool scc_entry : 1; |
117 | | unsigned int alias : 2; /* value may be changed indirectly */ |
118 | | unsigned int escape_state : 2; |
119 | | } zend_ssa_var; |
120 | | |
121 | | typedef struct _zend_ssa_var_info { |
122 | | uint32_t type; /* inferred type (see zend_inference.h) */ |
123 | | bool has_range : 1; |
124 | | bool is_instanceof : 1; /* 0 - class == "ce", 1 - may be child of "ce" */ |
125 | | bool recursive : 1; |
126 | | bool use_as_double : 1; |
127 | | bool delayed_fetch_this : 1; |
128 | | bool avoid_refcounting : 1; |
129 | | bool guarded_reference : 1; |
130 | | bool indirect_reference : 1; /* IS_INDIRECT returned by FETCH_DIM_W/FETCH_OBJ_W */ |
131 | | zend_ssa_range range; |
132 | | zend_class_entry *ce; |
133 | | } zend_ssa_var_info; |
134 | | |
135 | | typedef struct _zend_ssa { |
136 | | zend_cfg cfg; /* control flow graph */ |
137 | | int vars_count; /* number of SSA variables */ |
138 | | int sccs; /* number of SCCs */ |
139 | | zend_ssa_block *blocks; /* array of SSA blocks */ |
140 | | zend_ssa_op *ops; /* array of SSA instructions */ |
141 | | zend_ssa_var *vars; /* use/def chain of SSA variables */ |
142 | | zend_ssa_var_info *var_info; |
143 | | } zend_ssa; |
144 | | |
145 | | BEGIN_EXTERN_C() |
146 | | |
147 | | ZEND_API zend_result zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa); |
148 | | ZEND_API void zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa); |
149 | | ZEND_API int zend_ssa_rename_op(const zend_op_array *op_array, const zend_op *opline, uint32_t k, uint32_t build_flags, int ssa_vars_count, zend_ssa_op *ssa_ops, int *var); |
150 | | void zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var); |
151 | | void zend_ssa_replace_use_chain(zend_ssa *ssa, int op, int new_op, int var); |
152 | | |
153 | | void zend_ssa_remove_predecessor(zend_ssa *ssa, int from, int to); |
154 | | void zend_ssa_remove_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op); |
155 | | void zend_ssa_remove_instr(zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op); |
156 | | void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi); |
157 | | void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num); |
158 | | void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int b); |
159 | | void zend_ssa_rename_var_uses(zend_ssa *ssa, int old_var, int new_var, bool update_types); |
160 | | void zend_ssa_remove_block_from_cfg(zend_ssa *ssa, int b); |
161 | | |
162 | | static zend_always_inline void _zend_ssa_remove_def(zend_ssa_var *var) |
163 | 6.49k | { |
164 | 6.49k | ZEND_ASSERT(var->definition >= 0); |
165 | 6.49k | ZEND_ASSERT(var->use_chain < 0); |
166 | 6.49k | ZEND_ASSERT(!var->phi_use_chain); |
167 | 6.49k | var->definition = -1; |
168 | 6.49k | } Unexecuted instantiation: block_pass.c:_zend_ssa_remove_def Unexecuted instantiation: compact_literals.c:_zend_ssa_remove_def Unexecuted instantiation: compact_vars.c:_zend_ssa_remove_def Unexecuted instantiation: dce.c:_zend_ssa_remove_def dfa_pass.c:_zend_ssa_remove_def Line | Count | Source | 163 | 1.24k | { | 164 | 1.24k | ZEND_ASSERT(var->definition >= 0); | 165 | 1.24k | ZEND_ASSERT(var->use_chain < 0); | 166 | 1.24k | ZEND_ASSERT(!var->phi_use_chain); | 167 | 1.24k | var->definition = -1; | 168 | 1.24k | } |
Unexecuted instantiation: escape_analysis.c:_zend_ssa_remove_def Unexecuted instantiation: nop_removal.c:_zend_ssa_remove_def Unexecuted instantiation: optimize_func_calls.c:_zend_ssa_remove_def Unexecuted instantiation: optimize_temp_vars_5.c:_zend_ssa_remove_def Unexecuted instantiation: pass1.c:_zend_ssa_remove_def Unexecuted instantiation: pass3.c:_zend_ssa_remove_def sccp.c:_zend_ssa_remove_def Line | Count | Source | 163 | 3.19k | { | 164 | 3.19k | ZEND_ASSERT(var->definition >= 0); | 165 | 3.19k | ZEND_ASSERT(var->use_chain < 0); | 166 | 3.19k | ZEND_ASSERT(!var->phi_use_chain); | 167 | 3.19k | var->definition = -1; | 168 | 3.19k | } |
Unexecuted instantiation: scdf.c:_zend_ssa_remove_def Unexecuted instantiation: zend_call_graph.c:_zend_ssa_remove_def Unexecuted instantiation: zend_cfg.c:_zend_ssa_remove_def Unexecuted instantiation: zend_dump.c:_zend_ssa_remove_def Unexecuted instantiation: zend_func_info.c:_zend_ssa_remove_def Unexecuted instantiation: zend_inference.c:_zend_ssa_remove_def Unexecuted instantiation: zend_optimizer.c:_zend_ssa_remove_def zend_ssa.c:_zend_ssa_remove_def Line | Count | Source | 163 | 2.05k | { | 164 | 2.05k | ZEND_ASSERT(var->definition >= 0); | 165 | 2.05k | ZEND_ASSERT(var->use_chain < 0); | 166 | 2.05k | ZEND_ASSERT(!var->phi_use_chain); | 167 | 2.05k | var->definition = -1; | 168 | 2.05k | } |
Unexecuted instantiation: zend_execute.c:_zend_ssa_remove_def |
169 | | |
170 | | static zend_always_inline void zend_ssa_remove_result_def(zend_ssa *ssa, zend_ssa_op *ssa_op) |
171 | 5.78k | { |
172 | 5.78k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; |
173 | 5.78k | _zend_ssa_remove_def(var); |
174 | 5.78k | ssa_op->result_def = -1; |
175 | 5.78k | } Unexecuted instantiation: block_pass.c:zend_ssa_remove_result_def Unexecuted instantiation: compact_literals.c:zend_ssa_remove_result_def Unexecuted instantiation: compact_vars.c:zend_ssa_remove_result_def Unexecuted instantiation: dce.c:zend_ssa_remove_result_def dfa_pass.c:zend_ssa_remove_result_def Line | Count | Source | 171 | 1.24k | { | 172 | 1.24k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 173 | 1.24k | _zend_ssa_remove_def(var); | 174 | 1.24k | ssa_op->result_def = -1; | 175 | 1.24k | } |
Unexecuted instantiation: escape_analysis.c:zend_ssa_remove_result_def Unexecuted instantiation: nop_removal.c:zend_ssa_remove_result_def Unexecuted instantiation: optimize_func_calls.c:zend_ssa_remove_result_def Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_remove_result_def Unexecuted instantiation: pass1.c:zend_ssa_remove_result_def Unexecuted instantiation: pass3.c:zend_ssa_remove_result_def sccp.c:zend_ssa_remove_result_def Line | Count | Source | 171 | 3.12k | { | 172 | 3.12k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 173 | 3.12k | _zend_ssa_remove_def(var); | 174 | 3.12k | ssa_op->result_def = -1; | 175 | 3.12k | } |
Unexecuted instantiation: scdf.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_call_graph.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_cfg.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_dump.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_func_info.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_inference.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_optimizer.c:zend_ssa_remove_result_def zend_ssa.c:zend_ssa_remove_result_def Line | Count | Source | 171 | 1.41k | { | 172 | 1.41k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 173 | 1.41k | _zend_ssa_remove_def(var); | 174 | 1.41k | ssa_op->result_def = -1; | 175 | 1.41k | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_remove_result_def |
176 | | |
177 | | static zend_always_inline void zend_ssa_remove_op1_def(zend_ssa *ssa, zend_ssa_op *ssa_op) |
178 | 691 | { |
179 | 691 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; |
180 | 691 | _zend_ssa_remove_def(var); |
181 | 691 | ssa_op->op1_def = -1; |
182 | 691 | } Unexecuted instantiation: block_pass.c:zend_ssa_remove_op1_def Unexecuted instantiation: compact_literals.c:zend_ssa_remove_op1_def Unexecuted instantiation: compact_vars.c:zend_ssa_remove_op1_def Unexecuted instantiation: dce.c:zend_ssa_remove_op1_def Unexecuted instantiation: dfa_pass.c:zend_ssa_remove_op1_def Unexecuted instantiation: escape_analysis.c:zend_ssa_remove_op1_def Unexecuted instantiation: nop_removal.c:zend_ssa_remove_op1_def Unexecuted instantiation: optimize_func_calls.c:zend_ssa_remove_op1_def Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_remove_op1_def Unexecuted instantiation: pass1.c:zend_ssa_remove_op1_def Unexecuted instantiation: pass3.c:zend_ssa_remove_op1_def sccp.c:zend_ssa_remove_op1_def Line | Count | Source | 178 | 72 | { | 179 | 72 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; | 180 | 72 | _zend_ssa_remove_def(var); | 181 | 72 | ssa_op->op1_def = -1; | 182 | 72 | } |
Unexecuted instantiation: scdf.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_call_graph.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_cfg.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_dump.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_func_info.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_inference.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_optimizer.c:zend_ssa_remove_op1_def zend_ssa.c:zend_ssa_remove_op1_def Line | Count | Source | 178 | 619 | { | 179 | 619 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; | 180 | 619 | _zend_ssa_remove_def(var); | 181 | 619 | ssa_op->op1_def = -1; | 182 | 619 | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_remove_op1_def |
183 | | |
184 | | static zend_always_inline void zend_ssa_remove_op2_def(zend_ssa *ssa, zend_ssa_op *ssa_op) |
185 | 14 | { |
186 | 14 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; |
187 | 14 | _zend_ssa_remove_def(var); |
188 | 14 | ssa_op->op2_def = -1; |
189 | 14 | } Unexecuted instantiation: block_pass.c:zend_ssa_remove_op2_def Unexecuted instantiation: compact_literals.c:zend_ssa_remove_op2_def Unexecuted instantiation: compact_vars.c:zend_ssa_remove_op2_def Unexecuted instantiation: dce.c:zend_ssa_remove_op2_def Unexecuted instantiation: dfa_pass.c:zend_ssa_remove_op2_def Unexecuted instantiation: escape_analysis.c:zend_ssa_remove_op2_def Unexecuted instantiation: nop_removal.c:zend_ssa_remove_op2_def Unexecuted instantiation: optimize_func_calls.c:zend_ssa_remove_op2_def Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_remove_op2_def Unexecuted instantiation: pass1.c:zend_ssa_remove_op2_def Unexecuted instantiation: pass3.c:zend_ssa_remove_op2_def Unexecuted instantiation: sccp.c:zend_ssa_remove_op2_def Unexecuted instantiation: scdf.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_call_graph.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_cfg.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_dump.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_func_info.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_inference.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_optimizer.c:zend_ssa_remove_op2_def zend_ssa.c:zend_ssa_remove_op2_def Line | Count | Source | 185 | 14 | { | 186 | 14 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; | 187 | 14 | _zend_ssa_remove_def(var); | 188 | 14 | ssa_op->op2_def = -1; | 189 | 14 | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_remove_op2_def |
190 | | |
191 | | END_EXTERN_C() |
192 | | |
193 | | static zend_always_inline int zend_ssa_next_use(const zend_ssa_op *ssa_op, int var, int use) |
194 | 39.5M | { |
195 | 39.5M | ssa_op += use; |
196 | 39.5M | if (ssa_op->op1_use == var) { |
197 | 29.4M | return ssa_op->op1_use_chain; |
198 | 29.4M | } else if (ssa_op->op2_use == var) { |
199 | 9.62M | return ssa_op->op2_use_chain; |
200 | 9.62M | } else { |
201 | 447k | return ssa_op->res_use_chain; |
202 | 447k | } |
203 | 39.5M | } Unexecuted instantiation: block_pass.c:zend_ssa_next_use Unexecuted instantiation: compact_literals.c:zend_ssa_next_use Unexecuted instantiation: compact_vars.c:zend_ssa_next_use Unexecuted instantiation: dce.c:zend_ssa_next_use dfa_pass.c:zend_ssa_next_use Line | Count | Source | 194 | 34.8M | { | 195 | 34.8M | ssa_op += use; | 196 | 34.8M | if (ssa_op->op1_use == var) { | 197 | 25.9M | return ssa_op->op1_use_chain; | 198 | 25.9M | } else if (ssa_op->op2_use == var) { | 199 | 8.45M | return ssa_op->op2_use_chain; | 200 | 8.45M | } else { | 201 | 352k | return ssa_op->res_use_chain; | 202 | 352k | } | 203 | 34.8M | } |
escape_analysis.c:zend_ssa_next_use Line | Count | Source | 194 | 29.6k | { | 195 | 29.6k | ssa_op += use; | 196 | 29.6k | if (ssa_op->op1_use == var) { | 197 | 17.3k | return ssa_op->op1_use_chain; | 198 | 17.3k | } else if (ssa_op->op2_use == var) { | 199 | 4.51k | return ssa_op->op2_use_chain; | 200 | 7.83k | } else { | 201 | 7.83k | return ssa_op->res_use_chain; | 202 | 7.83k | } | 203 | 29.6k | } |
Unexecuted instantiation: nop_removal.c:zend_ssa_next_use Unexecuted instantiation: optimize_func_calls.c:zend_ssa_next_use Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_next_use Unexecuted instantiation: pass1.c:zend_ssa_next_use Unexecuted instantiation: pass3.c:zend_ssa_next_use Line | Count | Source | 194 | 1.04M | { | 195 | 1.04M | ssa_op += use; | 196 | 1.04M | if (ssa_op->op1_use == var) { | 197 | 782k | return ssa_op->op1_use_chain; | 198 | 782k | } else if (ssa_op->op2_use == var) { | 199 | 232k | return ssa_op->op2_use_chain; | 200 | 232k | } else { | 201 | 34.6k | return ssa_op->res_use_chain; | 202 | 34.6k | } | 203 | 1.04M | } |
Unexecuted instantiation: scdf.c:zend_ssa_next_use Unexecuted instantiation: zend_call_graph.c:zend_ssa_next_use Unexecuted instantiation: zend_cfg.c:zend_ssa_next_use Unexecuted instantiation: zend_dump.c:zend_ssa_next_use Unexecuted instantiation: zend_func_info.c:zend_ssa_next_use zend_inference.c:zend_ssa_next_use Line | Count | Source | 194 | 3.57M | { | 195 | 3.57M | ssa_op += use; | 196 | 3.57M | if (ssa_op->op1_use == var) { | 197 | 2.60M | return ssa_op->op1_use_chain; | 198 | 2.60M | } else if (ssa_op->op2_use == var) { | 199 | 916k | return ssa_op->op2_use_chain; | 200 | 916k | } else { | 201 | 52.7k | return ssa_op->res_use_chain; | 202 | 52.7k | } | 203 | 3.57M | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_next_use zend_ssa.c:zend_ssa_next_use Line | Count | Source | 194 | 39.5k | { | 195 | 39.5k | ssa_op += use; | 196 | 39.5k | if (ssa_op->op1_use == var) { | 197 | 31.5k | return ssa_op->op1_use_chain; | 198 | 31.5k | } else if (ssa_op->op2_use == var) { | 199 | 7.74k | return ssa_op->op2_use_chain; | 200 | 7.74k | } else { | 201 | 246 | return ssa_op->res_use_chain; | 202 | 246 | } | 203 | 39.5k | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_next_use |
204 | | |
205 | | static zend_always_inline zend_ssa_phi* zend_ssa_next_use_phi(const zend_ssa *ssa, int var, const zend_ssa_phi *p) |
206 | 7.70M | { |
207 | 7.70M | if (p->pi >= 0) { |
208 | 1.25M | return p->use_chains[0]; |
209 | 6.44M | } else { |
210 | 6.44M | int j; |
211 | 9.67M | for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { |
212 | 9.67M | if (p->sources[j] == var) { |
213 | 6.44M | return p->use_chains[j]; |
214 | 6.44M | } |
215 | 9.67M | } |
216 | 6.44M | } |
217 | 4 | return NULL; |
218 | 7.70M | } Unexecuted instantiation: block_pass.c:zend_ssa_next_use_phi Unexecuted instantiation: compact_literals.c:zend_ssa_next_use_phi Unexecuted instantiation: compact_vars.c:zend_ssa_next_use_phi Unexecuted instantiation: dce.c:zend_ssa_next_use_phi dfa_pass.c:zend_ssa_next_use_phi Line | Count | Source | 206 | 6.30M | { | 207 | 6.30M | if (p->pi >= 0) { | 208 | 926k | return p->use_chains[0]; | 209 | 5.37M | } else { | 210 | 5.37M | int j; | 211 | 8.04M | for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 212 | 8.04M | if (p->sources[j] == var) { | 213 | 5.37M | return p->use_chains[j]; | 214 | 5.37M | } | 215 | 8.04M | } | 216 | 5.37M | } | 217 | 0 | return NULL; | 218 | 6.30M | } |
Unexecuted instantiation: escape_analysis.c:zend_ssa_next_use_phi Unexecuted instantiation: nop_removal.c:zend_ssa_next_use_phi Unexecuted instantiation: optimize_func_calls.c:zend_ssa_next_use_phi Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_next_use_phi Unexecuted instantiation: pass1.c:zend_ssa_next_use_phi Unexecuted instantiation: pass3.c:zend_ssa_next_use_phi sccp.c:zend_ssa_next_use_phi Line | Count | Source | 206 | 287k | { | 207 | 287k | if (p->pi >= 0) { | 208 | 55.5k | return p->use_chains[0]; | 209 | 231k | } else { | 210 | 231k | int j; | 211 | 360k | for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 212 | 360k | if (p->sources[j] == var) { | 213 | 231k | return p->use_chains[j]; | 214 | 231k | } | 215 | 360k | } | 216 | 231k | } | 217 | 0 | return NULL; | 218 | 287k | } |
Unexecuted instantiation: scdf.c:zend_ssa_next_use_phi Unexecuted instantiation: zend_call_graph.c:zend_ssa_next_use_phi Unexecuted instantiation: zend_cfg.c:zend_ssa_next_use_phi Unexecuted instantiation: zend_dump.c:zend_ssa_next_use_phi Unexecuted instantiation: zend_func_info.c:zend_ssa_next_use_phi zend_inference.c:zend_ssa_next_use_phi Line | Count | Source | 206 | 1.04M | { | 207 | 1.04M | if (p->pi >= 0) { | 208 | 224k | return p->use_chains[0]; | 209 | 816k | } else { | 210 | 816k | int j; | 211 | 1.24M | for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 212 | 1.24M | if (p->sources[j] == var) { | 213 | 816k | return p->use_chains[j]; | 214 | 816k | } | 215 | 1.24M | } | 216 | 816k | } | 217 | 0 | return NULL; | 218 | 1.04M | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_next_use_phi zend_ssa.c:zend_ssa_next_use_phi Line | Count | Source | 206 | 67.6k | { | 207 | 67.6k | if (p->pi >= 0) { | 208 | 49.6k | return p->use_chains[0]; | 209 | 49.6k | } else { | 210 | 18.0k | int j; | 211 | 26.5k | for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 212 | 26.5k | if (p->sources[j] == var) { | 213 | 18.0k | return p->use_chains[j]; | 214 | 18.0k | } | 215 | 26.5k | } | 216 | 18.0k | } | 217 | 4 | return NULL; | 218 | 67.6k | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_next_use_phi |
219 | | |
220 | | static zend_always_inline bool zend_ssa_is_no_val_use(const zend_op *opline, const zend_ssa_op *ssa_op, int var) |
221 | 1.39M | { |
222 | 1.39M | if (opline->opcode == ZEND_ASSIGN |
223 | 1.39M | || opline->opcode == ZEND_UNSET_CV |
224 | 1.39M | || opline->opcode == ZEND_BIND_GLOBAL |
225 | 1.39M | || opline->opcode == ZEND_BIND_STATIC) { |
226 | 136k | return ssa_op->op1_use == var && ssa_op->op2_use != var; |
227 | 136k | } |
228 | 1.25M | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { |
229 | 8.36k | return ssa_op->op2_use == var && ssa_op->op1_use != var; |
230 | 8.36k | } |
231 | 1.25M | if (ssa_op->result_use == var |
232 | 1.25M | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT |
233 | 1.25M | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { |
234 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; |
235 | 0 | } |
236 | 1.25M | return 0; |
237 | 1.25M | } Unexecuted instantiation: block_pass.c:zend_ssa_is_no_val_use Unexecuted instantiation: compact_literals.c:zend_ssa_is_no_val_use Unexecuted instantiation: compact_vars.c:zend_ssa_is_no_val_use dce.c:zend_ssa_is_no_val_use Line | Count | Source | 221 | 1.05M | { | 222 | 1.05M | if (opline->opcode == ZEND_ASSIGN | 223 | 1.05M | || opline->opcode == ZEND_UNSET_CV | 224 | 1.05M | || opline->opcode == ZEND_BIND_GLOBAL | 225 | 1.05M | || opline->opcode == ZEND_BIND_STATIC) { | 226 | 98.7k | return ssa_op->op1_use == var && ssa_op->op2_use != var; | 227 | 98.7k | } | 228 | 956k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { | 229 | 6.28k | return ssa_op->op2_use == var && ssa_op->op1_use != var; | 230 | 6.28k | } | 231 | 950k | if (ssa_op->result_use == var | 232 | 950k | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT | 233 | 950k | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { | 234 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; | 235 | 0 | } | 236 | 950k | return 0; | 237 | 950k | } |
Unexecuted instantiation: dfa_pass.c:zend_ssa_is_no_val_use Unexecuted instantiation: escape_analysis.c:zend_ssa_is_no_val_use Unexecuted instantiation: nop_removal.c:zend_ssa_is_no_val_use Unexecuted instantiation: optimize_func_calls.c:zend_ssa_is_no_val_use Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_is_no_val_use Unexecuted instantiation: pass1.c:zend_ssa_is_no_val_use Unexecuted instantiation: pass3.c:zend_ssa_is_no_val_use Unexecuted instantiation: sccp.c:zend_ssa_is_no_val_use Unexecuted instantiation: scdf.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_call_graph.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_cfg.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_dump.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_func_info.c:zend_ssa_is_no_val_use zend_inference.c:zend_ssa_is_no_val_use Line | Count | Source | 221 | 340k | { | 222 | 340k | if (opline->opcode == ZEND_ASSIGN | 223 | 340k | || opline->opcode == ZEND_UNSET_CV | 224 | 340k | || opline->opcode == ZEND_BIND_GLOBAL | 225 | 340k | || opline->opcode == ZEND_BIND_STATIC) { | 226 | 38.0k | return ssa_op->op1_use == var && ssa_op->op2_use != var; | 227 | 38.0k | } | 228 | 301k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { | 229 | 2.08k | return ssa_op->op2_use == var && ssa_op->op1_use != var; | 230 | 2.08k | } | 231 | 299k | if (ssa_op->result_use == var | 232 | 299k | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT | 233 | 299k | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { | 234 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; | 235 | 0 | } | 236 | 299k | return 0; | 237 | 299k | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_ssa.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_execute.c:zend_ssa_is_no_val_use |
238 | | |
239 | 12.8k | static zend_always_inline void zend_ssa_rename_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) { |
240 | | /* Rename def to use if possible. Mark variable as not defined otherwise. */ |
241 | 12.8k | if (ssa_op->op1_def >= 0) { |
242 | 4.74k | if (ssa_op->op1_use >= 0) { |
243 | 4.74k | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, 1); |
244 | 4.74k | } |
245 | 4.74k | ssa->vars[ssa_op->op1_def].definition = -1; |
246 | 4.74k | ssa_op->op1_def = -1; |
247 | 4.74k | } |
248 | 12.8k | if (ssa_op->op2_def >= 0) { |
249 | 0 | if (ssa_op->op2_use >= 0) { |
250 | 0 | zend_ssa_rename_var_uses(ssa, ssa_op->op2_def, ssa_op->op2_use, 1); |
251 | 0 | } |
252 | 0 | ssa->vars[ssa_op->op2_def].definition = -1; |
253 | 0 | ssa_op->op2_def = -1; |
254 | 0 | } |
255 | 12.8k | if (ssa_op->result_def >= 0) { |
256 | 3.78k | if (ssa_op->result_use >= 0) { |
257 | 163 | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, 1); |
258 | 163 | } |
259 | 3.78k | ssa->vars[ssa_op->result_def].definition = -1; |
260 | 3.78k | ssa_op->result_def = -1; |
261 | 3.78k | } |
262 | 12.8k | } Unexecuted instantiation: block_pass.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: compact_literals.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: compact_vars.c:zend_ssa_rename_defs_of_instr dce.c:zend_ssa_rename_defs_of_instr Line | Count | Source | 239 | 12.8k | static zend_always_inline void zend_ssa_rename_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) { | 240 | | /* Rename def to use if possible. Mark variable as not defined otherwise. */ | 241 | 12.8k | if (ssa_op->op1_def >= 0) { | 242 | 4.74k | if (ssa_op->op1_use >= 0) { | 243 | 4.74k | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, 1); | 244 | 4.74k | } | 245 | 4.74k | ssa->vars[ssa_op->op1_def].definition = -1; | 246 | 4.74k | ssa_op->op1_def = -1; | 247 | 4.74k | } | 248 | 12.8k | if (ssa_op->op2_def >= 0) { | 249 | 0 | if (ssa_op->op2_use >= 0) { | 250 | 0 | zend_ssa_rename_var_uses(ssa, ssa_op->op2_def, ssa_op->op2_use, 1); | 251 | 0 | } | 252 | 0 | ssa->vars[ssa_op->op2_def].definition = -1; | 253 | 0 | ssa_op->op2_def = -1; | 254 | 0 | } | 255 | 12.8k | if (ssa_op->result_def >= 0) { | 256 | 3.78k | if (ssa_op->result_use >= 0) { | 257 | 163 | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, 1); | 258 | 163 | } | 259 | 3.78k | ssa->vars[ssa_op->result_def].definition = -1; | 260 | 3.78k | ssa_op->result_def = -1; | 261 | 3.78k | } | 262 | 12.8k | } |
Unexecuted instantiation: dfa_pass.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: escape_analysis.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: nop_removal.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: optimize_func_calls.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: optimize_temp_vars_5.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: pass1.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: pass3.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: sccp.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: scdf.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_call_graph.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_cfg.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_dump.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_func_info.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_inference.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_optimizer.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_ssa.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_execute.c:zend_ssa_rename_defs_of_instr |
263 | | |
264 | | #define NUM_PHI_SOURCES(phi) \ |
265 | 2.84M | ((phi)->pi >= 0 ? 1 : (ssa->cfg.blocks[(phi)->block].predecessors_count)) |
266 | | |
267 | | /* FOREACH_USE and FOREACH_PHI_USE explicitly support "continue" |
268 | | * and changing the use chain of the current element */ |
269 | 12.9M | #define FOREACH_USE(var, use) do { \ |
270 | 12.9M | int _var_num = (var) - ssa->vars, next; \ |
271 | 32.6M | for (use = (var)->use_chain; use >= 0; use = next) { \ |
272 | 25.4M | next = zend_ssa_next_use(ssa->ops, _var_num, use); |
273 | | #define FOREACH_USE_END() \ |
274 | 25.4M | } \ |
275 | 12.9M | } while (0) |
276 | | |
277 | 8.57M | #define FOREACH_PHI_USE(var, phi) do { \ |
278 | 8.57M | int _var_num = (var) - ssa->vars; \ |
279 | 8.57M | zend_ssa_phi *next_phi; \ |
280 | 10.7M | for (phi = (var)->phi_use_chain; phi; phi = next_phi) { \ |
281 | 3.72M | next_phi = zend_ssa_next_use_phi(ssa, _var_num, phi); |
282 | | #define FOREACH_PHI_USE_END() \ |
283 | 3.72M | } \ |
284 | 8.57M | } while (0) |
285 | | |
286 | 1.91M | #define FOREACH_PHI_SOURCE(phi, source) do { \ |
287 | 1.91M | zend_ssa_phi *_phi = (phi); \ |
288 | 1.91M | int _i, _end = NUM_PHI_SOURCES(phi); \ |
289 | 3.08M | for (_i = 0; _i < _end; _i++) { \ |
290 | 2.86M | ZEND_ASSERT(_phi->sources[_i] >= 0); \ |
291 | 2.86M | source = _phi->sources[_i]; |
292 | | #define FOREACH_PHI_SOURCE_END() \ |
293 | 2.86M | } \ |
294 | 1.91M | } while (0) |
295 | | |
296 | 525k | #define FOREACH_PHI(phi) do { \ |
297 | 525k | int _i; \ |
298 | 2.09M | for (_i = 0; _i < ssa->cfg.blocks_count; _i++) { \ |
299 | 1.57M | phi = ssa->blocks[_i].phis; \ |
300 | 2.84M | for (; phi; phi = phi->next) { |
301 | | #define FOREACH_PHI_END() \ |
302 | 1.27M | } \ |
303 | 1.57M | } \ |
304 | 525k | } while (0) |
305 | | |
306 | 376k | #define FOREACH_BLOCK(block) do { \ |
307 | 376k | int _i; \ |
308 | 1.51M | for (_i = 0; _i < ssa->cfg.blocks_count; _i++) { \ |
309 | 1.13M | (block) = &ssa->cfg.blocks[_i]; \ |
310 | 1.13M | if (!((block)->flags & ZEND_BB_REACHABLE)) { \ |
311 | 12.1k | continue; \ |
312 | 12.1k | } |
313 | | #define FOREACH_BLOCK_END() \ |
314 | 1.12M | } \ |
315 | 376k | } while (0) |
316 | | |
317 | | /* Does not support "break" */ |
318 | 376k | #define FOREACH_INSTR_NUM(i) do { \ |
319 | 376k | zend_basic_block *_block; \ |
320 | 1.13M | FOREACH_BLOCK(_block) { \ |
321 | 1.12M | uint32_t _end = _block->start + _block->len; \ |
322 | 8.09M | for ((i) = _block->start; (i) < _end; (i)++) { |
323 | | #define FOREACH_INSTR_NUM_END() \ |
324 | 6.96M | } \ |
325 | 1.12M | } FOREACH_BLOCK_END(); \ |
326 | 376k | } while (0) |
327 | | |
328 | | #endif /* ZEND_SSA_H */ |