summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2020-04-07 21:34:18 +0300
committerDmitry Stogov <dmitry@zend.com>2020-04-07 21:34:18 +0300
commitcff7703a6185803e22bd3543d5bcd114d0a6f514 (patch)
tree8754b3aa76283319fa414d0bcbb17480cecf708b
parent5db5f71f2831df4d32484a5638f6f6aa72e364a5 (diff)
downloadphp-git-cff7703a6185803e22bd3543d5bcd114d0a6f514.tar.gz
Revert "cleanup" (wrong commit)
This reverts commit 5db5f71f2831df4d32484a5638f6f6aa72e364a5.
-rw-r--r--ext/opcache/jit/zend_jit_trace.c801
1 files changed, 3 insertions, 798 deletions
diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index 9f17f681d6..171ecd7d51 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -803,11 +803,6 @@ static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, u
return 0;
}
-typedef struct _zend_tssa {
- zend_ssa ssa;
- const zend_op **tssa_opcodes;
-} zend_tssa;
-
static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num, zend_script *script, const zend_op_array **op_arrays, int *num_op_arrays_ptr)
{
zend_ssa *tssa;
@@ -918,7 +913,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
*num_op_arrays_ptr = num_op_arrays;
/* 2. Construct TSSA */
- tssa = zend_arena_calloc(&CG(arena), 1, sizeof(zend_tssa));
+ tssa = zend_arena_calloc(&CG(arena), 1, sizeof(zend_ssa));
tssa->cfg.blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_basic_block));
tssa->blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_ssa_block));
tssa->cfg.predecessors = zend_arena_calloc(&CG(arena), 2, sizeof(int));
@@ -926,7 +921,6 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
memset(ssa_ops, -1, ssa_ops_count * sizeof(zend_ssa_op));
ssa_opcodes = zend_arena_calloc(&CG(arena), ssa_ops_count, sizeof(zend_op*));
JIT_G(current_frame) = frame = (zend_jit_trace_stack_frame*)((char*)zend_arena_alloc(&CG(arena), stack_bottom + stack_size) + stack_bottom);
- ((zend_tssa*)tssa)->tssa_opcodes = ssa_opcodes;
if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
tssa->cfg.blocks_count = 2;
@@ -1684,784 +1678,6 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
return tssa;
}
-static int zend_jit_trace_try_allocate_free_reg(zend_jit_trace_rec *trace_buffer, const zend_op **ssa_opcodes, zend_ssa *ssa, zend_lifetime_interval *current, zend_regset available, zend_regset *hints, zend_lifetime_interval *active, zend_lifetime_interval *inactive, zend_lifetime_interval **list, zend_lifetime_interval **free)
-{
- zend_lifetime_interval *it;
- uint32_t freeUntilPos[ZREG_NUM];
- uint32_t pos, pos2;
- zend_reg i, reg, reg2;
- zend_reg hint = ZREG_NONE;
- zend_regset low_priority_regs;
- zend_life_range *range;
-
- if ((ssa->var_info[current->ssa_var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
- available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_FP);
- } else {
- available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_GP);
- }
-
- /* TODO: Allow usage of preserved registers ???
- * Their values have to be stored in prologuee and restored in epilogue
- */
- available = ZEND_REGSET_DIFFERENCE(available, ZEND_REGSET_PRESERVED);
-
- if (ZEND_REGSET_IS_EMPTY(available)) {
- return 0;
- }
-
- /* Set freeUntilPos of all physical registers to maxInt */
- for (i = 0; i < ZREG_NUM; i++) {
- freeUntilPos[i] = 0xffffffff;
- }
-
- /* for each interval it in active do */
- /* freeUntilPos[it.reg] = 0 */
- it = active;
- if (ssa->vars[current->ssa_var].definition == current->range.start) {
- while (it) {
- if (current->range.start != zend_interval_end(it)) {
- freeUntilPos[it->reg] = 0;
- } else if (zend_jit_may_reuse_reg(ssa_opcodes[current->range.start], ssa->ops + current->range.start, ssa, current->ssa_var, it->ssa_var)) {
- if (!ZEND_REGSET_IN(*hints, it->reg) &&
- /* TODO: Avoid most often scratch registers. Find a better way ??? */
- (!current->used_as_hint ||
- (it->reg != ZREG_R0 && it->reg != ZREG_R1 && it->reg != ZREG_XMM0 && it->reg != ZREG_XMM1))) {
- hint = it->reg;
- }
- } else {
- freeUntilPos[it->reg] = 0;
- }
- it = it->list_next;
- }
- } else {
- while (it) {
- freeUntilPos[it->reg] = 0;
- it = it->list_next;
- }
- }
- if (current->hint) {
- hint = current->hint->reg;
- if (hint != ZREG_NONE && current->hint->used_as_hint == current) {
- ZEND_REGSET_EXCL(*hints, hint);
- }
- }
-
- /* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
- Michael Franz, CGO'10 (2010), Figure 6. */
- if (current->split) {
- /* for each interval it in inactive intersecting with current do */
- /* freeUntilPos[it.reg] = next intersection of it with current */
- it = inactive;
- while (it) {
- uint32_t next = zend_interval_intersection(current, it);
-
- //ZEND_ASSERT(next != 0xffffffff && !current->split);
- if (next < freeUntilPos[it->reg]) {
- freeUntilPos[it->reg] = next;
- }
- it = it->list_next;
- }
- }
-
- /* Handle Scratch Registers */
- /* TODO: Optimize ??? */
- range = &current->range;
- do {
- uint32_t line = range->start;
- zend_regset regset;
- zend_reg reg;
-
- if (ssa->ops[line].op1_def == current->ssa_var ||
- ssa->ops[line].op2_def == current->ssa_var ||
- ssa->ops[line].result_def == current->ssa_var) {
- line++;
- }
- while (line <= range->end) {
- regset = zend_jit_get_scratch_regset(
- ssa_opcodes[line],
- ssa->ops + line,
- // TODO: Support for nested call frames ???
- trace_buffer->op_array, ssa, current->ssa_var);
- ZEND_REGSET_FOREACH(regset, reg) {
- if (line < freeUntilPos[reg]) {
- freeUntilPos[reg] = line;
- }
- } ZEND_REGSET_FOREACH_END();
- line++;
- }
- range = range->next;
- } while (range);
-
-#if 0
- /* Coalesing */
- if (ssa->vars[current->ssa_var].definition == current->start) {
- zend_op *opline = op_array->opcodes + current->start;
- int hint = -1;
-
- switch (opline->opcode) {
- case ZEND_ASSIGN:
- hint = ssa->ops[current->start].op2_use;
- case ZEND_QM_ASSIGN:
- hint = ssa->ops[current->start].op1_use;
- break;
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- hint = ssa->ops[current->start].op1_use;
- break;
- case ZEND_ASSIGN_OP:
- if (opline->extended_value == ZEND_ADD
- || opline->extended_value == ZEND_SUB
- || opline->extended_value == ZEND_MUL) {
- hint = ssa->ops[current->start].op1_use;
- }
- break;
- }
- if (hint >= 0) {
- }
- }
-#endif
-
- if (hint != ZREG_NONE && freeUntilPos[hint] > zend_interval_end(current)) {
- current->reg = hint;
- if (current->used_as_hint) {
- ZEND_REGSET_INCL(*hints, hint);
- }
- return 1;
- }
-
- pos = 0; reg = ZREG_NONE;
- pos2 = 0; reg2 = ZREG_NONE;
- low_priority_regs = *hints;
- if (current->used_as_hint) {
- /* TODO: Avoid most often scratch registers. Find a better way ??? */
- ZEND_REGSET_INCL(low_priority_regs, ZREG_R0);
- ZEND_REGSET_INCL(low_priority_regs, ZREG_R1);
- ZEND_REGSET_INCL(low_priority_regs, ZREG_XMM0);
- ZEND_REGSET_INCL(low_priority_regs, ZREG_XMM1);
- }
-
- ZEND_REGSET_FOREACH(available, i) {
- if (ZEND_REGSET_IN(low_priority_regs, i)) {
- if (freeUntilPos[i] > pos2) {
- reg2 = i;
- pos2 = freeUntilPos[i];
- }
- } else if (freeUntilPos[i] > pos) {
- reg = i;
- pos = freeUntilPos[i];
- }
- } ZEND_REGSET_FOREACH_END();
-
- if (reg == ZREG_NONE) {
- if (reg2 != ZREG_NONE) {
- reg = reg2;
- pos = pos2;
- reg2 = ZREG_NONE;
- }
- }
-
- if (reg == ZREG_NONE) {
- /* no register available without spilling */
- return 0;
- } else if (zend_interval_end(current) < pos) {
- /* register available for the whole interval */
- current->reg = reg;
- if (current->used_as_hint) {
- ZEND_REGSET_INCL(*hints, reg);
- }
- return 1;
-#if 0
- // TODO: allow low prioirity register usage
- } else if (reg2 != ZREG_NONE && zend_interval_end(current) < pos2) {
- /* register available for the whole interval */
- current->reg = reg2;
- if (current->used_as_hint) {
- ZEND_REGSET_INCL(*hints, reg2);
- }
- return 1;
-#endif
- } else {
- /* TODO: enable interval splitting ??? */
- /* register available for the first part of the interval */
- if (1 || zend_jit_split_interval(current, pos, list, free) != SUCCESS) {
- return 0;
- }
- current->reg = reg;
- if (current->used_as_hint) {
- ZEND_REGSET_INCL(*hints, reg);
- }
- return 1;
- }
-}
-
-static zend_lifetime_interval* zend_jit_trace_linear_scan(zend_jit_trace_rec *trace_buffer, const zend_op **ssa_opcodes, zend_ssa *ssa, zend_lifetime_interval *list)
-{
- zend_lifetime_interval *unhandled, *active, *inactive, *handled, *free;
- zend_lifetime_interval *current, **p, *q;
- uint32_t position;
- zend_regset available = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
- zend_regset hints = ZEND_REGSET_EMPTY;
-
- unhandled = list;
- /* active = inactive = handled = free = {} */
- active = inactive = handled = free = NULL;
- while (unhandled != NULL) {
- current = unhandled;
- unhandled = unhandled->list_next;
- position = current->range.start;
-
- p = &active;
- while (*p) {
- uint32_t end = zend_interval_end(*p);
-
- q = *p;
- if (end < position) {
- /* move ival from active to handled */
- ZEND_REGSET_INCL(available, q->reg);
- *p = q->list_next;
- q->list_next = handled;
- handled = q;
- } else if (!zend_interval_covers(q, position)) {
- /* move ival from active to inactive */
- ZEND_REGSET_INCL(available, q->reg);
- *p = q->list_next;
- q->list_next = inactive;
- inactive = q;
- } else {
- p = &q->list_next;
- }
- }
-
- p = &inactive;
- while (*p) {
- uint32_t end = zend_interval_end(*p);
-
- q = *p;
- if (end < position) {
- /* move ival from inactive to handled */
- *p = q->list_next;
- q->list_next = handled;
- handled = q;
- } else if (zend_interval_covers(q, position)) {
- /* move ival from inactive to active */
- ZEND_REGSET_EXCL(available, q->reg);
- *p = q->list_next;
- q->list_next = active;
- active = q;
- } else {
- p = &q->list_next;
- }
- }
-
- if (zend_jit_trace_try_allocate_free_reg(trace_buffer, ssa_opcodes, ssa, current, available, &hints, active, inactive, &unhandled, &free) ||
- zend_jit_allocate_blocked_reg()) {
- ZEND_REGSET_EXCL(available, current->reg);
- current->list_next = active;
- active = current;
- } else {
- current->list_next = free;
- free = current;
- }
- }
-
- /* move active to handled */
- while (active) {
- current = active;
- active = active->list_next;
- current->list_next = handled;
- handled = current;
- }
-
- /* move inactive to handled */
- while (inactive) {
- current = inactive;
- inactive = inactive->list_next;
- current->list_next = handled;
- handled = current;
- }
-
- return handled;
-}
-
-static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace_rec *trace_buffer, zend_ssa *ssa)
-{
- const zend_op **ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
- zend_jit_trace_rec *p;
- const zend_op_array *op_array;
- const zend_ssa_op *ssa_op;
- int i, j, idx, count, level;
- int *start, *end;
- zend_lifetime_interval **intervals, *list;
- void *checkpoint;
- ALLOCA_FLAG(use_heap);
-
- ZEND_ASSERT(ssa->var_info != NULL);
-
- start =do_alloca(sizeof(int) * ssa->vars_count * 2, use_heap);
- if (!start) {
- return NULL;
- }
- end = start + ssa->vars_count;
-
- memset(start, -1, sizeof(int) * ssa->vars_count * 2);
-
- op_array = trace_buffer->op_array;
- count = 0;
-
- i = 0;
- j = op_array->last_var;
- if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
- j += op_array->T;
- }
- while (i < j) {
- /* We don't start intervals for variables used in Phi */
- if ((ssa->vars[i].use_chain >= 0 /*|| ssa->vars[i].phi_use_chain*/)
- && zend_jit_var_supports_reg(ssa, i)) {
- start[i] = 0;
- count++;
- }
- i++;
- }
-
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
- zend_ssa_phi *phi = ssa->blocks[1].phis;
-
- while (phi) {
- if (ssa->vars[phi->ssa_var].use_chain >= 0
- && zend_jit_var_supports_reg(ssa, phi->ssa_var)) {
- start[phi->ssa_var] = 0;
- count++;
- }
- phi = phi->next;
- }
- }
-
- p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
- level = 0;
- ssa_op = ssa->ops;
- idx = 0;
- for (;;p++) {
- if (p->op == ZEND_JIT_TRACE_VM) {
- const zend_op *opline = p->opline;
- int len;
- zend_bool support_opline;
-
- support_opline =
- zend_jit_opline_supports_reg(op_array, ssa, opline, ssa_op);
- if (support_opline) {
- if (ssa_op->op1_use >= 0
- && start[ssa_op->op1_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
- end[ssa_op->op1_use] = idx;
- }
- if (ssa_op->op2_use >= 0
- && start[ssa_op->op2_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)) {
- end[ssa_op->op2_use] = idx;
- }
- if (ssa_op->result_use >= 0
- && start[ssa_op->result_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->result_use)) {
- end[ssa_op->result_use] = idx;
- }
- if (ssa_op->result_def >= 0
- && (ssa->vars[ssa_op->result_def].use_chain >= 0
- || ssa->vars[ssa_op->result_def].phi_use_chain)
- && zend_jit_var_supports_reg(ssa, ssa_op->result_def)) {
- start[ssa_op->result_def] = idx;
- count++;
- }
- if (ssa_op->op1_def >= 0
- && (ssa->vars[ssa_op->op1_def].use_chain >= 0
- || ssa->vars[ssa_op->op1_def].phi_use_chain)
- && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
- start[ssa_op->op1_def] = idx;
- count++;
- }
- if (ssa_op->op2_def >= 0
- && (ssa->vars[ssa_op->op2_def].use_chain >= 0
- || ssa->vars[ssa_op->op2_def].phi_use_chain)
- && zend_jit_var_supports_reg(ssa, ssa_op->op2_def)) {
- start[ssa_op->op2_def] = idx;
- count++;
- }
- } else {
- if (ssa_op->op1_use >= 0
- && start[ssa_op->op1_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
- start[ssa_op->op1_use] = -1;
- end[ssa_op->op1_use] = -1;
- count--;
- }
- if (ssa_op->op2_use >= 0
- && start[ssa_op->op2_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)) {
- start[ssa_op->op2_use] = -1;
- end[ssa_op->op2_use] = -1;
- count--;
- }
- if (ssa_op->result_use >= 0
- && start[ssa_op->result_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->result_use)) {
- start[ssa_op->result_use] = -1;
- end[ssa_op->result_use] = -1;
- count--;
- }
- }
-
- len = zend_jit_trace_op_len(opline);
- switch (opline->opcode) {
- case ZEND_ASSIGN_DIM:
- case ZEND_ASSIGN_OBJ:
- case ZEND_ASSIGN_STATIC_PROP:
- case ZEND_ASSIGN_DIM_OP:
- case ZEND_ASSIGN_OBJ_OP:
- case ZEND_ASSIGN_STATIC_PROP_OP:
- case ZEND_ASSIGN_OBJ_REF:
- case ZEND_ASSIGN_STATIC_PROP_REF:
- /* OP_DATA */
- ssa_op++;
- opline++;
- if (support_opline) {
- if (ssa_op->op1_use >= 0
- && start[ssa_op->op1_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
- end[ssa_op->op1_use] = idx;
- }
- if (ssa_op->op1_def >= 0
- && (ssa->vars[ssa_op->op1_def].use_chain >= 0
- || ssa->vars[ssa_op->op1_def].phi_use_chain)
- && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
- start[ssa_op->op1_def] = idx;
- count++;
- }
- } else {
- if (ssa_op->op1_use >= 0
- && start[ssa_op->op1_use] >= 0
- && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
- start[ssa_op->op1_use] = -1;
- end[ssa_op->op1_use] = -1;
- count--;
- }
- }
- ssa_op++;
- opline++;
- idx+=2;
- break;
- case ZEND_RECV_INIT:
- ssa_op++;
- opline++;
- idx++;
- while (opline->opcode == ZEND_RECV_INIT) {
- /* RECV_INIT doesn't support registers */
- ssa_op++;
- opline++;
- idx++;
- }
- break;
- case ZEND_BIND_GLOBAL:
- ssa_op++;
- opline++;
- idx++;
- while (opline->opcode == ZEND_BIND_GLOBAL) {
- /* BIND_GLOBAL doesn't support registers */
- ssa_op++;
- opline++;
- idx++;
- }
- break;
- default:
- ssa_op += len;
- idx += len;
- break;
- }
- } else if (p->op == ZEND_JIT_TRACE_ENTER) {
- op_array = p->op_array;
- /* New call frames */
- i = op_array->last_var;
- j = p->first_ssa_var;
- while (i) {
- if (ssa->vars[j].use_chain >= 0
- && zend_jit_var_supports_reg(ssa, j)) {
- start[j] = idx;
- count++;
- }
- j++;
- i--;
- }
- level++;
- } else if (p->op == ZEND_JIT_TRACE_BACK) {
- // TODO: Close exiting call frames ???
- op_array = p->op_array;
- if (level == 0) {
- /* New return frames */
- i = op_array->last_var + op_array->T;
- j = p->first_ssa_var;
- while (i) {
- if (ssa->vars[j].use_chain >= 0
- && zend_jit_var_supports_reg(ssa, j)) {
- start[j] = idx;
- count++;
- }
- j++;
- i--;
- }
- } else {
- level--;
- }
- } else if (p->op == ZEND_JIT_TRACE_END) {
- break;
- }
- }
-
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
- zend_ssa_phi *phi = ssa->blocks[1].phis;
-
- while (phi) {
- if (start[phi->sources[1]] >= 0) {
- end[phi->sources[1]] = idx - 1;
- }
- phi = phi->next;
- }
- }
-
- if (!count) {
- free_alloca(start, use_heap);
- return NULL;
- }
-
- checkpoint = zend_arena_checkpoint(CG(arena));
- intervals = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_lifetime_interval));
- memset(intervals, 0, sizeof(zend_lifetime_interval*) * ssa->vars_count);
- list = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval) * count);
- j = 0;
-//fprintf(stderr, "(%d)\n", count);
- for (i = 0; i < ssa->vars_count; i++) {
- if (start[i] >= 0) {
- if (end[i] < 0) {
- // TODO: ???
- end[i] = idx;
- // continue;
- }
-//fprintf(stderr, "#%d: %d..%d\n", i, start[i], end[i]);
- ZEND_ASSERT(j < count);
- intervals[i] = &list[j];
- list[j].ssa_var = i;
- list[j].reg = ZREG_NONE;
- list[j].split = 0;
- list[j].store = 0;
- list[j].load = 0;
- list[j].range.start = start[i];
- list[j].range.end = end[i];
- list[j].range.next = NULL;
- list[j].hint = NULL;
- list[j].used_as_hint = NULL;
- list[j].list_next = NULL;
- j++;
- }
- }
- ZEND_ASSERT(j == count);
- free_alloca(start, use_heap);
- start = end = NULL;
-
- /* Add hints */
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
- zend_ssa_phi *phi = ssa->blocks[1].phis;
-
- while (phi) {
- if (intervals[phi->ssa_var]) {
- if (intervals[phi->sources[1]]) {
- intervals[phi->sources[1]]->hint = intervals[phi->ssa_var];
- }
- }
- phi = phi->next;
- }
- }
-
- for (i = 0; i < ssa->vars_count; i++) {
- if (intervals[i] && !intervals[i]->hint) {
-
- if (ssa->vars[i].definition >= 0) {
- uint32_t line = ssa->vars[i].definition;
- const zend_op *opline = ssa_opcodes[line];
-
- switch (opline->opcode) {
- case ZEND_QM_ASSIGN:
- case ZEND_POST_INC:
- case ZEND_POST_DEC:
- if (ssa->ops[line].op1_use >= 0 &&
- intervals[ssa->ops[line].op1_use] &&
- (i == ssa->ops[line].op1_def ||
- (i == ssa->ops[line].result_def &&
- (ssa->ops[line].op1_def < 0 ||
- !intervals[ssa->ops[line].op1_def])))) {
- zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
- }
- break;
- case ZEND_SEND_VAR:
- case ZEND_PRE_INC:
- case ZEND_PRE_DEC:
- if (i == ssa->ops[line].op1_def &&
- ssa->ops[line].op1_use >= 0 &&
- intervals[ssa->ops[line].op1_use]) {
- zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
- }
- break;
- case ZEND_ASSIGN:
- if (ssa->ops[line].op2_use >= 0 &&
- intervals[ssa->ops[line].op2_use] &&
- (i == ssa->ops[line].op2_def ||
- (i == ssa->ops[line].op1_def &&
- (ssa->ops[line].op2_def < 0 ||
- !intervals[ssa->ops[line].op2_def])) ||
- (i == ssa->ops[line].result_def &&
- (ssa->ops[line].op2_def < 0 ||
- !intervals[ssa->ops[line].op2_def]) &&
- (ssa->ops[line].op1_def < 0 ||
- !intervals[ssa->ops[line].op1_def])))) {
- zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
- }
- break;
- }
- }
- }
- }
-
- list = zend_jit_sort_intervals(intervals, ssa->vars_count);
-
- if (list) {
- zend_lifetime_interval *ival = list;
- while (ival) {
- if (ival->hint) {
- ival->hint->used_as_hint = ival;
- }
- ival = ival->list_next;
- }
-
- if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_REG_ALLOC) {
- // TODO: Support for nested call frames ???
- op_array = trace_buffer->op_array;
- ival = list;
- while (ival) {
- zend_life_range *range;
- int var_num = ssa->vars[ival->ssa_var].var;
-
- fprintf(stderr, "#%d.", ival->ssa_var);
- // TODO: Support for nested call frames ???
- zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
- fprintf(stderr, ": %u-%u", ival->range.start, ival->range.end);
- range = ival->range.next;
- while (range) {
- fprintf(stderr, ", %u-%u", range->start, range->end);
- range = range->next;
- }
- if (ival->load) {
- fprintf(stderr, " load");
- }
- if (ival->store) {
- fprintf(stderr, " store");
- }
- if (ival->hint) {
- var_num = ssa->vars[ival->hint->ssa_var].var;
- fprintf(stderr, " hint=#%d.", ival->hint->ssa_var);
- // TODO: Support for nested call frames ???
- zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
- }
- fprintf(stderr, "\n");
- ival = ival->list_next;
- }
- fprintf(stderr, "\n");
- }
- }
-
- /* Linear Scan Register Allocation */
- list = zend_jit_trace_linear_scan(trace_buffer, ssa_opcodes, ssa, list);
-
- if (list) {
- zend_lifetime_interval *ival, *next;
-
- memset(intervals, 0, ssa->vars_count * sizeof(zend_lifetime_interval*));
- ival = list;
- while (ival != NULL) {
- ZEND_ASSERT(ival->reg != ZREG_NONE);
- next = ival->list_next;
- ival->list_next = intervals[ival->ssa_var];
- intervals[ival->ssa_var] = ival;
- ival = next;
- }
-
- /* SSA resolution */
- if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
- zend_ssa_phi *phi = ssa->blocks[1].phis;
-
- while (phi) {
- int def = phi->ssa_var;
- int use = phi->sources[1];
-
- if (intervals[def]) {
- if (!intervals[use]) {
- intervals[def]->load = 1;
- } else if (intervals[def]->reg != intervals[use]->reg) {
- intervals[def]->load = 1;
- intervals[use]->store = 1;
- }
- } else if (intervals[use]) {
- intervals[use]->store = 1;
- }
- phi = phi->next;
- }
- }
-
- // Remove useless register allocation ???
- // Remove intervals used once ???
-
- if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_REG_ALLOC) {
- // TODO: Support for nested call frames ???
- fprintf(stderr, "---- TRACE %d Allocated Live Ranges\n", ZEND_JIT_TRACE_NUM);
- for (i = 0; i < ssa->vars_count; i++) {
- ival = intervals[i];
- while (ival) {
- zend_life_range *range;
- int var_num = ssa->vars[ival->ssa_var].var;
-
- fprintf(stderr, "#%d.", ival->ssa_var);
- zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
- fprintf(stderr, ": %u-%u", ival->range.start, ival->range.end);
- range = ival->range.next;
- while (range) {
- fprintf(stderr, ", %u-%u", range->start, range->end);
- range = range->next;
- }
- fprintf(stderr, " (%s)", zend_reg_name[ival->reg]);
- if (ival->load) {
- fprintf(stderr, " load");
- }
- if (ival->store) {
- fprintf(stderr, " store");
- }
- if (ival->hint) {
- var_num = ssa->vars[ival->hint->ssa_var].var;
- fprintf(stderr, " hint=#%d.", ival->hint->ssa_var);
- zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
- if (ival->hint->reg != ZREG_NONE) {
- fprintf(stderr, " (%s)", zend_reg_name[ival->hint->reg]);
- }
- }
- fprintf(stderr, "\n");
- ival = ival->list_next;
- }
- }
- fprintf(stderr, "\n");
- }
-
- return intervals;
- }
-
- zend_arena_release(&CG(arena), checkpoint); //???
- return NULL;
-}
-
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
{
const void *handler = NULL;
@@ -2495,11 +1711,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
ssa = zend_jit_trace_build_tssa(trace_buffer, parent_trace, exit_num, script, op_arrays, &num_op_arrays);
- /* Register allocation */
- if (zend_jit_reg_alloc) {
- ra = zend_jit_trace_allocate_registers(trace_buffer, ssa);
- }
-
p = trace_buffer;
ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
op_array = p->op_array;
@@ -2561,6 +1772,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
op_array_ssa = &jit_extension->func_info.ssa;
+ // TODO: register allocation ???
+
dasm_growpc(&dasm_state, 1); /* trace needs just one global label for loop */
zend_jit_align_func(&dasm_state);
@@ -2604,14 +1817,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
SET_STACK_TYPE(stack, i, concrete_type(info));
}
}
- if (ra) {
- zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
- if (phi && ra[phi->ssa_var] && !ra[phi->ssa_var]->load) {
- if (!zend_jit_load_var(&dasm_state, ssa->var_info[i].type, i, ra[phi->ssa_var]->reg)) {
- goto jit_failure;
- }
- }
- }
}
}