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 ||
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;
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:
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;
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;
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();
} 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);
}
}
!(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);
}
}
!(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) {
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 {
#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);
}
}
((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)
#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)