From: Dmitry Stogov Date: Mon, 6 Apr 2020 13:17:02 +0000 (+0300) Subject: Minor register allocator refactoring X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c4bdf41862c07f5c7e0d4eb5dac4bbeac0b40296;p=php Minor register allocator refactoring --- diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 4839e93e6f..76acfc29de 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -1404,7 +1404,7 @@ static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, zend_ss while (it) { if (current->range.start != zend_interval_end(it)) { freeUntilPos[it->reg] = 0; - } else if (zend_jit_may_reuse_reg(op_array, ssa, current->range.start, current->ssa_var, it->ssa_var)) { + } else if (zend_jit_may_reuse_reg(op_array->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 || @@ -1460,7 +1460,10 @@ static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, zend_ss line++; } while (line <= range->end) { - regset = zend_jit_get_scratch_regset(op_array, ssa, line, current->ssa_var); + regset = zend_jit_get_scratch_regset( + op_array->opcodes + line, + ssa->ops + line, + op_array, ssa, current->ssa_var); ZEND_REGSET_FOREACH(regset, reg) { if (line < freeUntilPos[reg]) { freeUntilPos[reg] = line; diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 3029d911ba..2306c7a392 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -10895,13 +10895,13 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op return 1; } -static zend_bool zend_jit_may_reuse_reg(const zend_op_array *op_array, zend_ssa *ssa, uint32_t position, int def_var, int use_var) +static zend_bool zend_jit_may_reuse_reg(const zend_op *opline, const zend_ssa_op *ssa_op, zend_ssa *ssa, int def_var, int use_var) { if (ssa->var_info[def_var].type != ssa->var_info[use_var].type) { return 0; } - switch (op_array->opcodes[position].opcode) { + switch (opline->opcode) { case ZEND_QM_ASSIGN: case ZEND_SEND_VAR: case ZEND_ASSIGN: @@ -10916,8 +10916,8 @@ static zend_bool zend_jit_may_reuse_reg(const zend_op_array *op_array, zend_ssa case ZEND_BW_OR: case ZEND_BW_AND: case ZEND_BW_XOR: - if (def_var == ssa->ops[position].result_def && - use_var == ssa->ops[position].op1_use) { + if (def_var == ssa_op->result_def && + use_var == ssa_op->op1_use) { return 1; } break; @@ -11068,10 +11068,8 @@ static zend_bool zend_needs_extra_reg_for_const(const zend_op_array *op_array, c return 0; } -static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, zend_ssa *ssa, uint32_t line, int current_var) +static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var) { - const zend_op *opline = op_array->opcodes + line; - const zend_ssa_op *ssa_op = ssa->ops + line; uint32_t op1_info, op2_info, res_info; zend_regset regset = ZEND_REGSET_SCRATCH; @@ -11178,7 +11176,7 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, ze regset = ZEND_REGSET_EMPTY; if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) { if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, line))) { + (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, ssa_op - ssa->ops))) { ZEND_REGSET_INCL(regset, ZREG_R0); } res_info = OP1_INFO(); @@ -11200,14 +11198,14 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, ze } else { ZEND_REGSET_INCL(regset, ZREG_XMM0); if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, line))) { + (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, ssa_op - ssa->ops))) { ZEND_REGSET_INCL(regset, ZREG_XMM1); } } } if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) { if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, line))) { + (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, ssa_op - ssa->ops))) { ZEND_REGSET_INCL(regset, ZREG_XMM0); } } @@ -11226,7 +11224,7 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, ze !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) { regset = ZEND_REGSET_EMPTY; if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, line))) { + (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, ssa_op - ssa->ops))) { ZEND_REGSET_INCL(regset, ZREG_R0); } } @@ -11239,7 +11237,7 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, ze !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) { regset = ZEND_REGSET_EMPTY; if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, line))) { + (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, ssa_op - ssa->ops))) { ZEND_REGSET_INCL(regset, ZREG_R0); } if (opline->op2_type != IS_CONST && ssa_op->op2_use != current_var) { @@ -11257,7 +11255,7 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, ze Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG && zend_long_is_power_of_two(Z_LVAL_P(RT_CONSTANT(opline, opline->op2)))) { if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, line))) { + (ssa_op->op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, ssa_op - ssa->ops))) { ZEND_REGSET_INCL(regset, ZREG_R0); } } else { @@ -11339,11 +11337,13 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, ze #if ZTS /* %r0 is used to check EG(vm_interrupt) */ - { - uint32_t b = ssa->cfg.map[line]; + if (zend_jit_trigger == ZEND_JIT_ON_HOT_TRACE) { + // TODO: loop detection ??? + } else { + uint32_t b = ssa->cfg.map[ssa_op - ssa->ops]; if ((ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) != 0 - && ssa->cfg.blocks[b].start == line) { + && ssa->cfg.blocks[b].start == ssa_op - ssa->ops) { ZEND_REGSET_INCL(regset, ZREG_R0); } } diff --git a/ext/opcache/jit/zend_jit_x86.h b/ext/opcache/jit/zend_jit_x86.h index 6a3b455105..71fcb93ae1 100644 --- a/ext/opcache/jit/zend_jit_x86.h +++ b/ext/opcache/jit/zend_jit_x86.h @@ -236,12 +236,12 @@ typedef uintptr_t zend_jit_addr; ((last_use) ? (1 << (_ZEND_ADDR_REG_LAST_USE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) \ ) -#define OP_REG(line, op) \ - (ra && ssa->ops[line].op >= 0 && ra[ssa->ops[line].op] ? \ - OP_REG_EX(ra[ssa->ops[line].op]->reg, \ - ra[ssa->ops[line].op]->store, \ - ra[ssa->ops[line].op]->load, \ - zend_ssa_is_last_use(op_array, ssa, ssa->ops[line].op, line) \ +#define OP_REG(ssa_op, op) \ + (ra && ssa_op->op >= 0 && ra[ssa_op->op] ? \ + OP_REG_EX(ra[ssa_op->op]->reg, \ + ra[ssa_op->op]->store, \ + ra[ssa_op->op]->load, \ + zend_ssa_is_last_use(op_array, ssa, ssa_op->op, ssa_op - ssa->ops) \ ) : ZREG_NONE) static zend_always_inline zend_jit_addr _zend_jit_decode_op(zend_uchar op_type, znode_op op, const zend_op *opline, zend_reg reg) @@ -274,9 +274,9 @@ static zend_always_inline zend_jit_addr _zend_jit_decode_op(zend_uchar op_type, #define OP1_DATA_ADDR() \ OP_ADDR(opline + 1, op1_type, op1) -#define OP_REG_ADDR(opline, type, op, ssa_op) \ - _zend_jit_decode_op((opline)->type, (opline)->op, opline, \ - OP_REG((opline) - op_array->opcodes, ssa_op)) +#define OP_REG_ADDR(opline, type, _op, _ssa_op) \ + _zend_jit_decode_op((opline)->type, (opline)->_op, opline, \ + OP_REG(ssa_op, _ssa_op)) #define OP1_REG_ADDR() \ OP_REG_ADDR(opline, op1_type, op1, op1_use)