Skip to content

Commit 29a4918

Browse files
committed
Replace JMPZ with JMPZ_EX, avoid final branch for result init
Optimally, we'd still use JMPZ and avois smart branches. I'll see whether that's possible later.
1 parent 6618391 commit 29a4918

File tree

1 file changed

+61
-54
lines changed

1 file changed

+61
-54
lines changed

Zend/zend_compile.c

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6653,7 +6653,7 @@ typedef struct {
66536653
znode value;
66546654
} zend_pm_binding;
66556655

6656-
static void zend_compile_pattern(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context);
6656+
static void zend_compile_pattern(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context);
66576657
static zend_type zend_compile_single_typename(zend_ast *ast);
66586658

66596659
static void zend_pm_context_init(zend_pm_context *context)
@@ -6699,7 +6699,7 @@ static void zend_pm_labels_replace(zend_pm_context *context, uint32_t start_opnu
66996699
opline->op1.opline_num = labels[-opline->op1.opline_num];
67006700
}
67016701
break;
6702-
case ZEND_JMPZ:
6702+
case ZEND_JMPZ_EX:
67036703
if (opline->op2.opline_num >= label_lower_bound) {
67046704
opline->op2.opline_num = labels[-opline->op2.opline_num];
67056705
}
@@ -6709,12 +6709,21 @@ static void zend_pm_labels_replace(zend_pm_context *context, uint32_t start_opnu
67096709
}
67106710
}
67116711

6712-
static void zend_pm_compile_expr_like(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum)
6712+
static void zend_pm_emit_jmpz_ex(znode *result, uint32_t opnum_target)
67136713
{
6714-
znode result, value;
6714+
zend_op *opline = zend_emit_op(NULL, ZEND_JMPZ_EX, result, NULL);
6715+
opline->op2.opline_num = opnum_target;
6716+
SET_NODE(opline->result, result);
6717+
}
6718+
6719+
static void zend_pm_compile_expr_like(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum)
6720+
{
6721+
znode value;
67156722
zend_compile_expr(&value, ast->child[0]);
6716-
zend_emit_op_tmp(&result, expr_node->op_type == IS_CV || consume_expr ? ZEND_IS_IDENTICAL : ZEND_CASE_STRICT, expr_node, &value);
6717-
zend_emit_cond_jump(ZEND_JMPZ, &result, false_opnum);
6723+
zend_op *opline = zend_emit_op_tmp(NULL, expr_node->op_type == IS_CV || consume_expr ? ZEND_IS_IDENTICAL : ZEND_CASE_STRICT, expr_node, &value);
6724+
SET_NODE(opline->result, result);
6725+
6726+
zend_pm_emit_jmpz_ex(result, false_opnum);
67186727
}
67196728

67206729
static void zend_pm_verify_parenthesized_compound_pattern(zend_ast *ast, zend_ast_kind kind)
@@ -6729,7 +6738,7 @@ static void zend_pm_verify_parenthesized_compound_pattern(zend_ast *ast, zend_as
67296738
}
67306739
}
67316740

6732-
static void zend_pm_compile_or(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
6741+
static void zend_pm_compile_or(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
67336742
{
67346743
zend_pm_verify_parenthesized_compound_pattern(ast, ZEND_AST_AND_PATTERN);
67356744

@@ -6745,12 +6754,12 @@ static void zend_pm_compile_or(zend_ast *ast, znode *expr_node, bool consume_exp
67456754
zend_pm_label_set_next(context, next_label);
67466755
}
67476756
next_label = zend_pm_label_create(context);
6748-
zend_compile_pattern(ast_list->child[i], expr_node, false, next_label, context);
6757+
zend_compile_pattern(ast_list->child[i], result, expr_node, false, next_label, context);
67496758
zend_emit_jump(true_label);
67506759
}
67516760
zend_pm_label_set_next(context, next_label);
67526761

6753-
zend_compile_pattern(ast_list->child[ast_list->children - 1], expr_node, false, false_label, context);
6762+
zend_compile_pattern(ast_list->child[ast_list->children - 1], result, expr_node, false, false_label, context);
67546763

67556764
zend_pm_label_set_next(context, true_label);
67566765
if (consume_expr) {
@@ -6767,15 +6776,15 @@ static void zend_pm_compile_or(zend_ast *ast, znode *expr_node, bool consume_exp
67676776
context->inside_or_pattern = false;
67686777
}
67696778

6770-
static void zend_pm_compile_and(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
6779+
static void zend_pm_compile_and(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
67716780
{
67726781
zend_pm_verify_parenthesized_compound_pattern(ast, ZEND_AST_OR_PATTERN);
67736782

67746783
zend_ast_list *ast_list = zend_ast_get_list(ast);
67756784
uint32_t false_label = consume_expr ? zend_pm_label_create(context) : false_opnum;
67766785

67776786
for (uint32_t i = 0; i < ast_list->children; i++) {
6778-
zend_compile_pattern(ast_list->child[i], expr_node, false, false_label, context);
6787+
zend_compile_pattern(ast_list->child[i], result, expr_node, false, false_label, context);
67796788
}
67806789

67816790
if (consume_expr) {
@@ -6790,7 +6799,7 @@ static void zend_pm_compile_and(zend_ast *ast, znode *expr_node, bool consume_ex
67906799
}
67916800
}
67926801

6793-
static void zend_pm_compile_type(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum)
6802+
static void zend_pm_compile_type(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum)
67946803
{
67956804
zend_ast *type_ast = ast->child[0];
67966805
bool nullable = type_ast->attr & ZEND_TYPE_NULLABLE;
@@ -6808,12 +6817,12 @@ static void zend_pm_compile_type(zend_ast *ast, znode *expr_node, bool consume_e
68086817
Z_PTR_P(&type_node.u.constant) = type;
68096818
Z_TYPE_INFO_P(&type_node.u.constant) = IS_TYPE;
68106819

6811-
znode result;
6812-
zend_emit_op(&result, ZEND_HAS_TYPE, expr_node, &type_node);
6820+
zend_op *opline = zend_emit_op(NULL, ZEND_HAS_TYPE, expr_node, &type_node);
6821+
SET_NODE(opline->result, result);
68136822
if (consume_expr) {
68146823
zend_emit_op(NULL, ZEND_FREE, expr_node, NULL);
68156824
}
6816-
zend_emit_cond_jump(ZEND_JMPZ, &result, false_opnum);
6825+
zend_pm_emit_jmpz_ex(result, false_opnum);
68176826
}
68186827

68196828
static void zend_pm_copy_tmp(znode *dest, znode *src, bool consume)
@@ -6825,7 +6834,7 @@ static void zend_pm_copy_tmp(znode *dest, znode *src, bool consume)
68256834
}
68266835
}
68276836

6828-
static void zend_pm_compile_binding(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
6837+
static void zend_pm_compile_binding(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
68296838
{
68306839
if (context->inside_or_pattern) {
68316840
zend_error_noreturn(E_COMPILE_ERROR, "Must not bind to variables inside | pattern");
@@ -6843,10 +6852,20 @@ static void zend_pm_compile_binding(zend_ast *ast, znode *expr_node, bool consum
68436852
}
68446853

68456854
zend_stack_push(&context->bindings, &binding);
6855+
6856+
// FIXME: This can be elided most of the time. It may not for:
6857+
// - $a is $b
6858+
// - $a is 42|$b
6859+
znode true_node;
6860+
true_node.op_type = IS_CONST;
6861+
ZVAL_TRUE(&true_node.u.constant);
6862+
zend_op *opline = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &true_node, NULL);
6863+
SET_NODE(opline->result, result);
68466864
}
68476865

68486866
static void zend_pm_compile_container(
68496867
zend_ast *ast,
6868+
znode *result,
68506869
znode *expr_node,
68516870
bool consume_expr,
68526871
uint32_t false_opnum,
@@ -6860,10 +6879,10 @@ static void zend_pm_compile_container(
68606879

68616880
/* Make sure the value is actually of the right type. */
68626881
zend_pm_copy_tmp(&expr_copy_node, expr_node, false);
6863-
znode is_array_node;
6864-
zend_op *is_array_op = zend_emit_op(&is_array_node, ZEND_TYPE_CHECK, &expr_copy_node, NULL);
6882+
zend_op *is_array_op = zend_emit_op(NULL, ZEND_TYPE_CHECK, &expr_copy_node, NULL);
6883+
SET_NODE(is_array_op->result, result);
68656884
is_array_op->extended_value = is_array ? MAY_BE_ARRAY : MAY_BE_OBJECT;
6866-
zend_emit_cond_jump(ZEND_JMPZ, &is_array_node, false_label);
6885+
zend_pm_emit_jmpz_ex(result, false_label);
68676886

68686887
if (is_array) {
68696888
/* Make sure the array has the right size. */
@@ -6875,11 +6894,11 @@ static void zend_pm_compile_container(
68756894
count_target_node.op_type = IS_CONST;
68766895
ZVAL_LONG(&count_target_node.u.constant, element_list->children);
68776896

6878-
znode count_ok_node;
6879-
zend_emit_op(&count_ok_node,
6897+
zend_op *count_ok_op = zend_emit_op(NULL,
68806898
(ast->attr & ZEND_ARRAY_PATTERN_NON_EXHAUSTIVE) ? ZEND_IS_SMALLER_OR_EQUAL : ZEND_IS_EQUAL,
68816899
&count_target_node, &count_node);
6882-
zend_emit_cond_jump(ZEND_JMPZ, &count_ok_node, false_label);
6900+
SET_NODE(count_ok_op->result, result);
6901+
zend_pm_emit_jmpz_ex(result, false_label);
68836902
}
68846903

68856904
/* Check elements. */
@@ -6908,7 +6927,7 @@ static void zend_pm_compile_container(
69086927
}
69096928

69106929
/* Compile element check. */
6911-
zend_compile_pattern(element_value_ast, &element_value_node, true, false_label, context);
6930+
zend_compile_pattern(element_value_ast, result, &element_value_node, true, false_label, context);
69126931
}
69136932

69146933
if (consume_expr) {
@@ -6927,29 +6946,29 @@ static void zend_pm_compile_container(
69276946
}
69286947
}
69296948

6930-
static void zend_compile_pattern(zend_ast *ast, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
6949+
static void zend_compile_pattern(zend_ast *ast, znode *result, znode *expr_node, bool consume_expr, uint32_t false_opnum, zend_pm_context *context)
69316950
{
69326951
switch (ast->kind) {
69336952
case ZEND_AST_EXPR_LIKE_PATTERN:
6934-
zend_pm_compile_expr_like(ast, expr_node, consume_expr, false_opnum);
6953+
zend_pm_compile_expr_like(ast, result, expr_node, consume_expr, false_opnum);
69356954
break;
69366955
case ZEND_AST_OR_PATTERN:
6937-
zend_pm_compile_or(ast, expr_node, consume_expr, false_opnum, context);
6956+
zend_pm_compile_or(ast, result, expr_node, consume_expr, false_opnum, context);
69386957
break;
69396958
case ZEND_AST_AND_PATTERN:
6940-
zend_pm_compile_and(ast, expr_node, consume_expr, false_opnum, context);
6959+
zend_pm_compile_and(ast, result, expr_node, consume_expr, false_opnum, context);
69416960
break;
69426961
case ZEND_AST_TYPE_PATTERN:
6943-
zend_pm_compile_type(ast, expr_node, consume_expr, false_opnum);
6962+
zend_pm_compile_type(ast, result, expr_node, consume_expr, false_opnum);
69446963
break;
69456964
case ZEND_AST_BINDING_PATTERN:
6946-
zend_pm_compile_binding(ast, expr_node, consume_expr, false_opnum, context);
6965+
zend_pm_compile_binding(ast, result, expr_node, consume_expr, false_opnum, context);
69476966
break;
69486967
case ZEND_AST_ARRAY_PATTERN:
6949-
zend_pm_compile_container(ast, expr_node, consume_expr, false_opnum, context, true);
6968+
zend_pm_compile_container(ast, result, expr_node, consume_expr, false_opnum, context, true);
69506969
break;
69516970
case ZEND_AST_OBJECT_PATTERN:
6952-
zend_pm_compile_container(ast, expr_node, consume_expr, false_opnum, context, false);
6971+
zend_pm_compile_container(ast, result, expr_node, consume_expr, false_opnum, context, false);
69536972
break;
69546973
EMPTY_SWITCH_DEFAULT_CASE();
69556974
}
@@ -7002,7 +7021,7 @@ static void zend_emit_is(znode *result, znode *expr_node, bool consume_expr, zen
70027021

70037022
uint32_t start_opnum = get_next_op_number();
70047023
uint32_t false_label = zend_pm_label_create(&context);
7005-
zend_compile_pattern(pattern_ast, &expr_copy_node, consume_expr, false_label, &context);
7024+
zend_compile_pattern(pattern_ast, result, &expr_copy_node, consume_expr, false_label, &context);
70067025

70077026
if (context.num_bindings) {
70087027
zend_pm_binding *binding = zend_stack_base(&context.bindings);
@@ -7028,35 +7047,21 @@ static void zend_emit_is(znode *result, znode *expr_node, bool consume_expr, zen
70287047
}
70297048
}
70307049

7031-
znode true_node;
7032-
true_node.op_type = IS_CONST;
7033-
ZVAL_TRUE(&true_node.u.constant);
7034-
if (result->op_type == IS_UNUSED) {
7035-
zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &true_node, NULL);
7036-
} else {
7037-
zend_op *opline_qm_assign = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &true_node, NULL);
7038-
SET_NODE(opline_qm_assign->result, result);
7039-
}
7040-
uint32_t jmp_end = zend_emit_jump(0);
7041-
7042-
zend_pm_label_set_next(&context, false_label);
7043-
70447050
if (context.num_bindings) {
7051+
uint32_t jmp_end = zend_emit_jump(0);
7052+
zend_pm_label_set_next(&context, false_label);
7053+
70457054
zend_pm_binding *binding = zend_stack_base(&context.bindings);
70467055
zend_pm_binding *binding_end = zend_stack_top(&context.bindings);
70477056
while (binding <= binding_end) {
70487057
zend_emit_op(NULL, ZEND_FREE, &binding->value, NULL);
70497058
binding++;
70507059
}
7051-
}
7052-
7053-
znode false_node;
7054-
false_node.op_type = IS_CONST;
7055-
ZVAL_FALSE(&false_node.u.constant);
7056-
zend_op *opline_qm_assign = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &false_node, NULL);
7057-
SET_NODE(opline_qm_assign->result, result);
70587060

7059-
zend_update_jump_target_to_next(jmp_end);
7061+
zend_update_jump_target_to_next(jmp_end);
7062+
} else {
7063+
zend_pm_label_set_next(&context, false_label);
7064+
}
70607065

70617066
zend_pm_labels_replace(&context, start_opnum);
70627067
zend_pm_context_free(&context);
@@ -7070,7 +7075,9 @@ static void zend_compile_is(znode *result, zend_ast *ast)
70707075
znode expr_node;
70717076
zend_compile_expr(&expr_node, expr_ast);
70727077

7073-
result->op_type = IS_UNUSED;
7078+
result->op_type = IS_TMP_VAR;
7079+
result->u.op.var = get_temporary_variable();
7080+
70747081
zend_emit_is(result, &expr_node, (expr_node.op_type & (IS_VAR|IS_TMP_VAR)), pattern_ast);
70757082
}
70767083

0 commit comments

Comments
 (0)