Skip to content

Commit bdcda90

Browse files
committed
Simplify branching logic
1 parent 3c17f24 commit bdcda90

File tree

1 file changed

+53
-47
lines changed

1 file changed

+53
-47
lines changed

ext/opcache/jit/zend_jit_ir.c

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4470,51 +4470,64 @@ static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr s
44704470
return 1;
44714471
}
44724472

4473-
static ir_ref jit_observer_fcall_is_unobserved(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4474-
ir_ref run_time_cache, if_trampoline_or_generator = IR_UNUSED, if_rt_cache = IR_UNUSED;
4473+
struct jit_observer_fcall_is_unobserved_data {
4474+
ir_ref if_unobserved;
4475+
ir_ref if_rt_cache;
4476+
ir_ref if_trampoline_or_generator;
4477+
};
4478+
4479+
static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobserved_start(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4480+
ir_ref run_time_cache;
4481+
struct jit_observer_fcall_is_unobserved_data data = {
4482+
.if_rt_cache = IS_UNUSED,
4483+
.if_trampoline_or_generator = IS_UNUSED,
4484+
};
44754485
if (func) {
44764486
ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
44774487
} else {
44784488
ZEND_ASSERT(rx != IR_UNUSED);
4479-
if_trampoline_or_generator = ir_IF(ir_AND_U32(
4489+
data.if_trampoline_or_generator = ir_IF(ir_AND_U32(
44804490
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
44814491
ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4482-
ir_IF_FALSE(if_trampoline_or_generator);
4492+
ir_IF_FALSE(data.if_trampoline_or_generator);
44834493
}
4484-
if (func && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4485-
// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4486-
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
4487-
ZEND_ASSERT(rx != IR_UNUSED);
4488-
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4489-
ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4490-
ir_IF_TRUE(if_odd);
4491-
4492-
ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4493-
4494-
ir_MERGE_WITH_EMPTY_FALSE(if_odd);
4495-
run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
4496-
} else {
4494+
if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0) {
4495+
if (ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
44974496
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)), (uintptr_t)ZEND_MAP_PTR(func->common.run_time_cache)));
4497+
} else {
4498+
ZEND_ASSERT(rx != IR_UNUSED);
4499+
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(func_ref ? func_ref : ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4500+
data.if_rt_cache = ir_IF(ir_NE(run_time_cache, IR_NULL));
4501+
ir_IF_TRUE(data.if_rt_cache);
44984502
}
44994503
} else {
45004504
ZEND_ASSERT(rx != IR_UNUSED);
4505+
// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
45014506
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4502-
if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4503-
ir_IF_TRUE(if_rt_cache);
4507+
ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4508+
ir_IF_TRUE(if_odd);
4509+
4510+
ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4511+
4512+
ir_MERGE_WITH_EMPTY_FALSE(if_odd);
4513+
run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
45044514
}
45054515
*observer_handler = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
45064516
ir_ref is_unobserved = ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED));
4507-
if (if_rt_cache != IR_UNUSED) {
4508-
ir_MERGE_WITH_EMPTY_FALSE(if_rt_cache);
4509-
is_unobserved = ir_PHI_2(IR_BOOL, is_unobserved, IR_TRUE);
4510-
*observer_handler = ir_PHI_2(IR_ADDR, *observer_handler, IR_NULL);
4517+
4518+
data.if_unobserved = ir_IF(is_unobserved);
4519+
ir_IF_FALSE(data.if_unobserved);
4520+
return data;
4521+
}
4522+
4523+
static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4524+
if (data->if_rt_cache != IR_UNUSED) {
4525+
ir_MERGE_WITH_EMPTY_FALSE(data->if_rt_cache);
45114526
}
4512-
if (if_trampoline_or_generator != IR_UNUSED) {
4513-
ir_MERGE_WITH_EMPTY_TRUE(if_trampoline_or_generator);
4514-
is_unobserved = ir_PHI_2(IR_BOOL, is_unobserved, IR_TRUE);
4515-
*observer_handler = ir_PHI_2(IR_ADDR, *observer_handler, IR_NULL);
4527+
if (data->if_trampoline_or_generator != IR_UNUSED) {
4528+
ir_MERGE_WITH_EMPTY_TRUE(data->if_trampoline_or_generator);
45164529
}
4517-
return is_unobserved;
4530+
ir_MERGE_WITH_EMPTY_TRUE(data->if_unobserved);
45184531
}
45194532

45204533
static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
@@ -9940,15 +9953,13 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
99409953
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
99419954
ir_ref observer_handler;
99429955
ir_ref rx = jit_FP(jit); // Not sure why we cannot reuse rx here, but have to refetch
9943-
ir_ref is_unobserved = jit_observer_fcall_is_unobserved(jit, func, &observer_handler, rx, func_ref);
9944-
ir_ref if_is_unobserved = ir_IF(is_unobserved);
9945-
ir_IF_FALSE(if_is_unobserved);
9956+
struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
99469957
if (GCC_GLOBAL_REGS) {
99479958
// EX(opline) = opline
99489959
ir_STORE(jit_EX(opline), jit_IP(jit));
99499960
}
99509961
jit_observer_fcall_begin(jit, rx, observer_handler);
9951-
ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved);
9962+
jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
99529963
}
99539964

99549965
if (trace) {
@@ -10076,14 +10087,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1007610087
ir_STORE(jit_EG(current_execute_data), rx);
1007710088

1007810089
bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10079-
ir_ref is_unobserved;
1008010090
if (may_have_observer) {
1008110091
ir_ref observer_handler;
10082-
is_unobserved = jit_observer_fcall_is_unobserved(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
10083-
ir_ref if_is_unobserved = ir_IF(is_unobserved);
10084-
ir_IF_FALSE(if_is_unobserved);
10092+
struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
1008510093
jit_observer_fcall_begin(jit, rx, observer_handler);
10086-
ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved);
10094+
jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
1008710095
}
1008810096

1008910097
// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
@@ -10124,10 +10132,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1012410132
}
1012510133

1012610134
if (may_have_observer) {
10127-
ir_ref if_is_unobserved = ir_IF(is_unobserved);
10128-
ir_IF_FALSE(if_is_unobserved);
1012910135
jit_observer_fcall_end(jit, rx, res_addr);
10130-
ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved);
1013110136
}
1013210137

1013310138
// JIT: EG(current_execute_data) = execute_data;
@@ -16758,7 +16763,7 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
1675816763
}
1675916764

1676016765
struct jit_frameless_observer_data {
16761-
ir_ref if_is_unobserved;
16766+
ir_ref if_unobserved;
1676216767
ir_ref reused_jit_ip;
1676316768
};
1676416769

@@ -16767,30 +16772,31 @@ static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_
1676716772
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
1676816773
ir_ref observer_handler;
1676916774
zend_function *fbc = ZEND_FLF_FUNC(opline);
16770-
ir_ref is_unobserved = jit_observer_fcall_is_unobserved(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED);
16771-
data.if_is_unobserved = ir_IF(is_unobserved);
16775+
// Not need for runtime cache or generator checks here, we just need if_unobserved
16776+
data.if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
1677216777

1677316778
// push args to a valid call frame, without copying
16774-
ir_IF_FALSE(data.if_is_unobserved);
16775-
16776-
// yes, we'll temporarily reuse the IP, but we don't want to handle this via the reuse_ip mechanism for simiplicity
1677716779
bool track_last_valid_opline = jit->track_last_valid_opline;
1677816780
const zend_op *last_valid_opline = jit->last_valid_opline;
1677916781
bool reuse_ip = jit->reuse_ip;
1678016782
if (reuse_ip) {
1678116783
data.reused_jit_ip = jit_IP(jit);
1678216784
}
1678316785
zend_jit_push_call_frame(jit, opline, NULL, fbc, 0, 0, checked_stack, ir_CONST_ADDR(fbc), IR_NULL);
16786+
// yes, we'll temporarily reuse the IP, but we don't want to handle this via the reuse_ip mechanism for simiplicity - we just reset IP to original in end
1678416787
jit->track_last_valid_opline = track_last_valid_opline;
1678516788
jit->last_valid_opline = last_valid_opline;
1678616789
jit->reuse_ip = reuse_ip;
1678716790

16791+
// push all args
1678816792
uint32_t call_num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
1678916793
switch (call_num_args) {
1679016794
case 3: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(3)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op1_data_ref), op1_data_info, 0); ZEND_FALLTHROUGH;
1679116795
case 2: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(2)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op2_ref), op2_info, 0); ZEND_FALLTHROUGH;
1679216796
case 1: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(1)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op1_ref), op1_info, 0);
1679316797
}
16798+
16799+
// Make call frame externally visible
1679416800
ir_ref rx = jit_IP(jit);
1679516801
ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
1679616802
ir_STORE(jit_EG(current_execute_data), rx);
@@ -16838,7 +16844,7 @@ static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless
1683816844
}
1683916845

1684016846
ir_ref skip = ir_END();
16841-
ir_IF_TRUE(data->if_is_unobserved);
16847+
ir_IF_TRUE(data->if_unobserved);
1684216848
return skip;
1684316849
}
1684416850

0 commit comments

Comments
 (0)