Skip to content

Commit 94c9b26

Browse files
committed
More accurate "vararg" handling in DCE
1 parent 665ed84 commit 94c9b26

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

ext/opcache/Optimizer/dce.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,14 +457,29 @@ static void try_remove_trivial_phi(context *ctx, zend_ssa_phi *phi) {
457457
}
458458
}
459459

460+
static inline zend_bool may_break_varargs(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_op *ssa_op) {
461+
if (ssa_op->op1_def >= 0
462+
&& ssa->vars[ssa_op->op1_def].var < op_array->num_args) {
463+
return 1;
464+
}
465+
if (ssa_op->op2_def >= 0
466+
&& ssa->vars[ssa_op->op2_def].var < op_array->num_args) {
467+
return 1;
468+
}
469+
if (ssa_op->result_def >= 0
470+
&& ssa->vars[ssa_op->result_def].var < op_array->num_args) {
471+
return 1;
472+
}
473+
return 0;
474+
}
475+
460476
int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reorder_dtor_effects) {
461477
int i;
462478
zend_ssa_phi *phi;
463479
int removed_ops = 0;
464480

465-
/* DCE of CV operations may affect vararg functions. For now simply treat all instructions
466-
* as live if varargs in use and only collect dead phis. */
467-
zend_bool has_varargs = (ZEND_FUNC_INFO(op_array)->flags & ZEND_FUNC_VARARG) != 0;
481+
/* DCE of CV operations that changes arguments may affect vararg functions. */
482+
zend_bool has_varargs = ssa->cfg.vararg;
468483

469484
context ctx;
470485
ctx.ssa = ssa;
@@ -504,7 +519,7 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor
504519
add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i], 0);
505520
} else if (may_have_side_effects(op_array, ssa, &op_array->opcodes[i], &ssa->ops[i], ctx.reorder_dtor_effects)
506521
|| zend_may_throw(&op_array->opcodes[i], op_array, ssa)
507-
|| has_varargs) {
522+
|| (has_varargs && may_break_varargs(op_array, ssa, &ssa->ops[i]))) {
508523
add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i], 0);
509524
} else {
510525
zend_bitset_incl(ctx.instr_dead, i);

ext/opcache/Optimizer/zend_cfg.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,9 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
441441
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
442442
}
443443
break;
444+
case ZEND_FUNC_GET_ARGS:
445+
flags |= ZEND_FUNC_VARARG;
446+
break;
444447
}
445448
}
446449

@@ -598,7 +601,8 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
598601
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
599602
zend_mark_reachable_blocks(op_array, cfg, 0);
600603

601-
cfg->dynamic = (flags & ZEND_FUNC_INDIRECT_VAR_ACCESS);
604+
cfg->dynamic = (flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0;
605+
cfg->vararg = (flags & ZEND_FUNC_VARARG) != 0;
602606

603607
if (func_flags) {
604608
*func_flags |= flags;

ext/opcache/Optimizer/zend_cfg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ typedef struct _zend_cfg {
9393
unsigned int split_at_calls : 1;
9494
unsigned int split_at_recv : 1;
9595
unsigned int dynamic : 1; /* accesses varables by name */
96+
unsigned int vararg : 1; /* uses func_get_args() */
9697
} zend_cfg;
9798

9899
/* Build Flags */

0 commit comments

Comments
 (0)