/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 | 6.88k | { |
162 | 6.88k | ZEND_ASSERT(var->definition >= 0); |
163 | 6.88k | ZEND_ASSERT(var->use_chain < 0); |
164 | 6.88k | ZEND_ASSERT(!var->phi_use_chain); |
165 | 6.88k | var->definition = -1; |
166 | 6.88k | } 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.01k | { | 162 | 1.01k | ZEND_ASSERT(var->definition >= 0); | 163 | 1.01k | ZEND_ASSERT(var->use_chain < 0); | 164 | 1.01k | ZEND_ASSERT(!var->phi_use_chain); | 165 | 1.01k | var->definition = -1; | 166 | 1.01k | } |
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.52k | { | 162 | 1.52k | ZEND_ASSERT(var->definition >= 0); | 163 | 1.52k | ZEND_ASSERT(var->use_chain < 0); | 164 | 1.52k | ZEND_ASSERT(!var->phi_use_chain); | 165 | 1.52k | var->definition = -1; | 166 | 1.52k | } |
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 | 4.35k | { | 162 | 4.35k | ZEND_ASSERT(var->definition >= 0); | 163 | 4.35k | ZEND_ASSERT(var->use_chain < 0); | 164 | 4.35k | ZEND_ASSERT(!var->phi_use_chain); | 165 | 4.35k | var->definition = -1; | 166 | 4.35k | } |
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 | 6.56k | { |
170 | 6.56k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; |
171 | 6.56k | _zend_ssa_remove_def(var); |
172 | 6.56k | ssa_op->result_def = -1; |
173 | 6.56k | } 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.01k | { | 170 | 1.01k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 171 | 1.01k | _zend_ssa_remove_def(var); | 172 | 1.01k | ssa_op->result_def = -1; | 173 | 1.01k | } |
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.51k | { | 170 | 1.51k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 171 | 1.51k | _zend_ssa_remove_def(var); | 172 | 1.51k | ssa_op->result_def = -1; | 173 | 1.51k | } |
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 | 4.04k | { | 170 | 4.04k | zend_ssa_var *var = &ssa->vars[ssa_op->result_def]; | 171 | 4.04k | _zend_ssa_remove_def(var); | 172 | 4.04k | ssa_op->result_def = -1; | 173 | 4.04k | } |
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 | 300 | { |
177 | 300 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; |
178 | 300 | _zend_ssa_remove_def(var); |
179 | 300 | ssa_op->op1_def = -1; |
180 | 300 | } 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 | 8 | { | 177 | 8 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; | 178 | 8 | _zend_ssa_remove_def(var); | 179 | 8 | ssa_op->op1_def = -1; | 180 | 8 | } |
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 | 292 | { | 177 | 292 | zend_ssa_var *var = &ssa->vars[ssa_op->op1_def]; | 178 | 292 | _zend_ssa_remove_def(var); | 179 | 292 | ssa_op->op1_def = -1; | 180 | 292 | } |
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 | 20 | { |
184 | 20 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; |
185 | 20 | _zend_ssa_remove_def(var); |
186 | 20 | ssa_op->op2_def = -1; |
187 | 20 | } 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 | 20 | { | 184 | 20 | zend_ssa_var *var = &ssa->vars[ssa_op->op2_def]; | 185 | 20 | _zend_ssa_remove_def(var); | 186 | 20 | ssa_op->op2_def = -1; | 187 | 20 | } |
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 | 19.6M | { |
193 | 19.6M | ssa_op += use; |
194 | 19.6M | if (ssa_op->op1_use == var) { |
195 | 15.3M | return ssa_op->op1_use_chain; |
196 | 15.3M | } else if (ssa_op->op2_use == var) { |
197 | 4.17M | return ssa_op->op2_use_chain; |
198 | 4.17M | } else { |
199 | 150k | return ssa_op->res_use_chain; |
200 | 150k | } |
201 | 19.6M | } 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 | 17.3M | { | 193 | 17.3M | ssa_op += use; | 194 | 17.3M | if (ssa_op->op1_use == var) { | 195 | 13.5M | return ssa_op->op1_use_chain; | 196 | 13.5M | } else if (ssa_op->op2_use == var) { | 197 | 3.64M | return ssa_op->op2_use_chain; | 198 | 3.64M | } else { | 199 | 117k | return ssa_op->res_use_chain; | 200 | 117k | } | 201 | 17.3M | } |
escape_analysis.c:zend_ssa_next_use Line | Count | Source | 192 | 16.9k | { | 193 | 16.9k | ssa_op += use; | 194 | 16.9k | if (ssa_op->op1_use == var) { | 195 | 10.6k | return ssa_op->op1_use_chain; | 196 | 10.6k | } else if (ssa_op->op2_use == var) { | 197 | 2.61k | return ssa_op->op2_use_chain; | 198 | 3.71k | } else { | 199 | 3.71k | return ssa_op->res_use_chain; | 200 | 3.71k | } | 201 | 16.9k | } |
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 | 504k | { | 193 | 504k | ssa_op += use; | 194 | 504k | if (ssa_op->op1_use == var) { | 195 | 395k | return ssa_op->op1_use_chain; | 196 | 395k | } else if (ssa_op->op2_use == var) { | 197 | 98.3k | return ssa_op->op2_use_chain; | 198 | 98.3k | } else { | 199 | 11.3k | return ssa_op->res_use_chain; | 200 | 11.3k | } | 201 | 504k | } |
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.78M | { | 193 | 1.78M | ssa_op += use; | 194 | 1.78M | if (ssa_op->op1_use == var) { | 195 | 1.34M | return ssa_op->op1_use_chain; | 196 | 1.34M | } else if (ssa_op->op2_use == var) { | 197 | 425k | return ssa_op->op2_use_chain; | 198 | 425k | } else { | 199 | 17.3k | return ssa_op->res_use_chain; | 200 | 17.3k | } | 201 | 1.78M | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_next_use zend_ssa.c:zend_ssa_next_use Line | Count | Source | 192 | 27.0k | { | 193 | 27.0k | ssa_op += use; | 194 | 27.0k | if (ssa_op->op1_use == var) { | 195 | 21.9k | return ssa_op->op1_use_chain; | 196 | 21.9k | } else if (ssa_op->op2_use == var) { | 197 | 5.07k | return ssa_op->op2_use_chain; | 198 | 5.07k | } else { | 199 | 77 | return ssa_op->res_use_chain; | 200 | 77 | } | 201 | 27.0k | } |
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 | 2.68M | { |
205 | 2.68M | if (p->pi >= 0) { |
206 | 416k | return p->use_chains[0]; |
207 | 2.27M | } else { |
208 | 3.48M | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { |
209 | 3.48M | if (p->sources[j] == var) { |
210 | 2.27M | return p->use_chains[j]; |
211 | 2.27M | } |
212 | 3.48M | } |
213 | 2.27M | } |
214 | 0 | return NULL; |
215 | 2.68M | } 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.16M | { | 205 | 2.16M | if (p->pi >= 0) { | 206 | 301k | return p->use_chains[0]; | 207 | 1.86M | } else { | 208 | 2.83M | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 2.83M | if (p->sources[j] == var) { | 210 | 1.86M | return p->use_chains[j]; | 211 | 1.86M | } | 212 | 2.83M | } | 213 | 1.86M | } | 214 | 0 | return NULL; | 215 | 2.16M | } |
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 | 97.1k | { | 205 | 97.1k | if (p->pi >= 0) { | 206 | 17.7k | return p->use_chains[0]; | 207 | 79.3k | } else { | 208 | 126k | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 126k | if (p->sources[j] == var) { | 210 | 79.3k | return p->use_chains[j]; | 211 | 79.3k | } | 212 | 126k | } | 213 | 79.3k | } | 214 | 0 | return NULL; | 215 | 97.1k | } |
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 | 396k | { | 205 | 396k | if (p->pi >= 0) { | 206 | 82.9k | return p->use_chains[0]; | 207 | 313k | } else { | 208 | 495k | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 495k | if (p->sources[j] == var) { | 210 | 313k | return p->use_chains[j]; | 211 | 313k | } | 212 | 495k | } | 213 | 313k | } | 214 | 0 | return NULL; | 215 | 396k | } |
Unexecuted instantiation: zend_optimizer.c:zend_ssa_next_use_phi zend_ssa.c:zend_ssa_next_use_phi Line | Count | Source | 204 | 28.4k | { | 205 | 28.4k | if (p->pi >= 0) { | 206 | 14.3k | return p->use_chains[0]; | 207 | 14.3k | } else { | 208 | 20.6k | for (uint32_t j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) { | 209 | 20.6k | if (p->sources[j] == var) { | 210 | 14.1k | return p->use_chains[j]; | 211 | 14.1k | } | 212 | 20.6k | } | 213 | 14.1k | } | 214 | 0 | return NULL; | 215 | 28.4k | } |
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 | 667k | { |
219 | 667k | if (opline->opcode == ZEND_ASSIGN |
220 | 599k | || opline->opcode == ZEND_UNSET_CV |
221 | 598k | || opline->opcode == ZEND_BIND_GLOBAL |
222 | 597k | || opline->opcode == ZEND_BIND_STATIC) { |
223 | 80.8k | return ssa_op->op1_use == var && ssa_op->op2_use != var; |
224 | 80.8k | } |
225 | 586k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { |
226 | 5.23k | return ssa_op->op2_use == var && ssa_op->op1_use != var; |
227 | 5.23k | } |
228 | 581k | if (ssa_op->result_use == var |
229 | 379 | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT |
230 | 2 | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { |
231 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; |
232 | 0 | } |
233 | 581k | return 0; |
234 | 581k | } 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 | 520k | { | 219 | 520k | if (opline->opcode == ZEND_ASSIGN | 220 | 471k | || opline->opcode == ZEND_UNSET_CV | 221 | 470k | || opline->opcode == ZEND_BIND_GLOBAL | 222 | 470k | || opline->opcode == ZEND_BIND_STATIC) { | 223 | 55.9k | return ssa_op->op1_use == var && ssa_op->op2_use != var; | 224 | 55.9k | } | 225 | 464k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { | 226 | 3.81k | return ssa_op->op2_use == var && ssa_op->op1_use != var; | 227 | 3.81k | } | 228 | 460k | 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 | 460k | return 0; | 234 | 460k | } |
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 | 146k | { | 219 | 146k | if (opline->opcode == ZEND_ASSIGN | 220 | 127k | || opline->opcode == ZEND_UNSET_CV | 221 | 127k | || opline->opcode == ZEND_BIND_GLOBAL | 222 | 127k | || opline->opcode == ZEND_BIND_STATIC) { | 223 | 24.9k | return ssa_op->op1_use == var && ssa_op->op2_use != var; | 224 | 24.9k | } | 225 | 121k | if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { | 226 | 1.42k | return ssa_op->op2_use == var && ssa_op->op1_use != var; | 227 | 1.42k | } | 228 | 120k | if (ssa_op->result_use == var | 229 | 379 | && opline->opcode != ZEND_ADD_ARRAY_ELEMENT | 230 | 2 | && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { | 231 | 0 | return ssa_op->op1_use != var && ssa_op->op2_use != var; | 232 | 0 | } | 233 | 120k | return 0; | 234 | 120k | } |
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 | 9.39k | 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 | 9.39k | if (ssa_op->op1_def >= 0) { |
239 | 2.68k | if (ssa_op->op1_use >= 0) { |
240 | 2.68k | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, true); |
241 | 2.68k | } |
242 | 2.68k | ssa->vars[ssa_op->op1_def].definition = -1; |
243 | 2.68k | ssa_op->op1_def = -1; |
244 | 2.68k | } |
245 | 9.39k | 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 | 9.39k | if (ssa_op->result_def >= 0) { |
253 | 2.90k | if (ssa_op->result_use >= 0) { |
254 | 55 | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, true); |
255 | 55 | } |
256 | 2.90k | ssa->vars[ssa_op->result_def].definition = -1; |
257 | 2.90k | ssa_op->result_def = -1; |
258 | 2.90k | } |
259 | 9.39k | } 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 | 9.39k | 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 | 9.39k | if (ssa_op->op1_def >= 0) { | 239 | 2.68k | if (ssa_op->op1_use >= 0) { | 240 | 2.68k | zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, true); | 241 | 2.68k | } | 242 | 2.68k | ssa->vars[ssa_op->op1_def].definition = -1; | 243 | 2.68k | ssa_op->op1_def = -1; | 244 | 2.68k | } | 245 | 9.39k | 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 | 9.39k | if (ssa_op->result_def >= 0) { | 253 | 2.90k | if (ssa_op->result_use >= 0) { | 254 | | zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, true); | 255 | 55 | } | 256 | 2.90k | ssa->vars[ssa_op->result_def].definition = -1; | 257 | 2.90k | ssa_op->result_def = -1; | 258 | 2.90k | } | 259 | 9.39k | } |
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 | 963k | ((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.43M | #define FOREACH_USE(var, use) do { \ |
267 | 6.43M | int _var_num = (var) - ssa->vars, next; \ |
268 | 16.1M | for (use = (var)->use_chain; use >= 0; use = next) { \ |
269 | 12.5M | next = zend_ssa_next_use(ssa->ops, _var_num, use); |
270 | | #define FOREACH_USE_END() \ |
271 | 12.5M | } \ |
272 | 6.43M | } while (0) |
273 | | |
274 | 4.00M | #define FOREACH_PHI_USE(var, phi) do { \ |
275 | 4.00M | int _var_num = (var) - ssa->vars; \ |
276 | 4.00M | zend_ssa_phi *next_phi; \ |
277 | 4.72M | for (phi = (var)->phi_use_chain; phi; phi = next_phi) { \ |
278 | 1.26M | next_phi = zend_ssa_next_use_phi(ssa, _var_num, phi); |
279 | | #define FOREACH_PHI_USE_END() \ |
280 | 1.26M | } \ |
281 | 4.00M | } while (0) |
282 | | |
283 | 649k | #define FOREACH_PHI_SOURCE(phi, source) do { \ |
284 | 649k | zend_ssa_phi *_phi = (phi); \ |
285 | 649k | uint32_t _i, _end = NUM_PHI_SOURCES(phi); \ |
286 | 1.05M | for (_i = 0; _i < _end; _i++) { \ |
287 | 986k | ZEND_ASSERT(_phi->sources[_i] >= 0); \ |
288 | 986k | source = _phi->sources[_i]; |
289 | | #define FOREACH_PHI_SOURCE_END() \ |
290 | 985k | } \ |
291 | 649k | } while (0) |
292 | | |
293 | 242k | #define FOREACH_PHI(phi) do { \ |
294 | 921k | for (uint32_t _i = 0; _i < ssa->cfg.blocks_count; _i++) { \ |
295 | 678k | phi = ssa->blocks[_i].phis; \ |
296 | 1.10M | for (; phi; phi = phi->next) { |
297 | | #define FOREACH_PHI_END() \ |
298 | 429k | } \ |
299 | 678k | } \ |
300 | 242k | } while (0) |
301 | | |
302 | 174k | #define FOREACH_BLOCK(block) do { \ |
303 | 667k | for (uint32_t _i = 0; _i < ssa->cfg.blocks_count; _i++) { \ |
304 | 492k | (block) = &ssa->cfg.blocks[_i]; \ |
305 | 492k | if (!((block)->flags & ZEND_BB_REACHABLE)) { \ |
306 | 16.6k | continue; \ |
307 | 16.6k | } |
308 | | #define FOREACH_BLOCK_END() \ |
309 | 476k | } \ |
310 | 174k | } while (0) |
311 | | |
312 | | /* Does not support "break" */ |
313 | 174k | #define FOREACH_INSTR_NUM(i) do { \ |
314 | 174k | zend_basic_block *_block; \ |
315 | 492k | FOREACH_BLOCK(_block) { \ |
316 | 476k | uint32_t _end = _block->start + _block->len; \ |
317 | 4.30M | for ((i) = _block->start; (i) < _end; (i)++) { |
318 | | #define FOREACH_INSTR_NUM_END() \ |
319 | 3.83M | } \ |
320 | 476k | } FOREACH_BLOCK_END(); \ |
321 | 174k | } while (0) |
322 | | |
323 | | #endif /* ZEND_SSA_H */ |