2121
2222#if defined(IR_TARGET_X86)
2323# define IR_REG_SP 4 /* IR_REG_RSP */
24+ # define IR_REG_FP 5 /* IR_REG_RBP */
2425# define ZREG_FP 6 /* IR_REG_RSI */
2526# define ZREG_IP 7 /* IR_REG_RDI */
2627# define ZREG_FIRST_FPR 8
2728# define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7)) /* all preserved registers */
2829#elif defined(IR_TARGET_X64)
2930# define IR_REG_SP 4 /* IR_REG_RSP */
31+ # define IR_REG_FP 5 /* IR_REG_RBP */
3032# define ZREG_FP 14 /* IR_REG_R14 */
3133# define ZREG_IP 15 /* IR_REG_R15 */
3234# define ZREG_FIRST_FPR 16
4244# endif
4345#elif defined(IR_TARGET_AARCH64)
4446# define IR_REG_SP 31 /* IR_REG_RSP */
47+ # define IR_REG_FP 29 /* IR_REG_X29 */
4548# define ZREG_FP 27 /* IR_REG_X27 */
4649# define ZREG_IP 28 /* IR_REG_X28 */
4750# define ZREG_FIRST_FPR 32
@@ -676,9 +679,17 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps
676679
677680 if (ref > 0) {
678681 if (reg != ZREG_NONE) {
679- t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
680682 if (reg & IR_REG_SPILL_LOAD) {
681- t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_LOAD;
683+ ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
684+ /* spill slot on a CPU stack */
685+ t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
686+ t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
687+ t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
688+ } else if (reg & IR_REG_SPILL_SPECIAL) {
689+ /* spill slot on a VM stack */
690+ t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
691+ } else {
692+ t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
682693 }
683694 } else {
684695 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
@@ -1149,6 +1160,29 @@ static ir_ref jit_Z_DVAL_ref(zend_jit_ctx *jit, ir_ref ref)
11491160 return ir_LOAD_D(ref);
11501161}
11511162
1163+ static bool zend_jit_spilling_may_cause_conflict(zend_jit_ctx *jit, int var, ir_ref val)
1164+ {
1165+ // if (jit->ctx.ir_base[val].op == IR_RLOAD) {
1166+ // /* Deoptimization */
1167+ // return 0;
1168+ // }
1169+ // if (jit->ctx.ir_base[val].op == IR_LOAD
1170+ // && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1171+ // && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1172+ // && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1173+ // && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1174+ // && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr == (uintptr_t)EX_NUM_TO_VAR(jit->ssa->vars[var].var)) {
1175+ // /* LOAD from the same location (the LOAD is pinned) */
1176+ // // TODO: should be anti-dependent with the following stores ???
1177+ // return 0;
1178+ // }
1179+ // if (jit->ssa->vars[var].var < jit->current_op_array->last_var) {
1180+ // /* IS_CV */
1181+ // return 0;
1182+ // }
1183+ return 1;
1184+ }
1185+
11521186static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
11531187{
11541188 int var;
@@ -1161,46 +1195,8 @@ static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
11611195 }
11621196 ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
11631197
1164- /* Disable CSE for temporary variables */
1165- /* TODO: This is a workarounf to fix ext/standard/tests/strings/htmlentities20.phpt failure with tracing JIT ??? */
1166- if (0 && val > 0 && jit->ssa->vars[var].var >= jit->current_op_array->last_var) {
1167- ir_insn *insn = &jit->ctx.ir_base[val];
1168- ir_op op = insn->op;
1169-
1170- if (op <= IR_LAST_FOLDABLE_OP && jit->ctx.prev_insn_chain[op]) {
1171- if (jit->ctx.prev_insn_chain[op] == val) {
1172- if (insn->prev_insn_offset) {
1173- jit->ctx.prev_insn_chain[op] = val - (ir_ref)(uint32_t)insn->prev_insn_offset;
1174- } else {
1175- jit->ctx.prev_insn_chain[op] = IR_UNUSED;
1176- }
1177- } else {
1178- ir_ref prev = jit->ctx.prev_insn_chain[op];
1179- ir_ref tmp;
1180-
1181- while (prev) {
1182- insn = &jit->ctx.ir_base[prev];
1183- if (!insn->prev_insn_offset) {
1184- break;
1185- }
1186- tmp = prev - (ir_ref)(uint32_t)insn->prev_insn_offset;
1187- if (tmp == val) {
1188- ir_ref offset = jit->ctx.ir_base[tmp].prev_insn_offset;
1189-
1190- if (!offset || prev - tmp + offset > 0xffff) {
1191- insn->prev_insn_offset = 0;
1192- } else {
1193- insn->prev_insn_offset = prev - tmp + offset;
1194- }
1195- }
1196- prev = tmp;
1197- }
1198- }
1199- }
1200- }
1201-
12021198 /* Negative "var" has special meaning for IR */
1203- if (val > 0 && jit->ssa->vars[ var].var < jit->current_op_array->last_var ) {
1199+ if (val > 0 && !zend_jit_spilling_may_cause_conflict( jit, var, val) ) {
12041200 val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
12051201 }
12061202 jit->ra[var].ref = val;
@@ -2623,7 +2619,7 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
26232619 jit->ctx.fixed_call_stack_size = 16;
26242620#endif
26252621#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2626- jit->ctx.fixed_regset |= (1<<5 ); /* prevent %rbp (%r5) usage */
2622+ jit->ctx.fixed_regset |= (1<<IR_REG_FP ); /* prevent %rbp (%r5) usage */
26272623#endif
26282624 }
26292625 }
@@ -4148,6 +4144,43 @@ static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t
41484144 return 1;
41494145}
41504146
4147+ static int zend_jit_store_spill_slot(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, int32_t offset, bool set_type)
4148+ {
4149+ zend_jit_addr src;
4150+ zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4151+
4152+ if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4153+ src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4154+ if (jit->ra && jit->ra[var].ref == IR_NULL) {
4155+ zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4156+ } else {
4157+ jit_set_Z_LVAL(jit, dst, src);
4158+ if (set_type &&
4159+ (Z_REG(dst) != ZREG_FP ||
4160+ !JIT_G(current_frame) ||
4161+ STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4162+ jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4163+ }
4164+ }
4165+ } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4166+ src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4167+ if (jit->ra && jit->ra[var].ref == IR_NULL) {
4168+ zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4169+ } else {
4170+ jit_set_Z_DVAL(jit, dst, src);
4171+ if (set_type &&
4172+ (Z_REG(dst) != ZREG_FP ||
4173+ !JIT_G(current_frame) ||
4174+ STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4175+ jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4176+ }
4177+ }
4178+ } else {
4179+ ZEND_UNREACHABLE();
4180+ }
4181+ return 1;
4182+ }
4183+
41514184static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
41524185{
41534186 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
@@ -6169,6 +6202,9 @@ static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
61696202 phi = ir_PHI_N(res_inputs->count, res_inputs->refs);
61706203 }
61716204 if (Z_MODE(var_addr) == IS_REG) {
6205+ if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6206+ phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6207+ }
61726208 zend_jit_def_reg(jit, var_addr, phi);
61736209 if (real_res_addr) {
61746210 if (var_def_info & MAY_BE_LONG) {
@@ -15547,6 +15583,20 @@ static void *zend_jit_finish(zend_jit_ctx *jit)
1554715583 }
1554815584 } else {
1554915585 /* Only for tracing JIT */
15586+ zend_jit_trace_info *t = jit->trace;
15587+ zend_jit_trace_stack *stack;
15588+ uint32_t i;
15589+
15590+ if (t) {
15591+ for (i = 0; i < t->stack_map_size; i++) {
15592+ stack = t->stack_map + i;
15593+ if (stack->flags & ZREG_SPILL_SLOT) {
15594+ stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
15595+ stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
15596+ }
15597+ }
15598+ }
15599+
1555015600 zend_jit_trace_add_code(entry, size);
1555115601
1555215602#if ZEND_JIT_SUPPORT_CLDEMOTE
@@ -16023,12 +16073,12 @@ static int zend_jit_trace_start(zend_jit_ctx *jit,
1602316073
1602416074 if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
1602516075 /* op3 is used as a flag that the value is already stored in memory.
16026- * In case the IR framework desides to spill the result of IR_LOAD,
16076+ * In case the IR framework decides to spill the result of IR_LOAD,
1602716077 * it doesn't have to store the value once again.
1602816078 *
1602916079 * See: insn->op3 check in ir_emit_rload()
1603016080 */
16031- ir_set_op(&jit->ctx, ref, 3, 1 );
16081+ ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i) );
1603216082 }
1603316083 }
1603416084 }
0 commit comments