/src/php-src/Zend/Optimizer/zend_ssa.h
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine, SSA - Static Single Assignment Form | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright © The PHP Group and Contributors. | |
6 | | +----------------------------------------------------------------------+ |
7 | | | This source file is subject to the Modified BSD License that is | |
8 | | | bundled with this package in the file LICENSE, and is available | |
9 | | | through the World Wide Web at <https://www.php.net/license/>. | |
10 | | | | |
11 | | | SPDX-License-Identifier: BSD-3-Clause | |
12 | | +----------------------------------------------------------------------+ |
13 | | | Authors: Dmitry Stogov <dmitry@php.net> | |
14 | | +----------------------------------------------------------------------+ |
15 | | */ |
16 | | |
17 | | #ifndef ZEND_SSA_H |
18 | | #define ZEND_SSA_H |
19 | | |
20 | | #include "zend_optimizer.h" |
21 | | #include "zend_cfg.h" |
22 | | |
23 | | typedef struct _zend_ssa_range { |
24 | | zend_long min; |
25 | | zend_long max; |
26 | | bool underflow; |
27 | | bool overflow; |
28 | | } zend_ssa_range; |
29 | | |
30 | | typedef enum _zend_ssa_negative_lat { |
31 | | NEG_NONE = 0, |
32 | | NEG_INIT = 1, |
33 | | NEG_INVARIANT = 2, |
34 | | NEG_USE_LT = 3, |
35 | | NEG_USE_GT = 4, |
36 | | NEG_UNKNOWN = 5 |
37 | | } zend_ssa_negative_lat; |
38 | | |
39 | | /* Special kind of SSA Phi function used in eSSA */ |
40 | | typedef struct _zend_ssa_range_constraint { |
41 | | zend_ssa_range range; /* simple range constraint */ |
42 | | int min_var; |
43 | | int max_var; |
44 | | int min_ssa_var; /* ((min_var>0) ? MIN(ssa_var) : 0) + range.min */ |
45 | | int max_ssa_var; /* ((max_var>0) ? MAX(ssa_var) : 0) + range.max */ |
46 | | zend_ssa_negative_lat negative; |
47 | | } zend_ssa_range_constraint; |
48 | | |
49 | | typedef struct _zend_ssa_type_constraint { |
50 | | uint32_t type_mask; /* Type mask to intersect with */ |
51 | | zend_class_entry *ce; /* Class entry for instanceof constraints */ |
52 | | } zend_ssa_type_constraint; |
53 | | |
54 | | typedef union _zend_ssa_pi_constraint { |
55 | | zend_ssa_range_constraint range; |
56 | | zend_ssa_type_constraint type; |
57 | | } zend_ssa_pi_constraint; |
58 | | |
59 | | /* SSA Phi - ssa_var = Phi(source0, source1, ...sourceN) */ |
60 | | typedef struct _zend_ssa_phi zend_ssa_phi; |
61 | | struct _zend_ssa_phi { |
62 | | zend_ssa_phi *next; /* next Phi in the same BB */ |
63 | | int pi; /* if >= 0 this is actually a e-SSA Pi */ |
64 | | zend_ssa_pi_constraint constraint; /* e-SSA Pi constraint */ |
65 | | int var; /* Original CV, VAR or TMP variable index */ |
66 | | int ssa_var; /* SSA variable index */ |
67 | | uint32_t block; /* current BB index */ |
68 | | bool has_range_constraint; |
69 | | zend_ssa_phi **use_chains; |
70 | | zend_ssa_phi *sym_use_chain; |
71 | | int *sources; /* Array of SSA IDs that produce this var. |
72 | | As many as this block has |
73 | | predecessors. */ |
74 | | }; |
75 | | |
76 | | typedef struct _zend_ssa_block { |
77 | | zend_ssa_phi *phis; |
78 | | } zend_ssa_block; |
79 | | |
80 | | typedef struct _zend_ssa_op { |
81 | | int op1_use; |
82 | | int op2_use; |
83 | | int result_use; |
84 | | int op1_def; |
85 | | int op2_def; |
86 | | int result_def; |
87 | | int op1_use_chain; |
88 | | int op2_use_chain; |
89 | | int res_use_chain; |
90 | | } zend_ssa_op; |
91 | | |
92 | | typedef enum _zend_ssa_alias_kind { |
93 | | NO_ALIAS, |
94 | | SYMTABLE_ALIAS, |
95 | | HTTP_RESPONSE_HEADER_ALIAS |
96 | | } zend_ssa_alias_kind; |
97 | | |
98 | | typedef enum _zend_ssa_escape_state { |
99 | | ESCAPE_STATE_UNKNOWN, |
100 | | ESCAPE_STATE_NO_ESCAPE, |
101 | | ESCAPE_STATE_FUNCTION_ESCAPE, |
102 | | ESCAPE_STATE_GLOBAL_ESCAPE |
103 | | } zend_ssa_escape_state; |
104 | | |
105 | | typedef struct _zend_ssa_var { |
106 | | int var; /* original var number; op.var for CVs and following numbers for VARs and TMP_VARs */ |
107 | | int scc; /* strongly connected component */ |
108 | | int definition; /* opcode that defines this value */ |
109 | | int use_chain; /* uses of this value, linked through opN_use_chain */ |
110 | | zend_ssa_phi *definition_phi; /* phi that defines this value */ |
111 | | zend_ssa_phi *phi_use_chain; /* uses of this value in Phi, linked through use_chain */ |
112 | | zend_ssa_phi *sym_use_chain; /* uses of this value in Pi constraints */ |
113 | | bool no_val : 1; /* value doesn't matter (used as op1 in ZEND_ASSIGN) */ |
114 | | bool scc_entry : 1; |
115 | | unsigned int alias : 2; /* value may be changed indirectly */ |
116 | | unsigned int escape_state : 2; |
117 | | } zend_ssa_var; |
118 | | |
119 | | typedef struct _zend_ssa_var_info { |
120 | | uint32_t type; /* inferred type (see zend_inference.h) */ |
121 | | bool has_range : 1; |
122 | | bool is_instanceof : 1; /* 0 - class == "ce", 1 - may be child of "ce" */ |
123 | | bool recursive : 1; |
124 | | bool use_as_double : 1; |
125 | | bool delayed_fetch_this : 1; |
126 | | bool avoid_refcounting : 1; |
127 | | bool guarded_reference : 1; |
128 | | bool indirect_reference : 1; /* IS_INDIRECT returned by FETCH_DIM_W/FETCH_OBJ_W */ |
129 | | zend_ssa_range range; |
130 | | zend_class_entry *ce; |
131 | | } zend_ssa_var_info; |
132 | | |
133 | | typedef struct _zend_ssa { |
134 | | zend_cfg cfg; /* control flow graph */ |
135 | | int vars_count; /* number of SSA variables */ |
136 | | int sccs; /* number of SCCs */ |
137 | | zend_ssa_block *blocks; /* array of SSA blocks */ |
138 | | zend_ssa_op *ops; /* array of SSA instructions */ |
139 | | zend_ssa_var *vars; /* use/def chain of SSA variables */ |
140 | | zend_ssa_var_info *var_info; |
141 | | } zend_ssa; |
142 | | |
143 | | BEGIN_EXTERN_C() |
144 | | |
145 | | 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); |
146 | | ZEND_API void zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa); |
147 | | 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); |
148 | | void zend_ssa_unlink_use_chain(const zend_ssa *ssa, int op, int var); |
149 | | void zend_ssa_replace_use_chain(const zend_ssa *ssa, int op, int new_op, int var); |
150 | | |
151 | | void zend_ssa_remove_predecessor(zend_ssa *ssa, int from, int to); |
152 | | void zend_ssa_remove_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op); |
153 | | void zend_ssa_remove_instr(const zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op); |
154 | | void zend_ssa_remove_phi(const zend_ssa *ssa, zend_ssa_phi *phi); |
155 | | void zend_ssa_remove_uses_of_var(const zend_ssa *ssa, int var_num); |
156 | | void zend_ssa_remove_block(const zend_op_array *op_array, zend_ssa *ssa, uint32_t b); |
157 | | void zend_ssa_rename_var_uses(zend_ssa *ssa, int old_var, int new_var, bool update_types); |
158 | | void zend_ssa_remove_block_from_cfg(zend_ssa *ssa, int b); |
159 | | |
160 | | static zend_always_inline void _zend_ssa_remove_def(zend_ssa_var *var) |
161 | 5.93k | { |
162 | 5.93k | ZEND_ASSERT(var->definition >= 0); |
163 | 5.93k | ZEND_ASSERT(var->use_chain < 0); |
164 | 5.93k | ZEND_ASSERT(!var->phi_use_chain); |
165 | 5.93k | var->definition = -1; |
166 | 5.93k | } Unexecuted instantiation: zend_persist.c:_zend_ssa_remove_def Unexecuted instantiation: ZendAccelerator.c:_zend_ssa_remove_def Unexecuted instantiation: zend_jit_vm_helpers.c:_zend_ssa_remove_def Unexecuted instantiation: zend_jit.c:_zend_ssa_remove_def 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 | 161 | 1.50k | { | 162 | 1.50k | ZEND_ASSERT(var->definition >= 0); | 163 | 1.50k | ZEND_ASSERT(var->use_chain < 0); | 164 | 1.50k | ZEND_ASSERT(!var->phi_use_chain); | 165 | 1.50k | var->definition = -1; | 166 | 1.50k | } |
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 | 161 | 1.83k | { | 162 | 1.83k | ZEND_ASSERT(var->definition >= 0); | 163 | 1.83k | ZEND_ASSERT(var->use_chain < 0); | 164 | 1.83k | ZEND_ASSERT(!var->phi_use_chain); | 165 | 1.83k | var->definition = -1; | 166 | 1.83k | } |
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 | 161 | 2.59k | { | 162 | 2.59k | ZEND_ASSERT(var->definition >= 0); | 163 | 2.59k | ZEND_ASSERT(var->use_chain < 0); | 164 | 2.59k | ZEND_ASSERT(!var->phi_use_chain); | 165 | 2.59k | var->definition = -1; | 166 | 2.59k | } |
Unexecuted instantiation: zend_execute.c:_zend_ssa_remove_def |
167 | | |
168 | | static zend_always_inline void zend_ssa_remove_result_def(zend_ssa *ssa, zend_ssa_op *ssa_op) |
169 | 5.66k | { |
170 | 5.66k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; |
171 | 5.66k | _zend_ssa_remove_def(var); |
172 | 5.66k | ssa_op->result_def = -1; |
173 | 5.66k | } Unexecuted instantiation: zend_persist.c:zend_ssa_remove_result_def Unexecuted instantiation: ZendAccelerator.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_remove_result_def Unexecuted instantiation: zend_jit.c:zend_ssa_remove_result_def 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 | 169 | 1.50k | { | 170 | 1.50k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 171 | 1.50k | _zend_ssa_remove_def(var); | 172 | 1.50k | ssa_op->result_def = -1; | 173 | 1.50k | } |
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 | 169 | 1.80k | { | 170 | 1.80k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 171 | 1.80k | _zend_ssa_remove_def(var); | 172 | 1.80k | ssa_op->result_def = -1; | 173 | 1.80k | } |
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 | 169 | 2.35k | { | 170 | 2.35k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 171 | 2.35k | _zend_ssa_remove_def(var); | 172 | 2.35k | ssa_op->result_def = -1; | 173 | 2.35k | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_remove_result_def |
174 | | |
175 | | static zend_always_inline void zend_ssa_remove_op1_def(zend_ssa *ssa, zend_ssa_op *ssa_op) |
176 | 255 | { |
177 | 255 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; |
178 | 255 | _zend_ssa_remove_def(var); |
179 | 255 | ssa_op->op1_def = -1; |
180 | 255 | } Unexecuted instantiation: zend_persist.c:zend_ssa_remove_op1_def Unexecuted instantiation: ZendAccelerator.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_remove_op1_def Unexecuted instantiation: zend_jit.c:zend_ssa_remove_op1_def 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 | 176 | 30 | { | 177 | 30 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; | 178 | 30 | _zend_ssa_remove_def(var); | 179 | 30 | ssa_op->op1_def = -1; | 180 | 30 | } |
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 | 176 | 225 | { | 177 | 225 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; | 178 | 225 | _zend_ssa_remove_def(var); | 179 | 225 | ssa_op->op1_def = -1; | 180 | 225 | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_remove_op1_def |
181 | | |
182 | | static zend_always_inline void zend_ssa_remove_op2_def(zend_ssa *ssa, zend_ssa_op *ssa_op) |
183 | 12 | { |
184 | 12 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; |
185 | 12 | _zend_ssa_remove_def(var); |
186 | 12 | ssa_op->op2_def = -1; |
187 | 12 | } Unexecuted instantiation: zend_persist.c:zend_ssa_remove_op2_def Unexecuted instantiation: ZendAccelerator.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_remove_op2_def Unexecuted instantiation: zend_jit.c:zend_ssa_remove_op2_def 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 | 183 | 12 | { | 184 | 12 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; | 185 | 12 | _zend_ssa_remove_def(var); | 186 | 12 | ssa_op->op2_def = -1; | 187 | 12 | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_remove_op2_def |
188 | | |
189 | | END_EXTERN_C() |
190 | | |
191 | | static zend_always_inline int zend_ssa_next_use(const zend_ssa_op *ssa_op, int var, int use) |
192 | 15.9M | { |
193 | 15.9M | ssa_op += use; |
194 | 15.9M | if (ssa_op->op1_use == var) { |
195 | 11.9M | return ssa_op->op1_use_chain; |
196 | 11.9M | } else if (ssa_op->op2_use == var) { |
197 | 3.68M | return ssa_op->op2_use_chain; |
198 | 3.68M | } else { |
199 | 244k | return ssa_op->res_use_chain; |
200 | 244k | } |
201 | 15.9M | } Unexecuted instantiation: zend_persist.c:zend_ssa_next_use Unexecuted instantiation: ZendAccelerator.c:zend_ssa_next_use Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_next_use Unexecuted instantiation: zend_jit.c:zend_ssa_next_use 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 | 192 | 13.5M | { | 193 | 13.5M | ssa_op += use; | 194 | 13.5M | if (ssa_op->op1_use == var) { | 195 | 10.2M | return ssa_op->op1_use_chain; | 196 | 10.2M | } else if (ssa_op->op2_use == var) { | 197 | 3.17M | return ssa_op->op2_use_chain; | 198 | 3.17M | } else { | 199 | 193k | return ssa_op->res_use_chain; | 200 | 193k | } | 201 | 13.5M | } |
escape_analysis.c:zend_ssa_next_use Line | Count | Source | 192 | 14.2k | { | 193 | 14.2k | ssa_op += use; | 194 | 14.2k | if (ssa_op->op1_use == var) { | 195 | 9.26k | return ssa_op->op1_use_chain; | 196 | 9.26k | } else if (ssa_op->op2_use == var) { | 197 | 2.51k | return ssa_op->op2_use_chain; | 198 | 2.51k | } else { | 199 | 2.49k | return ssa_op->res_use_chain; | 200 | 2.49k | } | 201 | 14.2k | } |
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 | 192 | 528k | { | 193 | 528k | ssa_op += use; | 194 | 528k | if (ssa_op->op1_use == var) { | 195 | 408k | return ssa_op->op1_use_chain; | 196 | 408k | } else if (ssa_op->op2_use == var) { | 197 | 100k | return ssa_op->op2_use_chain; | 198 | 100k | } else { | 199 | 19.0k | return ssa_op->res_use_chain; | 200 | 19.0k | } | 201 | 528k | } |
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 | 192 | 1.77M | { | 193 | 1.77M | ssa_op += use; | 194 | 1.77M | if (ssa_op->op1_use == var) { | 195 | 1.33M | return ssa_op->op1_use_chain; | 196 | 1.33M | } else if (ssa_op->op2_use == var) { | 197 | 404k | return ssa_op->op2_use_chain; | 198 | 404k | } else { | 199 | 28.9k | return ssa_op->res_use_chain; | 200 | 28.9k | } | 201 | 1.77M | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_next_use zend_ssa.c:zend_ssa_next_use Line | Count | Source | 192 | 27.3k | { | 193 | 27.3k | ssa_op += use; | 194 | 27.3k | if (ssa_op->op1_use == var) { | 195 | 23.0k | return ssa_op->op1_use_chain; | 196 | 23.0k | } else if (ssa_op->op2_use == var) { | 197 | 4.15k | return ssa_op->op2_use_chain; | 198 | 4.15k | } else { | 199 | 102 | return ssa_op->res_use_chain; | 200 | 102 | } | 201 | 27.3k | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_next_use |
202 | | |
203 | | static zend_always_inline zend_ssa_phi* zend_ssa_next_use_phi(const zend_ssa *ssa, int var, const zend_ssa_phi *p) |
204 | 3.53M | { |
205 | 3.53M | if (p->pi >= 0) { |
206 | 557k | return p->use_chains[0]; |
207 | 2.97M | } else { |
208 | 4.52M | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { |
209 | 4.52M | if (p->sources[j] == var) { |
210 | 2.97M | return p->use_chains[j]; |
211 | 2.97M | } |
212 | 4.52M | } |
213 | 2.97M | } |
214 | 5 | return NULL; |
215 | 3.53M | } Unexecuted instantiation: zend_persist.c:zend_ssa_next_use_phi Unexecuted instantiation: ZendAccelerator.c:zend_ssa_next_use_phi Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_next_use_phi Unexecuted instantiation: zend_jit.c:zend_ssa_next_use_phi 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 | 204 | 2.89M | { | 205 | 2.89M | if (p->pi >= 0) { | 206 | 412k | return p->use_chains[0]; | 207 | 2.47M | } else { | 208 | 3.74M | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 3.74M | if (p->sources[j] == var) { | 210 | 2.47M | return p->use_chains[j]; | 211 | 2.47M | } | 212 | 3.74M | } | 213 | 2.47M | } | 214 | 0 | return NULL; | 215 | 2.89M | } |
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 | 204 | 130k | { | 205 | 130k | if (p->pi >= 0) { | 206 | 24.3k | return p->use_chains[0]; | 207 | 106k | } else { | 208 | 167k | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 167k | if (p->sources[j] == var) { | 210 | 106k | return p->use_chains[j]; | 211 | 106k | } | 212 | 167k | } | 213 | 106k | } | 214 | 0 | return NULL; | 215 | 130k | } |
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 | 204 | 481k | { | 205 | 481k | if (p->pi >= 0) { | 206 | 99.0k | return p->use_chains[0]; | 207 | 382k | } else { | 208 | 596k | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 596k | if (p->sources[j] == var) { | 210 | 382k | return p->use_chains[j]; | 211 | 382k | } | 212 | 596k | } | 213 | 382k | } | 214 | 0 | return NULL; | 215 | 481k | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_next_use_phi zend_ssa.c:zend_ssa_next_use_phi Line | Count | Source | 204 | 32.6k | { | 205 | 32.6k | if (p->pi >= 0) { | 206 | 21.2k | return p->use_chains[0]; | 207 | 21.2k | } else { | 208 | 17.6k | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 17.6k | if (p->sources[j] == var) { | 210 | 11.4k | return p->use_chains[j]; | 211 | 11.4k | } | 212 | 17.6k | } | 213 | 11.4k | } | 214 | 5 | return NULL; | 215 | 32.6k | } |
Unexecuted instantiation: zend_execute.c:zend_ssa_next_use_phi |
216 | | |
217 | | static zend_always_inline bool zend_ssa_is_no_val_use(const zend_op *opline, const zend_ssa_op *ssa_op, int var) |
218 | 674k | { |
219 | 674k | if (opline->opcode == ZEND_ASSIGN |
220 | 608k | || opline->opcode == ZEND_UNSET_CV |
221 | 606k | || opline->opcode == ZEND_BIND_GLOBAL |
222 | 605k | || opline->opcode == ZEND_BIND_STATIC) { |
223 | 73.0k | return ssa_op->op1_use == var && ssa_op->op2_use != var; |
224 | 73.0k | } |
225 | 601k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { |
226 | 4.29k | return ssa_op->op2_use == var && ssa_op->op1_use != var; |
227 | 4.29k | } |
228 | 596k | if (ssa_op->result_use == var |
229 | 372 | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT |
230 | 8 | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { |
231 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; |
232 | 0 | } |
233 | 596k | return 0; |
234 | 596k | } Unexecuted instantiation: zend_persist.c:zend_ssa_is_no_val_use Unexecuted instantiation: ZendAccelerator.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_is_no_val_use Unexecuted instantiation: zend_jit.c:zend_ssa_is_no_val_use 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 | 218 | 522k | { | 219 | 522k | if (opline->opcode == ZEND_ASSIGN | 220 | 474k | || opline->opcode == ZEND_UNSET_CV | 221 | 473k | || opline->opcode == ZEND_BIND_GLOBAL | 222 | 473k | || opline->opcode == ZEND_BIND_STATIC) { | 223 | 51.3k | return ssa_op->op1_use == var && ssa_op->op2_use != var; | 224 | 51.3k | } | 225 | 470k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { | 226 | 3.38k | return ssa_op->op2_use == var && ssa_op->op1_use != var; | 227 | 3.38k | } | 228 | 467k | if (ssa_op->result_use == var | 229 | 0 | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT | 230 | 0 | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { | 231 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; | 232 | 0 | } | 233 | 467k | return 0; | 234 | 467k | } |
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 | 218 | 151k | { | 219 | 151k | if (opline->opcode == ZEND_ASSIGN | 220 | 133k | || opline->opcode == ZEND_UNSET_CV | 221 | 132k | || opline->opcode == ZEND_BIND_GLOBAL | 222 | 132k | || opline->opcode == ZEND_BIND_STATIC) { | 223 | 21.6k | return ssa_op->op1_use == var && ssa_op->op2_use != var; | 224 | 21.6k | } | 225 | 130k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { | 226 | 910 | return ssa_op->op2_use == var && ssa_op->op1_use != var; | 227 | 910 | } | 228 | 129k | if (ssa_op->result_use == var | 229 | 372 | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT | 230 | 8 | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { | 231 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; | 232 | 0 | } | 233 | 129k | return 0; | 234 | 129k | } |
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 |
235 | | |
236 | 10.8k | static zend_always_inline void zend_ssa_rename_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) { |
237 | | /* Rename def to use if possible. Mark variable as not defined otherwise. */ |
238 | 10.8k | if (ssa_op->op1_def >= 0) { |
239 | 2.98k | if (ssa_op->op1_use >= 0) { |
240 | 2.98k | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, true); |
241 | 2.98k | } |
242 | 2.98k | ssa->vars[ssa_op->op1_def].definition = -1; |
243 | 2.98k | ssa_op->op1_def = -1; |
244 | 2.98k | } |
245 | 10.8k | if (ssa_op->op2_def >= 0) { |
246 | 0 | if (ssa_op->op2_use >= 0) { |
247 | 0 | zend_ssa_rename_var_uses(ssa, ssa_op->op2_def, ssa_op->op2_use, true); |
248 | 0 | } |
249 | 0 | ssa->vars[ssa_op->op2_def].definition = -1; |
250 | 0 | ssa_op->op2_def = -1; |
251 | 0 | } |
252 | 10.8k | if (ssa_op->result_def >= 0) { |
253 | 3.90k | if (ssa_op->result_use >= 0) { |
254 | 60 | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, true); |
255 | 60 | } |
256 | 3.90k | ssa->vars[ssa_op->result_def].definition = -1; |
257 | 3.90k | ssa_op->result_def = -1; |
258 | 3.90k | } |
259 | 10.8k | } Unexecuted instantiation: zend_persist.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: ZendAccelerator.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_jit_vm_helpers.c:zend_ssa_rename_defs_of_instr Unexecuted instantiation: zend_jit.c:zend_ssa_rename_defs_of_instr 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 | 236 | 10.8k | static zend_always_inline void zend_ssa_rename_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) { | 237 | | /* Rename def to use if possible. Mark variable as not defined otherwise. */ | 238 | 10.8k | if (ssa_op->op1_def >= 0) { | 239 | 2.98k | if (ssa_op->op1_use >= 0) { | 240 | 2.98k | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, true); | 241 | 2.98k | } | 242 | 2.98k | ssa->vars[ssa_op->op1_def].definition = -1; | 243 | 2.98k | ssa_op->op1_def = -1; | 244 | 2.98k | } | 245 | 10.8k | if (ssa_op->op2_def >= 0) { | 246 | 0 | if (ssa_op->op2_use >= 0) { | 247 | 0 | zend_ssa_rename_var_uses(ssa, ssa_op->op2_def, ssa_op->op2_use, true); | 248 | 0 | } | 249 | 0 | ssa->vars[ssa_op->op2_def].definition = -1; | 250 | 0 | ssa_op->op2_def = -1; | 251 | 0 | } | 252 | 10.8k | if (ssa_op->result_def >= 0) { | 253 | 3.90k | if (ssa_op->result_use >= 0) { | 254 | | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, true); | 255 | 60 | } | 256 | 3.90k | ssa->vars[ssa_op->result_def].definition = -1; | 257 | 3.90k | ssa_op->result_def = -1; | 258 | 3.90k | } | 259 | 10.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 |
260 | | |
261 | | #define NUM_PHI_SOURCES(phi) \ |
262 | 1.29M | ((phi)->pi >= 0 ? 1 : (ssa->cfg.blocks[(phi)->block].predecessors_count)) |
263 | | |
264 | | /* FOREACH_USE and FOREACH_PHI_USE explicitly support "continue" |
265 | | * and changing the use chain of the current element */ |
266 | 6.61M | #define FOREACH_USE(var, use) do { \ |
267 | 6.61M | int _var_num = (var) - ssa->vars, next; \ |
268 | 12.5M | for (use = (var)->use_chain; use >= 0; use = next) { \ |
269 | 8.80M | next = zend_ssa_next_use(ssa->ops, _var_num, use); |
270 | | #define FOREACH_USE_END() \ |
271 | 8.80M | } \ |
272 | 6.61M | } while (0) |
273 | | |
274 | 4.33M | #define FOREACH_PHI_USE(var, phi) do { \ |
275 | 4.33M | int _var_num = (var) - ssa->vars; \ |
276 | 4.33M | zend_ssa_phi *next_phi; \ |
277 | 5.30M | for (phi = (var)->phi_use_chain; phi; phi = next_phi) { \ |
278 | 1.70M | next_phi = zend_ssa_next_use_phi(ssa, _var_num, phi); |
279 | | #define FOREACH_PHI_USE_END() \ |
280 | 1.70M | } \ |
281 | 4.33M | } while (0) |
282 | | |
283 | 874k | #define FOREACH_PHI_SOURCE(phi, source) do { \ |
284 | 874k | zend_ssa_phi *_phi = (phi); \ |
285 | 874k | uint32_t _i, _end = NUM_PHI_SOURCES(phi); \ |
286 | 1.42M | for (_i = 0; _i < _end; _i++) { \ |
287 | 1.32M | ZEND_ASSERT(_phi->sources[_i] >= 0); \ |
288 | 1.32M | source = _phi->sources[_i]; |
289 | | #define FOREACH_PHI_SOURCE_END() \ |
290 | 1.31M | } \ |
291 | 874k | } while (0) |
292 | | |
293 | 263k | #define FOREACH_PHI(phi) do { \ |
294 | 1.04M | for (uint32_t _i = 0; _i < ssa->cfg.blocks_count; _i++) { \ |
295 | 777k | phi = ssa->blocks[_i].phis; \ |
296 | 1.35M | for (; phi; phi = phi->next) { |
297 | | #define FOREACH_PHI_END() \ |
298 | 578k | } \ |
299 | 777k | } \ |
300 | 263k | } while (0) |
301 | | |
302 | 189k | #define FOREACH_BLOCK(block) do { \ |
303 | 754k | for (uint32_t _i = 0; _i < ssa->cfg.blocks_count; _i++) { \ |
304 | 564k | (block) = &ssa->cfg.blocks[_i]; \ |
305 | 564k | if (!((block)->flags & ZEND_BB_REACHABLE)) { \ |
306 | 12.6k | continue; \ |
307 | 12.6k | } |
308 | | #define FOREACH_BLOCK_END() \ |
309 | 551k | } \ |
310 | 189k | } while (0) |
311 | | |
312 | | /* Does not support "break" */ |
313 | 189k | #define FOREACH_INSTR_NUM(i) do { \ |
314 | 189k | zend_basic_block *_block; \ |
315 | 564k | FOREACH_BLOCK(_block) { \ |
316 | 551k | uint32_t _end = _block->start + _block->len; \ |
317 | 4.35M | for ((i) = _block->start; (i) < _end; (i)++) { |
318 | | #define FOREACH_INSTR_NUM_END() \ |
319 | 3.80M | } \ |
320 | 551k | } FOREACH_BLOCK_END(); \ |
321 | 189k | } while (0) |
322 | | |
323 | | #endif /* ZEND_SSA_H */ |