Skip to content

Commit b0501cc

Browse files
committed
[skip-ci] [W.I.P] Introduce new opcode for cast optimization
1 parent 9e73bf5 commit b0501cc

10 files changed

Lines changed: 1732 additions & 1334 deletions

Zend/Optimizer/dfa_pass.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,54 @@ static inline bool can_elide_return_type_check(
316316
return false;
317317
}
318318

319+
static inline bool can_return_value_safely_be_coerced(
320+
const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_op *ssa_op, zend_op *opline
321+
) {
322+
const uint32_t return_type_mask = ZEND_TYPE_FULL_MASK(op_array->arg_info[-1].type);
323+
const zend_ssa_var_info *use_info = &ssa->var_info[ssa_op->op1_use];
324+
325+
/* Type preference order: int -> float -> string -> bool */
326+
/* Can always safely cast booleans to inter */
327+
if (return_type_mask & MAY_BE_LONG) {
328+
if (use_info->type & MAY_BE_BOOL) {
329+
opline->opcode = ZEND_CAST_VALUE_FOR_RETURN_TYPE;
330+
opline->extended_value = IS_LONG;
331+
return true;
332+
}
333+
return false;
334+
}
335+
if (return_type_mask & MAY_BE_DOUBLE) {
336+
/* Can always safely cast booleans, and integers to float */
337+
if (use_info->type & (MAY_BE_LONG|MAY_BE_BOOL)) {
338+
opline->opcode = ZEND_CAST_VALUE_FOR_RETURN_TYPE;
339+
opline->extended_value = IS_DOUBLE;
340+
return true;
341+
}
342+
return false;
343+
}
344+
/* Can always safely cast booleans, and integers to string,
345+
* float value must not be NAN */
346+
if (return_type_mask & MAY_BE_STRING) {
347+
if (use_info->type & (MAY_BE_LONG|MAY_BE_BOOL)) {
348+
opline->opcode = ZEND_CAST_VALUE_FOR_RETURN_TYPE;
349+
opline->extended_value = IS_STRING;
350+
return true;
351+
}
352+
return false;
353+
}
354+
return false;
355+
if ((return_type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
356+
/* Can always safely cast integers and strings to bool,
357+
* float value must not be NAN */
358+
if (use_info->type & (MAY_BE_LONG|MAY_BE_STRING)) {
359+
opline->opcode = ZEND_CAST_VALUE_FOR_RETURN_TYPE;
360+
opline->extended_value = IS_FALSE;
361+
return true;
362+
}
363+
return false;
364+
}
365+
}
366+
319367
static bool opline_supports_assign_contraction(
320368
zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, int src_var, uint32_t cv_var) {
321369
if (opline->opcode == ZEND_NEW) {
@@ -1287,6 +1335,8 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
12871335

12881336
MAKE_NOP(opline);
12891337
remove_nops = 1;
1338+
} else if (can_return_value_safely_be_coerced(op_array, ssa, &ssa->ops[op_1], opline)) {
1339+
continue;
12901340
}
12911341
}
12921342
}

Zend/zend_vm_def.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
* php zend_vm_gen.php
2323
*/
2424

25+
#include "zend_variables.h"
26+
2527
ZEND_VM_HELPER(zend_add_helper, ANY, ANY, zval *op_1, zval *op_2)
2628
{
2729
USE_OPLINE
@@ -4532,6 +4534,40 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
45324534
}
45334535
}
45344536

4537+
ZEND_VM_COLD_CONST_HANDLER(45, ZEND_CAST_VALUE_FOR_RETURN_TYPE, TMP|VAR|CV, UNUSED)
4538+
{
4539+
USE_OPLINE
4540+
zval *retval_ptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
4541+
ZEND_ASSERT(!Z_ISREF_P(retval_ptr));
4542+
4543+
switch (opline->extended_value) {
4544+
case IS_LONG: {
4545+
zend_long lval = zval_get_long(retval_ptr);
4546+
zval_ptr_dtor(retval_ptr);
4547+
ZVAL_LONG(retval_ptr, lval);
4548+
break;
4549+
}
4550+
case IS_DOUBLE: {
4551+
double dval = zval_get_double(retval_ptr);
4552+
zval_ptr_dtor(retval_ptr);
4553+
ZVAL_DOUBLE(retval_ptr, dval);
4554+
break;
4555+
}
4556+
case IS_STRING:
4557+
/* retval_ptr cannot be a refcounted value */
4558+
ZVAL_STR(retval_ptr, zval_get_string(retval_ptr));
4559+
break;
4560+
case IS_FALSE: { /* Used for booleans */
4561+
bool bval = i_zend_is_true(retval_ptr);
4562+
zval_ptr_dtor(retval_ptr);
4563+
ZVAL_BOOL(retval_ptr, bval);
4564+
break;
4565+
}
4566+
/* Default case assert? */
4567+
}
4568+
ZEND_VM_NEXT_OPCODE();
4569+
}
4570+
45354571
ZEND_VM_COLD_HANDLER(201, ZEND_VERIFY_NEVER_TYPE, UNUSED, UNUSED)
45364572
{
45374573
SAVE_OPLINE();

0 commit comments

Comments
 (0)