xref: /PHP-7.3/ext/opcache/Optimizer/zend_ssa.c (revision 9083e178)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine, SSA - Static Single Assignment Form                     |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@php.net>                              |
16    |          Nikita Popov <nikic@php.net>                                |
17    +----------------------------------------------------------------------+
18 */
19 
20 #include "php.h"
21 #include "zend_compile.h"
22 #include "zend_dfg.h"
23 #include "zend_ssa.h"
24 #include "zend_dump.h"
25 #include "zend_inference.h"
26 #include "Optimizer/zend_optimizer_internal.h"
27 
dominates(const zend_basic_block * blocks,int a,int b)28 static zend_bool dominates(const zend_basic_block *blocks, int a, int b) {
29 	while (blocks[b].level > blocks[a].level) {
30 		b = blocks[b].idom;
31 	}
32 	return a == b;
33 }
34 
dominates_other_predecessors(const zend_cfg * cfg,const zend_basic_block * block,int check,int exclude)35 static zend_bool dominates_other_predecessors(
36 		const zend_cfg *cfg, const zend_basic_block *block, int check, int exclude) {
37 	int i;
38 	for (i = 0; i < block->predecessors_count; i++) {
39 		int predecessor = cfg->predecessors[block->predecessor_offset + i];
40 		if (predecessor != exclude && !dominates(cfg->blocks, check, predecessor)) {
41 			return 0;
42 		}
43 	}
44 	return 1;
45 }
46 
needs_pi(const zend_op_array * op_array,zend_dfg * dfg,zend_ssa * ssa,int from,int to,int var)47 static zend_bool needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */
48 {
49 	zend_basic_block *from_block, *to_block;
50 	int other_successor;
51 
52 	if (!DFG_ISSET(dfg->in, dfg->size, to, var)) {
53 		/* Variable is not live, certainly won't benefit from pi */
54 		return 0;
55 	}
56 
57 	/* Make sure that both sucessors of the from block aren't the same. Pi nodes are associated
58 	 * with predecessor blocks, so we can't distinguish which edge the pi belongs to. */
59 	from_block = &ssa->cfg.blocks[from];
60 	ZEND_ASSERT(from_block->successors_count == 2);
61 	if (from_block->successors[0] == from_block->successors[1]) {
62 		return 0;
63 	}
64 
65 	to_block = &ssa->cfg.blocks[to];
66 	if (to_block->predecessors_count == 1) {
67 		/* Always place pi if one predecessor (an if branch) */
68 		return 1;
69 	}
70 
71 	/* Check that the other successor of the from block does not dominate all other predecessors.
72 	 * If it does, we'd probably end up annihilating a positive+negative pi assertion. */
73 	other_successor = from_block->successors[0] == to
74 		? from_block->successors[1] : from_block->successors[0];
75 	return !dominates_other_predecessors(&ssa->cfg, to_block, other_successor, from);
76 }
77 /* }}} */
78 
add_pi(zend_arena ** arena,const zend_op_array * op_array,zend_dfg * dfg,zend_ssa * ssa,int from,int to,int var)79 static zend_ssa_phi *add_pi(
80 		zend_arena **arena, const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa,
81 		int from, int to, int var) /* {{{ */
82 {
83 	zend_ssa_phi *phi;
84 	if (!needs_pi(op_array, dfg, ssa, from, to, var)) {
85 		return NULL;
86 	}
87 
88 	phi = zend_arena_calloc(arena, 1,
89 		ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
90 		ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[to].predecessors_count) +
91 		sizeof(void*) * ssa->cfg.blocks[to].predecessors_count);
92 	phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
93 	memset(phi->sources, 0xff, sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
94 	phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[to].predecessors_count));
95 
96 	phi->pi = from;
97 	phi->var = var;
98 	phi->ssa_var = -1;
99 	phi->next = ssa->blocks[to].phis;
100 	ssa->blocks[to].phis = phi;
101 
102 	/* Block "to" now defines "var" via the pi statement, so add it to the "def" set. Note that
103 	 * this is not entirely accurate, because the pi is actually placed along the edge from->to.
104 	 * If there is a back-edge to "to" this may result in non-minimal SSA form. */
105 	DFG_SET(dfg->def, dfg->size, to, var);
106 
107 	/* If there are multiple predecessors in the target block, we need to place a phi there.
108 	 * However this can (generally) not be expressed in terms of dominance frontiers, so place it
109 	 * explicitly. dfg->use here really is dfg->phi, we're reusing the set. */
110 	if (ssa->cfg.blocks[to].predecessors_count > 1) {
111 		DFG_SET(dfg->use, dfg->size, to, var);
112 	}
113 
114 	return phi;
115 }
116 /* }}} */
117 
pi_range(zend_ssa_phi * phi,int min_var,int max_var,zend_long min,zend_long max,char underflow,char overflow,char negative)118 static void pi_range(
119 		zend_ssa_phi *phi, int min_var, int max_var, zend_long min, zend_long max,
120 		char underflow, char overflow, char negative) /* {{{ */
121 {
122 	zend_ssa_range_constraint *constraint = &phi->constraint.range;
123 	constraint->min_var = min_var;
124 	constraint->max_var = max_var;
125 	constraint->min_ssa_var = -1;
126 	constraint->max_ssa_var = -1;
127 	constraint->range.min = min;
128 	constraint->range.max = max;
129 	constraint->range.underflow = underflow;
130 	constraint->range.overflow = overflow;
131 	constraint->negative = negative ? NEG_INIT : NEG_NONE;
132 	phi->has_range_constraint = 1;
133 }
134 /* }}} */
135 
pi_range_equals(zend_ssa_phi * phi,int var,zend_long val)136 static inline void pi_range_equals(zend_ssa_phi *phi, int var, zend_long val) {
137 	pi_range(phi, var, var, val, val, 0, 0, 0);
138 }
pi_range_not_equals(zend_ssa_phi * phi,int var,zend_long val)139 static inline void pi_range_not_equals(zend_ssa_phi *phi, int var, zend_long val) {
140 	pi_range(phi, var, var, val, val, 0, 0, 1);
141 }
pi_range_min(zend_ssa_phi * phi,int var,zend_long val)142 static inline void pi_range_min(zend_ssa_phi *phi, int var, zend_long val) {
143 	pi_range(phi, var, -1, val, ZEND_LONG_MAX, 0, 1, 0);
144 }
pi_range_max(zend_ssa_phi * phi,int var,zend_long val)145 static inline void pi_range_max(zend_ssa_phi *phi, int var, zend_long val) {
146 	pi_range(phi, -1, var, ZEND_LONG_MIN, val, 1, 0, 0);
147 }
148 
pi_type_mask(zend_ssa_phi * phi,uint32_t type_mask)149 static void pi_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
150 	phi->has_range_constraint = 0;
151 	phi->constraint.type.ce = NULL;
152 	phi->constraint.type.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
153 	phi->constraint.type.type_mask |= type_mask;
154 	if (type_mask & MAY_BE_NULL) {
155 		phi->constraint.type.type_mask |= MAY_BE_UNDEF;
156 	}
157 }
pi_not_type_mask(zend_ssa_phi * phi,uint32_t type_mask)158 static inline void pi_not_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
159 	uint32_t relevant = MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
160 	pi_type_mask(phi, ~type_mask & relevant);
161 }
mask_for_type_check(uint32_t type)162 static inline uint32_t mask_for_type_check(uint32_t type) {
163 	if (type & MAY_BE_ARRAY) {
164 		return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
165 	} else {
166 		return type;
167 	}
168 }
169 
170 /* We can interpret $a + 5 == 0 as $a = 0 - 5, i.e. shift the adjustment to the other operand.
171  * This negated adjustment is what is written into the "adjustment" parameter. */
find_adjusted_tmp_var(const zend_op_array * op_array,uint32_t build_flags,zend_op * opline,uint32_t var_num,zend_long * adjustment)172 static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_flags, zend_op *opline, uint32_t var_num, zend_long *adjustment) /* {{{ */
173 {
174 	zend_op *op = opline;
175 	zval *zv;
176 
177 	while (op != op_array->opcodes) {
178 		op--;
179 		if (op->result_type != IS_TMP_VAR || op->result.var != var_num) {
180 			continue;
181 		}
182 
183 		if (op->opcode == ZEND_POST_DEC) {
184 			if (op->op1_type == IS_CV) {
185 				*adjustment = -1;
186 				return EX_VAR_TO_NUM(op->op1.var);
187 			}
188 		} else if (op->opcode == ZEND_POST_INC) {
189 			if (op->op1_type == IS_CV) {
190 				*adjustment = 1;
191 				return EX_VAR_TO_NUM(op->op1.var);
192 			}
193 		} else if (op->opcode == ZEND_ADD) {
194 			if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
195 				zv = CRT_CONSTANT_EX(op_array, op, op->op2, (build_flags & ZEND_RT_CONSTANTS));
196 				if (Z_TYPE_P(zv) == IS_LONG
197 				 && Z_LVAL_P(zv) != ZEND_LONG_MIN) {
198 					*adjustment = -Z_LVAL_P(zv);
199 					return EX_VAR_TO_NUM(op->op1.var);
200 				}
201 			} else if (op->op2_type == IS_CV && op->op1_type == IS_CONST) {
202 				zv = CRT_CONSTANT_EX(op_array, op, op->op1, (build_flags & ZEND_RT_CONSTANTS));
203 				if (Z_TYPE_P(zv) == IS_LONG
204 				 && Z_LVAL_P(zv) != ZEND_LONG_MIN) {
205 					*adjustment = -Z_LVAL_P(zv);
206 					return EX_VAR_TO_NUM(op->op2.var);
207 				}
208 			}
209 		} else if (op->opcode == ZEND_SUB) {
210 			if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
211 				zv = CRT_CONSTANT_EX(op_array, op, op->op2, (build_flags & ZEND_RT_CONSTANTS));
212 				if (Z_TYPE_P(zv) == IS_LONG) {
213 					*adjustment = Z_LVAL_P(zv);
214 					return EX_VAR_TO_NUM(op->op1.var);
215 				}
216 			}
217 		}
218 		break;
219 	}
220 	return -1;
221 }
222 /* }}} */
223 
add_will_overflow(zend_long a,zend_long b)224 static inline zend_bool add_will_overflow(zend_long a, zend_long b) {
225 	return (b > 0 && a > ZEND_LONG_MAX - b)
226 		|| (b < 0 && a < ZEND_LONG_MIN - b);
227 }
sub_will_overflow(zend_long a,zend_long b)228 static inline zend_bool sub_will_overflow(zend_long a, zend_long b) {
229 	return (b > 0 && a < ZEND_LONG_MIN + b)
230 		|| (b < 0 && a > ZEND_LONG_MAX + b);
231 }
232 
233 /* e-SSA construction: Pi placement (Pi is actually a Phi with single
234  * source and constraint).
235  * Order of Phis is importent, Pis must be placed before Phis
236  */
place_essa_pis(zend_arena ** arena,const zend_script * script,const zend_op_array * op_array,uint32_t build_flags,zend_ssa * ssa,zend_dfg * dfg)237 static void place_essa_pis(
238 		zend_arena **arena, const zend_script *script, const zend_op_array *op_array,
239 		uint32_t build_flags, zend_ssa *ssa, zend_dfg *dfg) /* {{{ */ {
240 	zend_basic_block *blocks = ssa->cfg.blocks;
241 	int j, blocks_count = ssa->cfg.blocks_count;
242 	for (j = 0; j < blocks_count; j++) {
243 		zend_ssa_phi *pi;
244 		zend_op *opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1;
245 		int bt; /* successor block number if a condition is true */
246 		int bf; /* successor block number if a condition is false */
247 
248 		if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0 || blocks[j].len == 0) {
249 			continue;
250 		}
251 		/* the last instruction of basic block is conditional branch,
252 		 * based on comparison of CV(s)
253 		 */
254 		switch (opline->opcode) {
255 			case ZEND_JMPZ:
256 			case ZEND_JMPZNZ:
257 				bf = blocks[j].successors[0];
258 				bt = blocks[j].successors[1];
259 				break;
260 			case ZEND_JMPNZ:
261 				bt = blocks[j].successors[0];
262 				bf = blocks[j].successors[1];
263 				break;
264 			default:
265 				continue;
266 		}
267 		if (opline->op1_type == IS_TMP_VAR &&
268 		    ((opline-1)->opcode == ZEND_IS_EQUAL ||
269 		     (opline-1)->opcode == ZEND_IS_NOT_EQUAL ||
270 		     (opline-1)->opcode == ZEND_IS_SMALLER ||
271 		     (opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) &&
272 		    opline->op1.var == (opline-1)->result.var) {
273 			int  var1 = -1;
274 			int  var2 = -1;
275 			zend_long val1 = 0;
276 			zend_long val2 = 0;
277 //			long val = 0;
278 
279 			if ((opline-1)->op1_type == IS_CV) {
280 				var1 = EX_VAR_TO_NUM((opline-1)->op1.var);
281 			} else if ((opline-1)->op1_type == IS_TMP_VAR) {
282 				var1 = find_adjusted_tmp_var(
283 					op_array, build_flags, opline, (opline-1)->op1.var, &val2);
284 			}
285 
286 			if ((opline-1)->op2_type == IS_CV) {
287 				var2 = EX_VAR_TO_NUM((opline-1)->op2.var);
288 			} else if ((opline-1)->op2_type == IS_TMP_VAR) {
289 				var2 = find_adjusted_tmp_var(
290 					op_array, build_flags, opline, (opline-1)->op2.var, &val1);
291 			}
292 
293 			if (var1 >= 0 && var2 >= 0) {
294 				if (!sub_will_overflow(val1, val2) && !sub_will_overflow(val2, val1)) {
295 					zend_long tmp = val1;
296 					val1 -= val2;
297 					val2 -= tmp;
298 				} else {
299 					var1 = -1;
300 					var2 = -1;
301 				}
302 			} else if (var1 >= 0 && var2 < 0) {
303 				zend_long add_val2 = 0;
304 				if ((opline-1)->op2_type == IS_CONST) {
305 					zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS));
306 
307 					if (Z_TYPE_P(zv) == IS_LONG) {
308 						add_val2 = Z_LVAL_P(zv);
309 					} else if (Z_TYPE_P(zv) == IS_FALSE) {
310 						add_val2 = 0;
311 					} else if (Z_TYPE_P(zv) == IS_TRUE) {
312 						add_val2 = 1;
313 					} else {
314 						var1 = -1;
315 					}
316 				} else {
317 					var1 = -1;
318 				}
319 				if (!add_will_overflow(val2, add_val2)) {
320 					val2 += add_val2;
321 				} else {
322 					var1 = -1;
323 				}
324 			} else if (var1 < 0 && var2 >= 0) {
325 				zend_long add_val1 = 0;
326 				if ((opline-1)->op1_type == IS_CONST) {
327 					zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS));
328 					if (Z_TYPE_P(zv) == IS_LONG) {
329 						add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS)));
330 					} else if (Z_TYPE_P(zv) == IS_FALSE) {
331 						add_val1 = 0;
332 					} else if (Z_TYPE_P(zv) == IS_TRUE) {
333 						add_val1 = 1;
334 					} else {
335 						var2 = -1;
336 					}
337 				} else {
338 					var2 = -1;
339 				}
340 				if (!add_will_overflow(val1, add_val1)) {
341 					val1 += add_val1;
342 				} else {
343 					var2 = -1;
344 				}
345 			}
346 
347 			if (var1 >= 0) {
348 				if ((opline-1)->opcode == ZEND_IS_EQUAL) {
349 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
350 						pi_range_equals(pi, var2, val2);
351 					}
352 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
353 						pi_range_not_equals(pi, var2, val2);
354 					}
355 				} else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
356 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
357 						pi_range_equals(pi, var2, val2);
358 					}
359 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
360 						pi_range_not_equals(pi, var2, val2);
361 					}
362 				} else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
363 					if (val2 > ZEND_LONG_MIN) {
364 						if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
365 							pi_range_max(pi, var2, val2-1);
366 						}
367 					}
368 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
369 						pi_range_min(pi, var2, val2);
370 					}
371 				} else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
372 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
373 						pi_range_max(pi, var2, val2);
374 					}
375 					if (val2 < ZEND_LONG_MAX) {
376 						if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
377 							pi_range_min(pi, var2, val2+1);
378 						}
379 					}
380 				}
381 			}
382 			if (var2 >= 0) {
383 				if((opline-1)->opcode == ZEND_IS_EQUAL) {
384 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
385 						pi_range_equals(pi, var1, val1);
386 					}
387 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
388 						pi_range_not_equals(pi, var1, val1);
389 					}
390 				} else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
391 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
392 						pi_range_equals(pi, var1, val1);
393 					}
394 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
395 						pi_range_not_equals(pi, var1, val1);
396 					}
397 				} else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
398 					if (val1 < ZEND_LONG_MAX) {
399 						if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
400 							pi_range_min(pi, var1, val1+1);
401 						}
402 					}
403 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
404 						pi_range_max(pi, var1, val1);
405 					}
406 				} else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
407 					if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
408 						pi_range_min(pi, var1, val1);
409 					}
410 					if (val1 > ZEND_LONG_MIN) {
411 						if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
412 							pi_range_max(pi, var1, val1-1);
413 						}
414 					}
415 				}
416 			}
417 		} else if (opline->op1_type == IS_TMP_VAR &&
418 		           ((opline-1)->opcode == ZEND_POST_INC ||
419 		            (opline-1)->opcode == ZEND_POST_DEC) &&
420 		           opline->op1.var == (opline-1)->result.var &&
421 		           (opline-1)->op1_type == IS_CV) {
422 			int var = EX_VAR_TO_NUM((opline-1)->op1.var);
423 
424 			if ((opline-1)->opcode == ZEND_POST_DEC) {
425 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
426 					pi_range_equals(pi, -1, -1);
427 				}
428 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
429 					pi_range_not_equals(pi, -1, -1);
430 				}
431 			} else if ((opline-1)->opcode == ZEND_POST_INC) {
432 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
433 					pi_range_equals(pi, -1, 1);
434 				}
435 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
436 					pi_range_not_equals(pi, -1, 1);
437 				}
438 			}
439 		} else if (opline->op1_type == IS_VAR &&
440 		           ((opline-1)->opcode == ZEND_PRE_INC ||
441 		            (opline-1)->opcode == ZEND_PRE_DEC) &&
442 		           opline->op1.var == (opline-1)->result.var &&
443 		           (opline-1)->op1_type == IS_CV) {
444 			int var = EX_VAR_TO_NUM((opline-1)->op1.var);
445 
446 			if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
447 				pi_range_equals(pi, -1, 0);
448 			}
449 			/* speculative */
450 			if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
451 				pi_range_not_equals(pi, -1, 0);
452 			}
453 		} else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_TYPE_CHECK &&
454 				   opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) {
455 			int var = EX_VAR_TO_NUM((opline-1)->op1.var);
456 			uint32_t type = (opline-1)->extended_value;
457 			if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
458 				pi_type_mask(pi, mask_for_type_check(type));
459 			}
460 			if (type != MAY_BE_RESOURCE) {
461 				/* is_resource() may return false for closed resources */
462 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
463 					pi_not_type_mask(pi, mask_for_type_check(type));
464 				}
465 			}
466 		} else if (opline->op1_type == IS_TMP_VAR &&
467 				   ((opline-1)->opcode == ZEND_IS_IDENTICAL
468 					|| (opline-1)->opcode == ZEND_IS_NOT_IDENTICAL) &&
469 				   opline->op1.var == (opline-1)->result.var) {
470 			int var;
471 			zval *val;
472 			uint32_t type_mask;
473 			if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) {
474 				var = EX_VAR_TO_NUM((opline-1)->op1.var);
475 				val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS));
476 			} else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) {
477 				var = EX_VAR_TO_NUM((opline-1)->op2.var);
478 				val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS));
479 			} else {
480 				continue;
481 			}
482 
483 			/* We're interested in === null/true/false comparisons here, because they eliminate
484 			 * a type in the false-branch. Other === VAL comparisons are unlikely to be useful. */
485 			if (Z_TYPE_P(val) != IS_NULL && Z_TYPE_P(val) != IS_TRUE && Z_TYPE_P(val) != IS_FALSE) {
486 				continue;
487 			}
488 
489 			type_mask = _const_op_type(val);
490 			if ((opline-1)->opcode == ZEND_IS_IDENTICAL) {
491 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
492 					pi_type_mask(pi, type_mask);
493 				}
494 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
495 					pi_not_type_mask(pi, type_mask);
496 				}
497 			} else {
498 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
499 					pi_type_mask(pi, type_mask);
500 				}
501 				if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
502 					pi_not_type_mask(pi, type_mask);
503 				}
504 			}
505 		} else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_INSTANCEOF &&
506 				   opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV &&
507 				   (opline-1)->op2_type == IS_CONST) {
508 			int var = EX_VAR_TO_NUM((opline-1)->op1.var);
509 			zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS)) + 1);
510 			zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL;
511 			if (!ce) {
512 				ce = zend_hash_find_ptr(CG(class_table), lcname);
513 				if (!ce || ce->type != ZEND_INTERNAL_CLASS) {
514 					continue;
515 				}
516 			}
517 
518 			if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
519 				pi_type_mask(pi, MAY_BE_OBJECT);
520 				pi->constraint.type.ce = ce;
521 			}
522 		}
523 	}
524 }
525 /* }}} */
526 
zend_ssa_rename(const zend_op_array * op_array,uint32_t build_flags,zend_ssa * ssa,int * var,int n)527 static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, int *var, int n) /* {{{ */
528 {
529 	zend_basic_block *blocks = ssa->cfg.blocks;
530 	zend_ssa_block *ssa_blocks = ssa->blocks;
531 	zend_ssa_op *ssa_ops = ssa->ops;
532 	int ssa_vars_count = ssa->vars_count;
533 	int i, j;
534 	zend_op *opline, *end;
535 	int *tmp = NULL;
536 	ALLOCA_FLAG(use_heap);
537 
538 	// FIXME: Can we optimize this copying out in some cases?
539 	if (blocks[n].next_child >= 0) {
540 		tmp = do_alloca(sizeof(int) * (op_array->last_var + op_array->T), use_heap);
541 		memcpy(tmp, var, sizeof(int) * (op_array->last_var + op_array->T));
542 		var = tmp;
543 	}
544 
545 	if (ssa_blocks[n].phis) {
546 		zend_ssa_phi *phi = ssa_blocks[n].phis;
547 		do {
548 			if (phi->ssa_var < 0) {
549 				phi->ssa_var = ssa_vars_count;
550 				var[phi->var] = ssa_vars_count;
551 				ssa_vars_count++;
552 			} else {
553 				var[phi->var] = phi->ssa_var;
554 			}
555 			phi = phi->next;
556 		} while (phi);
557 	}
558 
559 	opline = op_array->opcodes + blocks[n].start;
560 	end = opline + blocks[n].len;
561 	for (; opline < end; opline++) {
562 		uint32_t k = opline - op_array->opcodes;
563 		if (opline->opcode != ZEND_OP_DATA) {
564 			zend_op *next = opline + 1;
565 			if (next < end && next->opcode == ZEND_OP_DATA) {
566 				if (next->op1_type == IS_CV) {
567 					ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
568 					//USE_SSA_VAR(next->op1.var);
569 				} else if (next->op1_type & (IS_VAR|IS_TMP_VAR)) {
570 					ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
571 					//USE_SSA_VAR(op_array->last_var + next->op1.var);
572 				}
573 				if (next->op2_type == IS_CV) {
574 					ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
575 					//USE_SSA_VAR(next->op2.var);
576 				} else if (next->op2_type & (IS_VAR|IS_TMP_VAR)) {
577 					ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
578 					//USE_SSA_VAR(op_array->last_var + next->op2.var);
579 				}
580 			}
581 			if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
582 				ssa_ops[k].op1_use = var[EX_VAR_TO_NUM(opline->op1.var)];
583 				//USE_SSA_VAR(op_array->last_var + opline->op1.var)
584 			}
585 			if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
586 				if (opline->op2_type == IS_CV) {
587 					ssa_ops[k].op2_use = var[EX_VAR_TO_NUM(opline->op2.var)];
588 				}
589 				ssa_ops[k].op2_def = ssa_vars_count;
590 				var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
591 				ssa_vars_count++;
592 				//NEW_SSA_VAR(opline->op2.var)
593 			} else if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
594 				ssa_ops[k].op2_use = var[EX_VAR_TO_NUM(opline->op2.var)];
595 				//USE_SSA_VAR(op_array->last_var + opline->op2.var)
596 			}
597 			switch (opline->opcode) {
598 				case ZEND_ASSIGN:
599 					if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op2_type == IS_CV) {
600 						ssa_ops[k].op2_def = ssa_vars_count;
601 						var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
602 						ssa_vars_count++;
603 						//NEW_SSA_VAR(opline->op2.var)
604 					}
605 					if (opline->op1_type == IS_CV) {
606 						ssa_ops[k].op1_def = ssa_vars_count;
607 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
608 						ssa_vars_count++;
609 						//NEW_SSA_VAR(opline->op1.var)
610 					}
611 					break;
612 				case ZEND_ASSIGN_REF:
613 //TODO: ???
614 					if (opline->op2_type == IS_CV) {
615 						ssa_ops[k].op2_def = ssa_vars_count;
616 						var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
617 						ssa_vars_count++;
618 						//NEW_SSA_VAR(opline->op2.var)
619 					}
620 					if (opline->op1_type == IS_CV) {
621 						ssa_ops[k].op1_def = ssa_vars_count;
622 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
623 						ssa_vars_count++;
624 						//NEW_SSA_VAR(opline->op1.var)
625 					}
626 					break;
627 				case ZEND_BIND_GLOBAL:
628 				case ZEND_BIND_STATIC:
629 					if (opline->op1_type == IS_CV) {
630 						ssa_ops[k].op1_def = ssa_vars_count;
631 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
632 						ssa_vars_count++;
633 						//NEW_SSA_VAR(opline->op1.var)
634 					}
635 					break;
636 				case ZEND_ASSIGN_DIM:
637 				case ZEND_ASSIGN_OBJ:
638 					if (opline->op1_type == IS_CV) {
639 						ssa_ops[k].op1_def = ssa_vars_count;
640 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
641 						ssa_vars_count++;
642 						//NEW_SSA_VAR(opline->op1.var)
643 					}
644 					if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
645 						ssa_ops[k + 1].op1_def = ssa_vars_count;
646 						var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
647 						ssa_vars_count++;
648 						//NEW_SSA_VAR(next->op1.var)
649 					}
650 					break;
651 				case ZEND_PRE_INC_OBJ:
652 				case ZEND_PRE_DEC_OBJ:
653 				case ZEND_POST_INC_OBJ:
654 				case ZEND_POST_DEC_OBJ:
655 					if (opline->op1_type == IS_CV) {
656 						ssa_ops[k].op1_def = ssa_vars_count;
657 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
658 						ssa_vars_count++;
659 						//NEW_SSA_VAR(opline->op1.var)
660 					}
661 					break;
662 				case ZEND_ADD_ARRAY_ELEMENT:
663 					ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
664 				case ZEND_INIT_ARRAY:
665 					if (((build_flags & ZEND_SSA_RC_INFERENCE)
666 								|| (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
667 							&& opline->op1_type == IS_CV) {
668 						ssa_ops[k].op1_def = ssa_vars_count;
669 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
670 						ssa_vars_count++;
671 						//NEW_SSA_VAR(opline+->op1.var)
672 					}
673 					break;
674 				case ZEND_SEND_VAR:
675 				case ZEND_CAST:
676 				case ZEND_QM_ASSIGN:
677 				case ZEND_JMP_SET:
678 				case ZEND_COALESCE:
679 					if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
680 						ssa_ops[k].op1_def = ssa_vars_count;
681 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
682 						ssa_vars_count++;
683 						//NEW_SSA_VAR(opline->op1.var)
684 					}
685 					break;
686 				case ZEND_SEND_VAR_NO_REF:
687 				case ZEND_SEND_VAR_NO_REF_EX:
688 				case ZEND_SEND_VAR_EX:
689 				case ZEND_SEND_FUNC_ARG:
690 				case ZEND_SEND_REF:
691 				case ZEND_SEND_UNPACK:
692 				case ZEND_FE_RESET_RW:
693 				case ZEND_MAKE_REF:
694 					if (opline->op1_type == IS_CV) {
695 						ssa_ops[k].op1_def = ssa_vars_count;
696 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
697 						ssa_vars_count++;
698 						//NEW_SSA_VAR(opline->op1.var)
699 					}
700 					break;
701 				case ZEND_FE_RESET_R:
702 					if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
703 						ssa_ops[k].op1_def = ssa_vars_count;
704 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
705 						ssa_vars_count++;
706 						//NEW_SSA_VAR(opline->op1.var)
707 					}
708 					break;
709 				case ZEND_ASSIGN_ADD:
710 				case ZEND_ASSIGN_SUB:
711 				case ZEND_ASSIGN_MUL:
712 				case ZEND_ASSIGN_DIV:
713 				case ZEND_ASSIGN_MOD:
714 				case ZEND_ASSIGN_SL:
715 				case ZEND_ASSIGN_SR:
716 				case ZEND_ASSIGN_CONCAT:
717 				case ZEND_ASSIGN_BW_OR:
718 				case ZEND_ASSIGN_BW_AND:
719 				case ZEND_ASSIGN_BW_XOR:
720 				case ZEND_ASSIGN_POW:
721 				case ZEND_PRE_INC:
722 				case ZEND_PRE_DEC:
723 				case ZEND_POST_INC:
724 				case ZEND_POST_DEC:
725 					if (opline->op1_type == IS_CV) {
726 						ssa_ops[k].op1_def = ssa_vars_count;
727 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
728 						ssa_vars_count++;
729 						//NEW_SSA_VAR(opline->op1.var)
730 					}
731 					break;
732 				case ZEND_UNSET_CV:
733 					ssa_ops[k].op1_def = ssa_vars_count;
734 					var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
735 					ssa_vars_count++;
736 					break;
737 				case ZEND_UNSET_DIM:
738 				case ZEND_UNSET_OBJ:
739 				case ZEND_FETCH_DIM_W:
740 				case ZEND_FETCH_DIM_RW:
741 				case ZEND_FETCH_DIM_FUNC_ARG:
742 				case ZEND_FETCH_DIM_UNSET:
743 				case ZEND_FETCH_OBJ_W:
744 				case ZEND_FETCH_OBJ_RW:
745 				case ZEND_FETCH_OBJ_FUNC_ARG:
746 				case ZEND_FETCH_OBJ_UNSET:
747 				case ZEND_FETCH_LIST_W:
748 					if (opline->op1_type == IS_CV) {
749 						ssa_ops[k].op1_def = ssa_vars_count;
750 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
751 						ssa_vars_count++;
752 						//NEW_SSA_VAR(opline->op1.var)
753 					}
754 					break;
755 				case ZEND_BIND_LEXICAL:
756 					if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
757 						ssa_ops[k].op2_def = ssa_vars_count;
758 						var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
759 						ssa_vars_count++;
760 					}
761 					break;
762 				case ZEND_YIELD:
763 					if (opline->op1_type == IS_CV
764 							&& ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
765 								|| (build_flags & ZEND_SSA_RC_INFERENCE))) {
766 						ssa_ops[k].op1_def = ssa_vars_count;
767 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
768 						ssa_vars_count++;
769 					}
770 					break;
771 				case ZEND_VERIFY_RETURN_TYPE:
772 					if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
773 						ssa_ops[k].op1_def = ssa_vars_count;
774 						var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
775 						ssa_vars_count++;
776 						//NEW_SSA_VAR(opline->op1.var)
777 					}
778 					break;
779 				default:
780 					break;
781 			}
782 			if (opline->result_type == IS_CV) {
783 				if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
784 				 && opline->opcode != ZEND_RECV) {
785 					ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
786 				}
787 				ssa_ops[k].result_def = ssa_vars_count;
788 				var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
789 				ssa_vars_count++;
790 				//NEW_SSA_VAR(opline->result.var)
791 			} else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
792 				ssa_ops[k].result_def = ssa_vars_count;
793 				var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
794 				ssa_vars_count++;
795 				//NEW_SSA_VAR(op_array->last_var + opline->result.var)
796 			}
797 		}
798 	}
799 
800 	for (i = 0; i < blocks[n].successors_count; i++) {
801 		int succ = blocks[n].successors[i];
802 		zend_ssa_phi *p;
803 		for (p = ssa_blocks[succ].phis; p; p = p->next) {
804 			if (p->pi == n) {
805 				/* e-SSA Pi */
806 				if (p->has_range_constraint) {
807 					if (p->constraint.range.min_var >= 0) {
808 						p->constraint.range.min_ssa_var = var[p->constraint.range.min_var];
809 					}
810 					if (p->constraint.range.max_var >= 0) {
811 						p->constraint.range.max_ssa_var = var[p->constraint.range.max_var];
812 					}
813 				}
814 				for (j = 0; j < blocks[succ].predecessors_count; j++) {
815 					p->sources[j] = var[p->var];
816 				}
817 				if (p->ssa_var < 0) {
818 					p->ssa_var = ssa_vars_count;
819 					ssa_vars_count++;
820 				}
821 			} else if (p->pi < 0) {
822 				/* Normal Phi */
823 				for (j = 0; j < blocks[succ].predecessors_count; j++)
824 					if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
825 						break;
826 					}
827 				ZEND_ASSERT(j < blocks[succ].predecessors_count);
828 				p->sources[j] = var[p->var];
829 			}
830 		}
831 		for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {
832 			if (p->pi == n) {
833 				zend_ssa_phi *q = p->next;
834 				while (q) {
835 					if (q->pi < 0 && q->var == p->var) {
836 						for (j = 0; j < blocks[succ].predecessors_count; j++) {
837 							if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
838 								break;
839 							}
840 						}
841 						ZEND_ASSERT(j < blocks[succ].predecessors_count);
842 						q->sources[j] = p->ssa_var;
843 					}
844 					q = q->next;
845 				}
846 			}
847 		}
848 	}
849 
850 	ssa->vars_count = ssa_vars_count;
851 
852 	j = blocks[n].children;
853 	while (j >= 0) {
854 		// FIXME: Tail call optimization?
855 		if (zend_ssa_rename(op_array, build_flags, ssa, var, j) != SUCCESS)
856 			return FAILURE;
857 		j = blocks[j].next_child;
858 	}
859 
860 	if (tmp) {
861 		free_alloca(tmp, use_heap);
862 	}
863 
864 	return SUCCESS;
865 }
866 /* }}} */
867 
zend_build_ssa(zend_arena ** arena,const zend_script * script,const zend_op_array * op_array,uint32_t build_flags,zend_ssa * ssa)868 int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa) /* {{{ */
869 {
870 	zend_basic_block *blocks = ssa->cfg.blocks;
871 	zend_ssa_block *ssa_blocks;
872 	int blocks_count = ssa->cfg.blocks_count;
873 	uint32_t set_size;
874 	zend_bitset def, in, phi;
875 	int *var = NULL;
876 	int i, j, k, changed;
877 	zend_dfg dfg;
878 	ALLOCA_FLAG(dfg_use_heap)
879 	ALLOCA_FLAG(var_use_heap)
880 
881 	if ((blocks_count * (op_array->last_var + op_array->T)) > 4 * 1024 * 1024) {
882 	    /* Don't buld SSA for very big functions */
883 		return FAILURE;
884 	}
885 
886 	ssa->rt_constants = (build_flags & ZEND_RT_CONSTANTS);
887 	ssa_blocks = zend_arena_calloc(arena, blocks_count, sizeof(zend_ssa_block));
888 	ssa->blocks = ssa_blocks;
889 
890 	/* Compute Variable Liveness */
891 	dfg.vars = op_array->last_var + op_array->T;
892 	dfg.size = set_size = zend_bitset_len(dfg.vars);
893 	dfg.tmp = do_alloca((set_size * sizeof(zend_ulong)) * (blocks_count * 4 + 1), dfg_use_heap);
894 	memset(dfg.tmp, 0, (set_size * sizeof(zend_ulong)) * (blocks_count * 4 + 1));
895 	dfg.def = dfg.tmp + set_size;
896 	dfg.use = dfg.def + set_size * blocks_count;
897 	dfg.in  = dfg.use + set_size * blocks_count;
898 	dfg.out = dfg.in  + set_size * blocks_count;
899 
900 	if (zend_build_dfg(op_array, &ssa->cfg, &dfg, build_flags) != SUCCESS) {
901 		free_alloca(dfg.tmp, dfg_use_heap);
902 		return FAILURE;
903 	}
904 
905 	if (build_flags & ZEND_SSA_DEBUG_LIVENESS) {
906 		zend_dump_dfg(op_array, &ssa->cfg, &dfg);
907 	}
908 
909 	def = dfg.def;
910 	in  = dfg.in;
911 
912 	/* Reuse the "use" set, as we no longer need it */
913 	phi = dfg.use;
914 	zend_bitset_clear(phi, set_size * blocks_count);
915 
916 	/* Place e-SSA pis. This will add additional "def" points, so it must
917 	 * happen before def propagation. */
918 	place_essa_pis(arena, script, op_array, build_flags, ssa, &dfg);
919 
920 	/* SSA construction, Step 1: Propagate "def" sets in merge points */
921 	do {
922 		changed = 0;
923 		for (j = 0; j < blocks_count; j++) {
924 			zend_bitset def_j = def + j * set_size, phi_j = phi + j * set_size;
925 			if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
926 				continue;
927 			}
928 			if (blocks[j].predecessors_count > 1) {
929 				if (blocks[j].flags & ZEND_BB_IRREDUCIBLE_LOOP) {
930 					/* Prevent any values from flowing into irreducible loops by
931 					   replacing all incoming values with explicit phis.  The
932 					   register allocator depends on this property.  */
933 					zend_bitset_union(phi_j, in + (j * set_size), set_size);
934 				} else {
935 					for (k = 0; k < blocks[j].predecessors_count; k++) {
936 						i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k];
937 						while (i != -1 && i != blocks[j].idom) {
938 							zend_bitset_union_with_intersection(
939 								phi_j, phi_j, def + (i * set_size), in + (j * set_size), set_size);
940 							i = blocks[i].idom;
941 						}
942 					}
943 				}
944 				if (!zend_bitset_subset(phi_j, def_j, set_size)) {
945 					zend_bitset_union(def_j, phi_j, set_size);
946 					changed = 1;
947 				}
948 			}
949 		}
950 	} while (changed);
951 
952 	/* SSA construction, Step 2: Phi placement based on Dominance Frontiers */
953 	var = do_alloca(sizeof(int) * (op_array->last_var + op_array->T), var_use_heap);
954 	if (!var) {
955 		free_alloca(dfg.tmp, dfg_use_heap);
956 		return FAILURE;
957 	}
958 
959 	for (j = 0; j < blocks_count; j++) {
960 		if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
961 			continue;
962 		}
963 		if (!zend_bitset_empty(phi + j * set_size, set_size)) {
964 			ZEND_BITSET_REVERSE_FOREACH(phi + j * set_size, set_size, i) {
965 				zend_ssa_phi *phi = zend_arena_calloc(arena, 1,
966 					ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
967 					ZEND_MM_ALIGNED_SIZE(sizeof(int) * blocks[j].predecessors_count) +
968 					sizeof(void*) * blocks[j].predecessors_count);
969 
970 				phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
971 				memset(phi->sources, 0xff, sizeof(int) * blocks[j].predecessors_count);
972 				phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[j].predecessors_count));
973 
974 				phi->pi = -1;
975 				phi->var = i;
976 				phi->ssa_var = -1;
977 
978 				/* Place phis after pis */
979 				{
980 					zend_ssa_phi **pp = &ssa_blocks[j].phis;
981 					while (*pp) {
982 						if ((*pp)->pi < 0) {
983 							break;
984 						}
985 						pp = &(*pp)->next;
986 					}
987 					phi->next = *pp;
988 					*pp = phi;
989 				}
990 			} ZEND_BITSET_FOREACH_END();
991 		}
992 	}
993 
994 	if (build_flags & ZEND_SSA_DEBUG_PHI_PLACEMENT) {
995 		zend_dump_phi_placement(op_array, ssa);
996 	}
997 
998 	/* SSA construction, Step 3: Renaming */
999 	ssa->ops = zend_arena_calloc(arena, op_array->last, sizeof(zend_ssa_op));
1000 	memset(ssa->ops, 0xff, op_array->last * sizeof(zend_ssa_op));
1001 	memset(var + op_array->last_var, 0xff, op_array->T * sizeof(int));
1002 	/* Create uninitialized SSA variables for each CV */
1003 	for (j = 0; j < op_array->last_var; j++) {
1004 		var[j] = j;
1005 	}
1006 	ssa->vars_count = op_array->last_var;
1007 	if (zend_ssa_rename(op_array, build_flags, ssa, var, 0) != SUCCESS) {
1008 		free_alloca(var, var_use_heap);
1009 		free_alloca(dfg.tmp, dfg_use_heap);
1010 		return FAILURE;
1011 	}
1012 
1013 	free_alloca(var, var_use_heap);
1014 	free_alloca(dfg.tmp, dfg_use_heap);
1015 
1016 	return SUCCESS;
1017 }
1018 /* }}} */
1019 
zend_ssa_compute_use_def_chains(zend_arena ** arena,const zend_op_array * op_array,zend_ssa * ssa)1020 int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
1021 {
1022 	zend_ssa_var *ssa_vars;
1023 	int i;
1024 
1025 	if (!ssa->vars) {
1026 		ssa->vars = zend_arena_calloc(arena, ssa->vars_count, sizeof(zend_ssa_var));
1027 	}
1028 	ssa_vars = ssa->vars;
1029 
1030 	for (i = 0; i < op_array->last_var; i++) {
1031 		ssa_vars[i].var = i;
1032 		ssa_vars[i].scc = -1;
1033 		ssa_vars[i].definition = -1;
1034 		ssa_vars[i].use_chain = -1;
1035 	}
1036 	for (i = op_array->last_var; i < ssa->vars_count; i++) {
1037 		ssa_vars[i].var = -1;
1038 		ssa_vars[i].scc = -1;
1039 		ssa_vars[i].definition = -1;
1040 		ssa_vars[i].use_chain = -1;
1041 	}
1042 
1043 	for (i = op_array->last - 1; i >= 0; i--) {
1044 		zend_ssa_op *op = ssa->ops + i;
1045 
1046 		if (op->op1_use >= 0) {
1047 			op->op1_use_chain = ssa_vars[op->op1_use].use_chain;
1048 			ssa_vars[op->op1_use].use_chain = i;
1049 		}
1050 		if (op->op2_use >= 0 && op->op2_use != op->op1_use) {
1051 			op->op2_use_chain = ssa_vars[op->op2_use].use_chain;
1052 			ssa_vars[op->op2_use].use_chain = i;
1053 		}
1054 		if (op->result_use >= 0 && op->result_use != op->op1_use && op->result_use != op->op2_use) {
1055 			op->res_use_chain = ssa_vars[op->result_use].use_chain;
1056 			ssa_vars[op->result_use].use_chain = i;
1057 		}
1058 		if (op->op1_def >= 0) {
1059 			ssa_vars[op->op1_def].var = EX_VAR_TO_NUM(op_array->opcodes[i].op1.var);
1060 			ssa_vars[op->op1_def].definition = i;
1061 		}
1062 		if (op->op2_def >= 0) {
1063 			ssa_vars[op->op2_def].var = EX_VAR_TO_NUM(op_array->opcodes[i].op2.var);
1064 			ssa_vars[op->op2_def].definition = i;
1065 		}
1066 		if (op->result_def >= 0) {
1067 			ssa_vars[op->result_def].var = EX_VAR_TO_NUM(op_array->opcodes[i].result.var);
1068 			ssa_vars[op->result_def].definition = i;
1069 		}
1070 	}
1071 
1072 	for (i = 0; i < ssa->cfg.blocks_count; i++) {
1073 		zend_ssa_phi *phi = ssa->blocks[i].phis;
1074 		while (phi) {
1075 			phi->block = i;
1076 			ssa_vars[phi->ssa_var].var = phi->var;
1077 			ssa_vars[phi->ssa_var].definition_phi = phi;
1078 			if (phi->pi >= 0) {
1079 				zend_ssa_phi *p;
1080 
1081 				ZEND_ASSERT(phi->sources[0] >= 0);
1082 				p = ssa_vars[phi->sources[0]].phi_use_chain;
1083 				while (p && p != phi) {
1084 					p = zend_ssa_next_use_phi(ssa, phi->sources[0], p);
1085 				}
1086 				if (!p) {
1087 					phi->use_chains[0] = ssa_vars[phi->sources[0]].phi_use_chain;
1088 					ssa_vars[phi->sources[0]].phi_use_chain = phi;
1089 				}
1090 				if (phi->has_range_constraint) {
1091 					/* min and max variables can't be used together */
1092 					zend_ssa_range_constraint *constraint = &phi->constraint.range;
1093 					if (constraint->min_ssa_var >= 0) {
1094 						phi->sym_use_chain = ssa_vars[constraint->min_ssa_var].sym_use_chain;
1095 						ssa_vars[constraint->min_ssa_var].sym_use_chain = phi;
1096 					} else if (constraint->max_ssa_var >= 0) {
1097 						phi->sym_use_chain = ssa_vars[constraint->max_ssa_var].sym_use_chain;
1098 						ssa_vars[constraint->max_ssa_var].sym_use_chain = phi;
1099 					}
1100 				}
1101 			} else {
1102 				int j;
1103 
1104 				for (j = 0; j < ssa->cfg.blocks[i].predecessors_count; j++) {
1105 					zend_ssa_phi *p;
1106 
1107 					ZEND_ASSERT(phi->sources[j] >= 0);
1108 					p = ssa_vars[phi->sources[j]].phi_use_chain;
1109 					while (p && p != phi) {
1110 						p = zend_ssa_next_use_phi(ssa, phi->sources[j], p);
1111 					}
1112 					if (!p) {
1113 						phi->use_chains[j] = ssa_vars[phi->sources[j]].phi_use_chain;
1114 						ssa_vars[phi->sources[j]].phi_use_chain = phi;
1115 					}
1116 				}
1117 			}
1118 			phi = phi->next;
1119 		}
1120 	}
1121 
1122 	/* Mark indirectly accessed variables */
1123 	for (i = 0; i < op_array->last_var; i++) {
1124 		if ((ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
1125 			ssa_vars[i].alias = SYMTABLE_ALIAS;
1126 		} else if (zend_string_equals_literal(op_array->vars[i], "php_errormsg")) {
1127 			ssa_vars[i].alias = PHP_ERRORMSG_ALIAS;
1128 		} else if (zend_string_equals_literal(op_array->vars[i], "http_response_header")) {
1129 			ssa_vars[i].alias = HTTP_RESPONSE_HEADER_ALIAS;
1130 		}
1131 	}
1132 	for (i = op_array->last_var; i < ssa->vars_count; i++) {
1133 		if (ssa_vars[i].var < op_array->last_var) {
1134 			ssa_vars[i].alias = ssa_vars[ssa_vars[i].var].alias;
1135 		}
1136 	}
1137 
1138 	return SUCCESS;
1139 }
1140 /* }}} */
1141 
zend_ssa_unlink_use_chain(zend_ssa * ssa,int op,int var)1142 int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var) /* {{{ */
1143 {
1144 	if (ssa->vars[var].use_chain == op) {
1145 		ssa->vars[var].use_chain = zend_ssa_next_use(ssa->ops, var, op);
1146 		return 1;
1147 	} else {
1148 		int use = ssa->vars[var].use_chain;
1149 
1150 		while (use >= 0) {
1151 			if (ssa->ops[use].result_use == var) {
1152 				if (ssa->ops[use].res_use_chain == op) {
1153 					ssa->ops[use].res_use_chain = zend_ssa_next_use(ssa->ops, var, op);
1154 					return 1;
1155 				} else {
1156 					use = ssa->ops[use].res_use_chain;
1157 				}
1158 			} else if (ssa->ops[use].op1_use == var) {
1159 				if (ssa->ops[use].op1_use_chain == op) {
1160 					ssa->ops[use].op1_use_chain = zend_ssa_next_use(ssa->ops, var, op);
1161 					return 1;
1162 				} else {
1163 					use = ssa->ops[use].op1_use_chain;
1164 				}
1165 			} else if (ssa->ops[use].op2_use == var) {
1166 				if (ssa->ops[use].op2_use_chain == op) {
1167 					ssa->ops[use].op2_use_chain = zend_ssa_next_use(ssa->ops, var, op);
1168 					return 1;
1169 				} else {
1170 					use = ssa->ops[use].op2_use_chain;
1171 				}
1172 			} else {
1173 				break;
1174 			}
1175 		}
1176 		/* something wrong */
1177 		ZEND_ASSERT(0);
1178 		return 0;
1179 	}
1180 }
1181 /* }}} */
1182 
zend_ssa_remove_instr(zend_ssa * ssa,zend_op * opline,zend_ssa_op * ssa_op)1183 void zend_ssa_remove_instr(zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op) /* {{{ */
1184 {
1185 	if (ssa_op->result_use >= 0) {
1186 		zend_ssa_unlink_use_chain(ssa, ssa_op - ssa->ops, ssa_op->result_use);
1187 		ssa_op->result_use = -1;
1188 		ssa_op->res_use_chain = -1;
1189 	}
1190 	if (ssa_op->op1_use >= 0) {
1191 		if (ssa_op->op1_use != ssa_op->op2_use) {
1192 			zend_ssa_unlink_use_chain(ssa, ssa_op - ssa->ops, ssa_op->op1_use);
1193 		} else {
1194 			ssa_op->op2_use_chain = ssa_op->op1_use_chain;
1195 		}
1196 		ssa_op->op1_use = -1;
1197 		ssa_op->op1_use_chain = -1;
1198 	}
1199 	if (ssa_op->op2_use >= 0) {
1200 		zend_ssa_unlink_use_chain(ssa, ssa_op - ssa->ops, ssa_op->op2_use);
1201 		ssa_op->op2_use = -1;
1202 		ssa_op->op2_use_chain = -1;
1203 	}
1204 
1205 	/* We let the caller make sure that all defs are gone */
1206 	ZEND_ASSERT(ssa_op->result_def == -1);
1207 	ZEND_ASSERT(ssa_op->op1_def == -1);
1208 	ZEND_ASSERT(ssa_op->op2_def == -1);
1209 
1210 	MAKE_NOP(opline);
1211 }
1212 /* }}} */
1213 
zend_ssa_next_use_phi_ptr(zend_ssa * ssa,int var,zend_ssa_phi * p)1214 static inline zend_ssa_phi **zend_ssa_next_use_phi_ptr(zend_ssa *ssa, int var, zend_ssa_phi *p) /* {{{ */
1215 {
1216 	if (p->pi >= 0) {
1217 		return &p->use_chains[0];
1218 	} else {
1219 		int j;
1220 		for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
1221 			if (p->sources[j] == var) {
1222 				return &p->use_chains[j];
1223 			}
1224 		}
1225 	}
1226 	ZEND_ASSERT(0);
1227 	return NULL;
1228 }
1229 /* }}} */
1230 
1231 /* May be called even if source is not used in the phi (useful when removing uses in a phi
1232  * with multiple identical operands) */
zend_ssa_remove_use_of_phi_source(zend_ssa * ssa,zend_ssa_phi * phi,int source,zend_ssa_phi * next_use_phi)1233 static inline void zend_ssa_remove_use_of_phi_source(zend_ssa *ssa, zend_ssa_phi *phi, int source, zend_ssa_phi *next_use_phi) /* {{{ */
1234 {
1235 	zend_ssa_phi **cur = &ssa->vars[source].phi_use_chain;
1236 	while (*cur && *cur != phi) {
1237 		cur = zend_ssa_next_use_phi_ptr(ssa, source, *cur);
1238 	}
1239 	if (*cur) {
1240 		*cur = next_use_phi;
1241 	}
1242 }
1243 /* }}} */
1244 
zend_ssa_remove_uses_of_phi_sources(zend_ssa * ssa,zend_ssa_phi * phi)1245 static void zend_ssa_remove_uses_of_phi_sources(zend_ssa *ssa, zend_ssa_phi *phi) /* {{{ */
1246 {
1247 	int source;
1248 	FOREACH_PHI_SOURCE(phi, source) {
1249 		zend_ssa_remove_use_of_phi_source(ssa, phi, source, zend_ssa_next_use_phi(ssa, source, phi));
1250 	} FOREACH_PHI_SOURCE_END();
1251 }
1252 /* }}} */
1253 
zend_ssa_remove_phi_from_block(zend_ssa * ssa,zend_ssa_phi * phi)1254 static void zend_ssa_remove_phi_from_block(zend_ssa *ssa, zend_ssa_phi *phi) /* {{{ */
1255 {
1256 	zend_ssa_block *block = &ssa->blocks[phi->block];
1257 	zend_ssa_phi **cur = &block->phis;
1258 	while (*cur != phi) {
1259 		ZEND_ASSERT(*cur != NULL);
1260 		cur = &(*cur)->next;
1261 	}
1262 	*cur = (*cur)->next;
1263 }
1264 /* }}} */
1265 
zend_ssa_remove_defs_of_instr(zend_ssa * ssa,zend_ssa_op * ssa_op)1266 static inline void zend_ssa_remove_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) /* {{{ */
1267 {
1268 	if (ssa_op->op1_def >= 0) {
1269 		zend_ssa_remove_uses_of_var(ssa, ssa_op->op1_def);
1270 		zend_ssa_remove_op1_def(ssa, ssa_op);
1271 	}
1272 	if (ssa_op->op2_def >= 0) {
1273 		zend_ssa_remove_uses_of_var(ssa, ssa_op->op2_def);
1274 		zend_ssa_remove_op2_def(ssa, ssa_op);
1275 	}
1276 	if (ssa_op->result_def >= 0) {
1277 		zend_ssa_remove_uses_of_var(ssa, ssa_op->result_def);
1278 		zend_ssa_remove_result_def(ssa, ssa_op);
1279 	}
1280 }
1281 /* }}} */
1282 
zend_ssa_remove_phi_source(zend_ssa * ssa,zend_ssa_phi * phi,int pred_offset,int predecessors_count)1283 static inline void zend_ssa_remove_phi_source(zend_ssa *ssa, zend_ssa_phi *phi, int pred_offset, int predecessors_count) /* {{{ */
1284 {
1285 	int j, var_num = phi->sources[pred_offset];
1286 	zend_ssa_phi *next_phi = phi->use_chains[pred_offset];
1287 
1288 	predecessors_count--;
1289 	if (pred_offset < predecessors_count) {
1290 		memmove(phi->sources + pred_offset, phi->sources + pred_offset + 1, (predecessors_count - pred_offset) * sizeof(uint32_t));
1291 		memmove(phi->use_chains + pred_offset, phi->use_chains + pred_offset + 1, (predecessors_count - pred_offset) * sizeof(zend_ssa_phi*));
1292 	}
1293 
1294 	/* Check if they same var is used in a different phi operand as well, in this case we don't
1295 	 * need to adjust the use chain (but may have to move the next pointer). */
1296 	for (j = 0; j < predecessors_count; j++) {
1297 		if (phi->sources[j] == var_num) {
1298 			if (j < pred_offset) {
1299 				if (next_phi == NULL) {
1300 					next_phi = phi->use_chains[pred_offset];
1301 				} else {
1302 					ZEND_ASSERT(phi->use_chains[pred_offset] == NULL);
1303 				}
1304 			} else if (j >= pred_offset) {
1305 				phi->use_chains[j] = next_phi;
1306 			}
1307 			return;
1308 		}
1309 	}
1310 
1311 	/* Variable only used in one operand, remove the phi from the use chain. */
1312 	zend_ssa_remove_use_of_phi_source(ssa, phi, var_num, next_phi);
1313 }
1314 /* }}} */
1315 
zend_ssa_remove_phi(zend_ssa * ssa,zend_ssa_phi * phi)1316 void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi) /* {{{ */
1317 {
1318 	ZEND_ASSERT(phi->ssa_var >= 0);
1319 	ZEND_ASSERT(ssa->vars[phi->ssa_var].use_chain < 0
1320 		&& ssa->vars[phi->ssa_var].phi_use_chain == NULL);
1321 	zend_ssa_remove_uses_of_phi_sources(ssa, phi);
1322 	zend_ssa_remove_phi_from_block(ssa, phi);
1323 	ssa->vars[phi->ssa_var].definition_phi = NULL;
1324 	phi->ssa_var = -1;
1325 }
1326 /* }}} */
1327 
zend_ssa_remove_uses_of_var(zend_ssa * ssa,int var_num)1328 void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num) /* {{{ */
1329 {
1330 	zend_ssa_var *var = &ssa->vars[var_num];
1331 	zend_ssa_phi *phi;
1332 	int use;
1333 	FOREACH_PHI_USE(var, phi) {
1334 		int i, end = NUM_PHI_SOURCES(phi);
1335 		for (i = 0; i < end; i++) {
1336 			if (phi->sources[i] == var_num) {
1337 				phi->use_chains[i] = NULL;
1338 			}
1339 		}
1340 	} FOREACH_PHI_USE_END();
1341 	var->phi_use_chain = NULL;
1342 	FOREACH_USE(var, use) {
1343 		zend_ssa_op *ssa_op = &ssa->ops[use];
1344 		if (ssa_op->op1_use == var_num) {
1345 			ssa_op->op1_use = -1;
1346 			ssa_op->op1_use_chain = -1;
1347 		}
1348 		if (ssa_op->op2_use == var_num) {
1349 			ssa_op->op2_use = -1;
1350 			ssa_op->op2_use_chain = -1;
1351 		}
1352 		if (ssa_op->result_use == var_num) {
1353 			ssa_op->result_use = -1;
1354 			ssa_op->res_use_chain = -1;
1355 		}
1356 	} FOREACH_USE_END();
1357 	var->use_chain = -1;
1358 }
1359 /* }}} */
1360 
zend_ssa_remove_predecessor(zend_ssa * ssa,int from,int to)1361 void zend_ssa_remove_predecessor(zend_ssa *ssa, int from, int to) /* {{{ */
1362 {
1363 	zend_basic_block *next_block = &ssa->cfg.blocks[to];
1364 	zend_ssa_block *next_ssa_block = &ssa->blocks[to];
1365 	zend_ssa_phi *phi;
1366 	int j;
1367 
1368 	/* Find at which predecessor offset this block is referenced */
1369 	int pred_offset = -1;
1370 	int *predecessors = &ssa->cfg.predecessors[next_block->predecessor_offset];
1371 
1372 	for (j = 0; j < next_block->predecessors_count; j++) {
1373 		if (predecessors[j] == from) {
1374 			pred_offset = j;
1375 			break;
1376 		}
1377 	}
1378 
1379 	/* If there are duplicate successors, the predecessors may have been removed in
1380 	 * a previous iteration already. */
1381 	if (pred_offset == -1) {
1382 		return;
1383 	}
1384 
1385 	/* For phis in successor blocks, remove the operands associated with this block */
1386 	for (phi = next_ssa_block->phis; phi; phi = phi->next) {
1387 		if (phi->pi >= 0) {
1388 			if (phi->pi == from) {
1389 				zend_ssa_remove_uses_of_var(ssa, phi->ssa_var);
1390 				zend_ssa_remove_phi(ssa, phi);
1391 			}
1392 		} else {
1393 			ZEND_ASSERT(phi->sources[pred_offset] >= 0);
1394 			zend_ssa_remove_phi_source(ssa, phi, pred_offset, next_block->predecessors_count);
1395 		}
1396 	}
1397 
1398 	/* Remove this predecessor */
1399 	next_block->predecessors_count--;
1400 	if (pred_offset < next_block->predecessors_count) {
1401 		predecessors = &ssa->cfg.predecessors[next_block->predecessor_offset + pred_offset];
1402 		memmove(predecessors, predecessors + 1, (next_block->predecessors_count - pred_offset) * sizeof(uint32_t));
1403 	}
1404 }
1405 /* }}} */
1406 
zend_ssa_remove_block(zend_op_array * op_array,zend_ssa * ssa,int i)1407 void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int i) /* {{{ */
1408 {
1409 	zend_basic_block *block = &ssa->cfg.blocks[i];
1410 	zend_ssa_block *ssa_block = &ssa->blocks[i];
1411 	int *predecessors;
1412 	zend_ssa_phi *phi;
1413 	int j, s;
1414 
1415 	block->flags &= ~ZEND_BB_REACHABLE;
1416 
1417 	/* Removes phis in this block */
1418 	for (phi = ssa_block->phis; phi; phi = phi->next) {
1419 		zend_ssa_remove_uses_of_var(ssa, phi->ssa_var);
1420 		zend_ssa_remove_phi(ssa, phi);
1421 	}
1422 
1423 	/* Remove instructions in this block */
1424 	for (j = block->start; j < block->start + block->len; j++) {
1425 		if (op_array->opcodes[j].opcode == ZEND_NOP) {
1426 			continue;
1427 		}
1428 
1429 		if (op_array->opcodes[j].result_type & (IS_TMP_VAR|IS_VAR)) {
1430 			zend_optimizer_remove_live_range_ex(op_array, op_array->opcodes[j].result.var, j);
1431 		}
1432 		zend_ssa_remove_defs_of_instr(ssa, &ssa->ops[j]);
1433 		zend_ssa_remove_instr(ssa, &op_array->opcodes[j], &ssa->ops[j]);
1434 	}
1435 
1436 	for (s = 0; s < block->successors_count; s++) {
1437 		zend_ssa_remove_predecessor(ssa, i, block->successors[s]);
1438 	}
1439 
1440 	/* Remove successors of predecessors */
1441 	predecessors = &ssa->cfg.predecessors[block->predecessor_offset];
1442 	for (j = 0; j < block->predecessors_count; j++) {
1443 		if (predecessors[j] >= 0) {
1444 			zend_basic_block *prev_block = &ssa->cfg.blocks[predecessors[j]];
1445 
1446 			for (s = 0; s < prev_block->successors_count; s++) {
1447 				if (prev_block->successors[s] == i) {
1448 					memmove(prev_block->successors + s,
1449 							prev_block->successors + s + 1,
1450 							sizeof(int) * (prev_block->successors_count - s - 1));
1451 					prev_block->successors_count--;
1452 					s--;
1453 				}
1454 			}
1455 		}
1456 	}
1457 
1458 	block->successors_count = 0;
1459 	block->predecessors_count = 0;
1460 
1461 	/* Remove from dominators tree */
1462 	if (block->idom >= 0) {
1463 		j = ssa->cfg.blocks[block->idom].children;
1464 		if (j == i) {
1465 			ssa->cfg.blocks[block->idom].children = block->next_child;
1466 		} else if (j >= 0) {
1467 			while (ssa->cfg.blocks[j].next_child >= 0) {
1468 				if (ssa->cfg.blocks[j].next_child == i) {
1469 					ssa->cfg.blocks[j].next_child = block->next_child;
1470 					break;
1471 				}
1472 				j = ssa->cfg.blocks[j].next_child;
1473 			}
1474 		}
1475 	}
1476 	block->idom = -1;
1477 	block->level = -1;
1478 	block->children = -1;
1479 	block->next_child = -1;
1480 }
1481 /* }}} */
1482 
propagate_phi_type_widening(zend_ssa * ssa,int var)1483 static void propagate_phi_type_widening(zend_ssa *ssa, int var) /* {{{ */
1484 {
1485 	zend_ssa_phi *phi;
1486 	FOREACH_PHI_USE(&ssa->vars[var], phi) {
1487 		if (ssa->var_info[var].type & ~ssa->var_info[phi->ssa_var].type) {
1488 			ssa->var_info[phi->ssa_var].type |= ssa->var_info[var].type;
1489 			propagate_phi_type_widening(ssa, phi->ssa_var);
1490 		}
1491 	} FOREACH_PHI_USE_END();
1492 }
1493 /* }}} */
1494 
zend_ssa_rename_var_uses(zend_ssa * ssa,int old,int new,zend_bool update_types)1495 void zend_ssa_rename_var_uses(zend_ssa *ssa, int old, int new, zend_bool update_types) /* {{{ */
1496 {
1497 	zend_ssa_var *old_var = &ssa->vars[old];
1498 	zend_ssa_var *new_var = &ssa->vars[new];
1499 	int use;
1500 	zend_ssa_phi *phi;
1501 
1502 	ZEND_ASSERT(old >= 0 && new >= 0);
1503 	ZEND_ASSERT(old != new);
1504 
1505 	/* Only a no_val is both variables are */
1506 	new_var->no_val &= old_var->no_val;
1507 
1508 	/* Update ssa_op use chains */
1509 	FOREACH_USE(old_var, use) {
1510 		zend_ssa_op *ssa_op = &ssa->ops[use];
1511 
1512 		/* If the op already uses the new var, don't add the op to the use
1513 		 * list again. Instead move the use_chain to the correct operand. */
1514 		zend_bool add_to_use_chain = 1;
1515 		if (ssa_op->result_use == new) {
1516 			add_to_use_chain = 0;
1517 		} else if (ssa_op->op1_use == new) {
1518 			if (ssa_op->result_use == old) {
1519 				ssa_op->res_use_chain = ssa_op->op1_use_chain;
1520 				ssa_op->op1_use_chain = -1;
1521 			}
1522 			add_to_use_chain = 0;
1523 		} else if (ssa_op->op2_use == new) {
1524 			if (ssa_op->result_use == old) {
1525 				ssa_op->res_use_chain = ssa_op->op2_use_chain;
1526 				ssa_op->op2_use_chain = -1;
1527 			} else if (ssa_op->op1_use == old) {
1528 				ssa_op->op1_use_chain = ssa_op->op2_use_chain;
1529 				ssa_op->op2_use_chain = -1;
1530 			}
1531 			add_to_use_chain = 0;
1532 		}
1533 
1534 		/* Perform the actual renaming */
1535 		if (ssa_op->result_use == old) {
1536 			ssa_op->result_use = new;
1537 		}
1538 		if (ssa_op->op1_use == old) {
1539 			ssa_op->op1_use = new;
1540 		}
1541 		if (ssa_op->op2_use == old) {
1542 			ssa_op->op2_use = new;
1543 		}
1544 
1545 		/* Add op to use chain of new var (if it isn't already). We use the
1546 		 * first use chain of (result, op1, op2) that has the new variable. */
1547 		if (add_to_use_chain) {
1548 			if (ssa_op->result_use == new) {
1549 				ssa_op->res_use_chain = new_var->use_chain;
1550 				new_var->use_chain = use;
1551 			} else if (ssa_op->op1_use == new) {
1552 				ssa_op->op1_use_chain = new_var->use_chain;
1553 				new_var->use_chain = use;
1554 			} else {
1555 				ZEND_ASSERT(ssa_op->op2_use == new);
1556 				ssa_op->op2_use_chain = new_var->use_chain;
1557 				new_var->use_chain = use;
1558 			}
1559 		}
1560 	} FOREACH_USE_END();
1561 	old_var->use_chain = -1;
1562 
1563 	/* Update phi use chains */
1564 	FOREACH_PHI_USE(old_var, phi) {
1565 		int j;
1566 		zend_bool after_first_new_source = 0;
1567 
1568 		/* If the phi already uses the new var, find its use chain, as we may
1569 		 * need to move it to a different source operand. */
1570 		zend_ssa_phi **existing_use_chain_ptr = NULL;
1571 		for (j = 0; j < ssa->cfg.blocks[phi->block].predecessors_count; j++) {
1572 			if (phi->sources[j] == new) {
1573 				existing_use_chain_ptr = &phi->use_chains[j];
1574 				break;
1575 			}
1576 		}
1577 
1578 		for (j = 0; j < ssa->cfg.blocks[phi->block].predecessors_count; j++) {
1579 			if (phi->sources[j] == new) {
1580 				after_first_new_source = 1;
1581 			} else if (phi->sources[j] == old) {
1582 				phi->sources[j] = new;
1583 
1584 				/* Either move existing use chain to this source, or add the phi
1585 				 * to the phi use chain of the new variables. Do this only once. */
1586 				if (!after_first_new_source) {
1587 					if (existing_use_chain_ptr) {
1588 						phi->use_chains[j] = *existing_use_chain_ptr;
1589 						*existing_use_chain_ptr = NULL;
1590 					} else {
1591 						phi->use_chains[j] = new_var->phi_use_chain;
1592 						new_var->phi_use_chain = phi;
1593 					}
1594 					after_first_new_source = 1;
1595 				}
1596 			}
1597 		}
1598 
1599 		/* Make sure phi result types are not incorrectly narrow after renaming.
1600 		 * This should not normally happen, but can occur if we DCE an assignment
1601 		 * or unset and there is an improper phi-indirected use lateron. */
1602 		// TODO Alternatively we could rerun type-inference after DCE
1603 		if (update_types && (ssa->var_info[new].type & ~ssa->var_info[phi->ssa_var].type)) {
1604 			ssa->var_info[phi->ssa_var].type |= ssa->var_info[new].type;
1605 			propagate_phi_type_widening(ssa, phi->ssa_var);
1606 		}
1607 	} FOREACH_PHI_USE_END();
1608 	old_var->phi_use_chain = NULL;
1609 }
1610 /* }}} */
1611 
1612 /*
1613  * Local variables:
1614  * tab-width: 4
1615  * c-basic-offset: 4
1616  * indent-tabs-mode: t
1617  * End:
1618  */
1619