/* e-SSA construction: Pi placement (Pi is actually a Phi with single * source and constraint). * Order of Phis is importent, Pis must be placed before Phis */ static void place_essa_pis( zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, zend_dfg *dfg) { zend_basic_block *blocks = ssa->cfg.blocks; int j, blocks_count = ssa->cfg.blocks_count; for (j = 0; j < blocks_count; j++) { zend_ssa_phi *pi; zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].end; int bt; /* successor block number if a condition is true */ int bf; /* successor block number if a condition is false */ if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) { continue; } /* the last instruction of basic block is conditional branch, * based on comparison of CV(s) */ switch (opline->opcode) { case ZEND_JMPZ: case ZEND_JMPZNZ: bf = ssa->cfg.blocks[j].successors[0]; bt = ssa->cfg.blocks[j].successors[1]; break; case ZEND_JMPNZ: bt = ssa->cfg.blocks[j].successors[0]; bf = ssa->cfg.blocks[j].successors[1]; break; default: continue; } if (opline->op1_type == IS_TMP_VAR && ((opline-1)->opcode == ZEND_IS_EQUAL || (opline-1)->opcode == ZEND_IS_NOT_EQUAL || (opline-1)->opcode == ZEND_IS_SMALLER || (opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) && opline->op1.var == (opline-1)->result.var) { int var1 = -1; int var2 = -1; zend_long val1 = 0; zend_long val2 = 0; // long val = 0; if ((opline-1)->op1_type == IS_CV) { var1 = EX_VAR_TO_NUM((opline-1)->op1.var); } else if ((opline-1)->op1_type == IS_TMP_VAR) { var1 = find_adjusted_tmp_var( op_array, build_flags, opline, (opline-1)->op1.var, &val2); } if ((opline-1)->op2_type == IS_CV) { var2 = EX_VAR_TO_NUM((opline-1)->op2.var); } else if ((opline-1)->op2_type == IS_TMP_VAR) { var2 = find_adjusted_tmp_var( op_array, build_flags, opline, (opline-1)->op2.var, &val1); } if (var1 >= 0 && var2 >= 0) { if (!sub_will_overflow(val1, val2) && !sub_will_overflow(val2, val1)) { zend_long tmp = val1; val1 -= val2; val2 -= tmp; } else { var1 = -1; var2 = -1; } } else if (var1 >= 0 && var2 < 0) { zend_long add_val2 = 0; if ((opline-1)->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_LONG) { add_val2 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op2)); } else if ((opline-1)->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_FALSE) { add_val2 = 0; } else if ((opline-1)->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_TRUE) { add_val2 = 1; } else { var1 = -1; } if (!add_will_overflow(val2, add_val2)) { val2 += add_val2; } else { var1 = -1; } } else if (var1 < 0 && var2 >= 0) { zend_long add_val1 = 0; if ((opline-1)->op1_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_LONG) { add_val1 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op1)); } else if ((opline-1)->op1_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_FALSE) { add_val1 = 0; } else if ((opline-1)->op1_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_TRUE) { add_val1 = 1; } else { var2 = -1; } if (!add_will_overflow(val1, add_val1)) { val1 += add_val1; } else { var2 = -1; } } if (var1 >= 0) { if ((opline-1)->opcode == ZEND_IS_EQUAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) { pi_range_equals(pi, var2, val2); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) { pi_range_not_equals(pi, var2, val2); } } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) { pi_range_equals(pi, var2, val2); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) { pi_range_not_equals(pi, var2, val2); } } else if ((opline-1)->opcode == ZEND_IS_SMALLER) { if (val2 > ZEND_LONG_MIN) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) { pi_range_max(pi, var2, val2-1); } } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) { pi_range_min(pi, var2, val2); } } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) { pi_range_max(pi, var2, val2); } if (val2 < ZEND_LONG_MAX) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) { pi_range_min(pi, var2, val2+1); } } } } if (var2 >= 0) { if((opline-1)->opcode == ZEND_IS_EQUAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) { pi_range_equals(pi, var1, val1); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) { pi_range_not_equals(pi, var1, val1); } } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) { pi_range_equals(pi, var1, val1); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) { pi_range_not_equals(pi, var1, val1); } } else if ((opline-1)->opcode == ZEND_IS_SMALLER) { if (val1 < ZEND_LONG_MAX) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) { pi_range_min(pi, var1, val1+1); } } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) { pi_range_max(pi, var1, val1); } } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) { pi_range_min(pi, var1, val1); } if (val1 > ZEND_LONG_MIN) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) { pi_range_max(pi, var1, val1-1); } } } } } else if (opline->op1_type == IS_TMP_VAR && ((opline-1)->opcode == ZEND_POST_INC || (opline-1)->opcode == ZEND_POST_DEC) && opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) { int var = EX_VAR_TO_NUM((opline-1)->op1.var); if ((opline-1)->opcode == ZEND_POST_DEC) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) { pi_range_equals(pi, -1, -1); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) { pi_range_not_equals(pi, -1, -1); } } else if ((opline-1)->opcode == ZEND_POST_INC) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) { pi_range_equals(pi, -1, 1); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) { pi_range_not_equals(pi, -1, 1); } } } else if (opline->op1_type == IS_VAR && ((opline-1)->opcode == ZEND_PRE_INC || (opline-1)->opcode == ZEND_PRE_DEC) && opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) { int var = EX_VAR_TO_NUM((opline-1)->op1.var); if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) { pi_range_equals(pi, -1, 0); } /* speculative */ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) { pi_range_not_equals(pi, -1, 0); } } else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_TYPE_CHECK && opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) { int var = EX_VAR_TO_NUM((opline-1)->op1.var); uint32_t type = (opline-1)->extended_value; if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) { pi_type_mask(pi, mask_for_type_check(type)); } if (type != IS_OBJECT && type != IS_RESOURCE) { /* is_object() and is_resource() may return false, even though the value is * an object/resource. */ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) { pi_not_type_mask(pi, mask_for_type_check(type)); } } } else if (opline->op1_type == IS_TMP_VAR && ((opline-1)->opcode == ZEND_IS_IDENTICAL || (opline-1)->opcode == ZEND_IS_NOT_IDENTICAL) && opline->op1.var == (opline-1)->result.var) { int var; zval *val; uint32_t type_mask; if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) { var = EX_VAR_TO_NUM((opline-1)->op1.var); val = CRT_CONSTANT((opline-1)->op2); } else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) { var = EX_VAR_TO_NUM((opline-1)->op2.var); val = CRT_CONSTANT((opline-1)->op1); } else { continue; } /* We're interested in === null/true/false comparisons here, because they eliminate * a type in the false-branch. Other === VAL comparisons are unlikely to be useful. */ if (Z_TYPE_P(val) != IS_NULL && Z_TYPE_P(val) != IS_TRUE && Z_TYPE_P(val) != IS_FALSE) { continue; } type_mask = _const_op_type(val); if ((opline-1)->opcode == ZEND_IS_IDENTICAL) { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) { pi_type_mask(pi, type_mask); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) { pi_not_type_mask(pi, type_mask); } } else { if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) { pi_type_mask(pi, type_mask); } if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) { pi_not_type_mask(pi, type_mask); } } } } }
void print_part1() { printf("VERSION=%s\n", VERSION); printf("PI=%lg\n", PI); printf("pi()=%lg\n", pi()); printf("PI+5=%lg\n", add_pi(5)); }