return ssa_vars_count;
}
+static int zend_jit_trace_add_call_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
+{
+ zend_ssa_phi *prev = NULL;
+ const zend_op_array *op_array = trace_buffer->op_array;
+ const zend_op *opline = trace_buffer[1].opline;
+ int count = opline - op_array->opcodes;
+ int i;
+
+ for(i = 0; i < count; i++) {
+ zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
+ ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
+ sizeof(void*) * 2);
+ phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
+ phi->sources[0] = STACK_VAR(stack, i);
+ phi->sources[1] = -1;
+ phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
+ phi->pi = -1;
+ phi->var = i;
+ phi->ssa_var = ssa_vars_count;
+ SET_STACK_VAR(stack, i, ssa_vars_count);
+ ssa_vars_count++;
+ phi->block = 1;
+ if (prev) {
+ prev->next = phi;
+ } else {
+ tssa->blocks[1].phis = phi;
+ }
+ prev = phi;
+ }
+ return ssa_vars_count;
+}
+
+static int zend_jit_trace_add_ret_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
+{
+ const zend_op *opline = trace_buffer[1].opline - 1;
+ int i;
+
+ if (RETURN_VALUE_USED(opline)) {
+ zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
+ ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
+ sizeof(void*) * 2);
+
+ i = EX_VAR_TO_NUM(opline->result.var);
+ phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
+ phi->sources[0] = STACK_VAR(stack, i);
+ phi->sources[1] = -1;
+ phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
+ phi->pi = -1;
+ phi->var = i;
+ phi->ssa_var = ssa_vars_count;
+ SET_STACK_VAR(stack, i, ssa_vars_count);
+ ssa_vars_count++;
+ phi->block = 1;
+ tssa->blocks[1].phis = phi;
+ }
+ return ssa_vars_count;
+}
+
static int zend_jit_trace_copy_ssa_var_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
{
int var, use;
tssa->blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_ssa_block));
tssa->cfg.predecessors = zend_arena_calloc(&CG(arena), 2, sizeof(int));
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
tssa->cfg.blocks_count = 2;
tssa->cfg.edges_count = 2;
// TODO: For tracing, it's possible, to create pseudo Phi functions
// at the end of loop, without this additional pass (like LuaJIT) ???
ssa_vars_count = zend_jit_trace_add_phis(trace_buffer, ssa_vars_count, tssa, stack);
+ } else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
+ ssa_vars_count = zend_jit_trace_add_call_phis(trace_buffer, ssa_vars_count, tssa, stack);
+ } else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
+ ssa_vars_count = zend_jit_trace_add_ret_phis(trace_buffer, ssa_vars_count, tssa, stack);
}
p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
i++;
}
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
/* Update Phi sources */
zend_ssa_phi *phi = tssa->blocks[1].phis;
}
}
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
/* Propagate initial value through Phi functions */
zend_ssa_phi *phi = tssa->blocks[1].phis;
while (q->op == ZEND_JIT_TRACE_INIT_CALL) {
q++;
}
- if (q->op == ZEND_JIT_TRACE_VM) {
+ if (q->op == ZEND_JIT_TRACE_VM
+ || (q->op == ZEND_JIT_TRACE_END
+ && q->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)) {
const zend_op *opline = q->opline - 1;
if (opline->result_type != IS_UNUSED) {
ssa_var_info[
}
}
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
/* Propagate guards through Phi sources */
zend_ssa_phi *phi = tssa->blocks[1].phis;
}
}
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
zend_ssa_phi *phi = ssa->blocks[1].phis;
while (phi) {
}
}
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
zend_ssa_phi *phi = ssa->blocks[1].phis;
while (phi) {
phi = phi->next;
}
- for (i = 0; i < op_array->last_var; i++) {
- if (start[i] >= 0 && !ssa->vars[i].phi_use_chain) {
- end[i] = idx;
- flags[i] &= ~ZREG_LAST_USE;
- } else {
- zend_jit_close_var(stack, i, start, end, flags, idx);
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ for (i = 0; i < op_array->last_var; i++) {
+ if (start[i] >= 0 && !ssa->vars[i].phi_use_chain) {
+ end[i] = idx;
+ flags[i] &= ~ZREG_LAST_USE;
+ } else {
+ zend_jit_close_var(stack, i, start, end, flags, idx);
+ }
}
}
} else {
}
}
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
zend_ssa_phi *phi = ssa->blocks[1].phis;
while (phi) {
}
/* SSA resolution */
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
+ if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
zend_ssa_phi *phi = ssa->blocks[1].phis;
while (phi) {
ZEND_UNREACHABLE();
// SET_STACK_TYPE(stack, i, STACK_TYPE(parent_stack, i));
} else if ((info & MAY_BE_GUARD) != 0
- && trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)
&& (ssa->vars[i].use_chain != -1
|| (ssa->vars[i].phi_use_chain
&& !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_GUARD)))) {
}
if ((info & MAY_BE_PACKED_GUARD) != 0
- && trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
+ || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)
&& ssa->vars[i].use_chain != -1) {
if (!zend_jit_packed_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), info)) {
goto jit_failure;
if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
|| trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
|| trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
+ zend_ssa_phi *p = tssa->blocks[1].phis;
+
fprintf(stderr, "LOOP:\n");
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
- zend_ssa_phi *p = tssa->blocks[1].phis;
-
- while (p) {
- fprintf(stderr, " ;");
- zend_dump_ssa_var(op_array, tssa, p->ssa_var, 0, p->var, ZEND_DUMP_RC_INFERENCE);
- fprintf(stderr, " = Phi(");
- zend_dump_ssa_var(op_array, tssa, p->sources[0], 0, p->var, ZEND_DUMP_RC_INFERENCE);
- fprintf(stderr, ", ");
- zend_dump_ssa_var(op_array, tssa, p->sources[1], 0, p->var, ZEND_DUMP_RC_INFERENCE);
- fprintf(stderr, ")\n");
- p = p->next;
- }
+
+ while (p) {
+ fprintf(stderr, " ;");
+ zend_dump_ssa_var(op_array, tssa, p->ssa_var, 0, p->var, ZEND_DUMP_RC_INFERENCE);
+ fprintf(stderr, " = Phi(");
+ zend_dump_ssa_var(op_array, tssa, p->sources[0], 0, p->var, ZEND_DUMP_RC_INFERENCE);
+ fprintf(stderr, ", ");
+ zend_dump_ssa_var(op_array, tssa, p->sources[1], 0, p->var, ZEND_DUMP_RC_INFERENCE);
+ fprintf(stderr, ")\n");
+ p = p->next;
}
}
}