Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsdos committed Oct 22, 2024
1 parent 207883e commit 9ad6e92
Show file tree
Hide file tree
Showing 9 changed files with 299 additions and 78 deletions.
105 changes: 105 additions & 0 deletions Zend/Optimizer/dfa_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,103 @@ static bool zend_dfa_try_to_replace_result(zend_op_array *op_array, zend_ssa *ss
return 0;
}

static bool dominates(const zend_basic_block *blocks, int a, int b) {
while (blocks[b].level > blocks[a].level) {
b = blocks[b].idom;
}
return a == b;
}

static bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_ssa *ssa, int var, int use)
{
int next_use;

if (ssa->vars[var].phi_use_chain) {
zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
do {
if (!ssa->vars[phi->ssa_var].no_val) {
return 0;
}
phi = zend_ssa_next_use_phi(ssa, var, phi);
} while (phi);
}

if (ssa->cfg.blocks[ssa->cfg.map[use]].loop_header > 0
|| (ssa->cfg.blocks[ssa->cfg.map[use]].flags & ZEND_BB_LOOP_HEADER)) {
int b = ssa->cfg.map[use];
int prev_use = ssa->vars[var].use_chain;
int def_block;

if (ssa->vars[var].definition >= 0) {
def_block =ssa->cfg.map[ssa->vars[var].definition];
} else {
ZEND_ASSERT(ssa->vars[var].definition_phi);
def_block = ssa->vars[var].definition_phi->block;
}
if (dominates(ssa->cfg.blocks, def_block,
(ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) ? b : ssa->cfg.blocks[b].loop_header)) {
return 0;
}

while (prev_use >= 0 && prev_use != use) {
if (b != ssa->cfg.map[prev_use]
&& dominates(ssa->cfg.blocks, b, ssa->cfg.map[prev_use])
&& !zend_ssa_is_no_val_use(op_array->opcodes + prev_use, ssa->ops + prev_use, var)) {
return 0;
}
prev_use = zend_ssa_next_use(ssa->ops, var, prev_use);
}
}

next_use = zend_ssa_next_use(ssa->ops, var, use);
if (next_use < 0) {
return 1;
} else if (zend_ssa_is_no_val_use(op_array->opcodes + next_use, ssa->ops + next_use, var)) {
return 1;
}
return 0;
}

/* Sets a flag on SEND ops when a copy can be a avoided. */
static void zend_dfa_optimize_send_copies(zend_op_array *op_array, zend_ssa *ssa)
{
/* func_get_args(), indirect accesses and exceptions could make the optimization observable.
* The latter two cases are already tested before applying the DFA pass. */
ZEND_ASSERT(!op_array->last_try_catch);
ZEND_ASSERT(!(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS));
if (ssa->cfg.flags & ZEND_FUNC_VARARG) {
return;
}

for (uint32_t i = 0; i < op_array->last; i++) {
zend_op *opline = op_array->opcodes + i;
if ((opline->opcode != ZEND_SEND_VAR && opline->opcode != ZEND_SEND_VAR_EX)
|| opline->op2_type != IS_UNUSED
|| opline->op1_type != IS_CV) {
continue;
}

// TODO: prevent argument modification

zend_ssa_op *ssa_op = ssa->ops + i;

int ssa_cv = ssa_op->op1_use;

uint32_t type = ssa->var_info[ssa_cv].type;
if ((type & (MAY_BE_REF|MAY_BE_UNDEF|MAY_BE_ANY)) != MAY_BE_STRING || !(type & MAY_BE_RC1)) {
continue;
}

zend_ssa_var *ssa_var = ssa->vars + ssa_cv;
//printf("flags %d %d\n", ssa_var->no_val, ssa_var->alias);
//printf("is last use %d\n", zend_ssa_is_last_use(op_array, ssa, ssa_cv, i));
if (!ssa_var->alias && zend_ssa_is_last_use(op_array, ssa, ssa_cv, i)) { // TODO: don't copy-paste this function pls
//printf("hello %p\n", ssa_var);
opline->extended_value = 1;//TODO: no magic number pls
}
}
}

void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map)
{
if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) {
Expand Down Expand Up @@ -1148,6 +1245,14 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
#endif
}

/* Optimization should not be done on main because of globals. */
if (op_array->function_name) {
zend_dfa_optimize_send_copies(op_array, ssa);
#if ZEND_DEBUG_DFA
ssa_verify_integrity(op_array, ssa, "after optimize send copies");
#endif
}

for (v = op_array->last_var; v < ssa->vars_count; v++) {

op_1 = ssa->vars[v].definition;
Expand Down
43 changes: 33 additions & 10 deletions Zend/zend_operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -3059,7 +3059,22 @@ ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t
}
/* }}} */

ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
static zend_string* ZEND_FASTCALL zend_string_alloc_or_reuse(zend_string *str, bool persistent, bool in_place, const unsigned char *p)
{
if (in_place) {
//printf("in place!\n");
ZEND_ASSERT(!persistent);
zend_string_forget_hash_val(str);
GC_ADDREF(str);
return str;
} else {
zend_string *res = zend_string_alloc(ZSTR_LEN(str), persistent);
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
return res;
}
}

ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex2(zend_string *str, bool persistent, bool in_place) /* {{{ */
{
size_t length = ZSTR_LEN(str);
unsigned char *p = (unsigned char *) ZSTR_VAL(str);
Expand All @@ -3070,8 +3085,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo
while (p + BLOCKCONV_STRIDE <= end) {
BLOCKCONV_LOAD(p);
if (BLOCKCONV_FOUND()) {
zend_string *res = zend_string_alloc(length, persistent);
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
zend_string *res = zend_string_alloc_or_reuse(str, persistent, in_place, p);
unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));

/* Lowercase the chunk we already compared. */
Expand All @@ -3091,8 +3105,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo

while (p < end) {
if (*p != zend_tolower_ascii(*p)) {
zend_string *res = zend_string_alloc(length, persistent);
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
zend_string *res = zend_string_alloc_or_reuse(str, persistent, in_place, p);

unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
while (p < end) {
Expand All @@ -3108,7 +3121,13 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo
}
/* }}} */

ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
{
return zend_string_tolower_ex2(str, persistent, false);
}
/* }}} */

ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex2(zend_string *str, bool persistent, bool in_place) /* {{{ */
{
size_t length = ZSTR_LEN(str);
unsigned char *p = (unsigned char *) ZSTR_VAL(str);
Expand All @@ -3119,8 +3138,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, boo
while (p + BLOCKCONV_STRIDE <= end) {
BLOCKCONV_LOAD(p);
if (BLOCKCONV_FOUND()) {
zend_string *res = zend_string_alloc(length, persistent);
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
zend_string *res = zend_string_alloc_or_reuse(str, persistent, in_place, p);
unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));

/* Uppercase the chunk we already compared. */
Expand All @@ -3140,8 +3158,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, boo

while (p < end) {
if (*p != zend_toupper_ascii(*p)) {
zend_string *res = zend_string_alloc(length, persistent);
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
zend_string *res = zend_string_alloc_or_reuse(str, persistent, in_place, p);

unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
while (p < end) {
Expand All @@ -3157,6 +3174,12 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, boo
}
/* }}} */

ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */
{
return zend_string_toupper_ex2(str, persistent, false);
}
/* }}} */

ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
{
int retval;
Expand Down
6 changes: 4 additions & 2 deletions Zend/zend_operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,15 @@ ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup(const char *source, siz
ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length);
ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t length);
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent);
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex2(zend_string *str, bool persistent, bool in_place);
ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent);
ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex2(zend_string *str, bool persistent, bool in_place);

static zend_always_inline zend_string* zend_string_tolower(zend_string *str) {
return zend_string_tolower_ex(str, false);
return zend_string_tolower_ex2(str, false, false);
}
static zend_always_inline zend_string* zend_string_toupper(zend_string *str) {
return zend_string_toupper_ex(str, false);
return zend_string_toupper_ex2(str, false, false);
}

ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2);
Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1579,4 +1579,9 @@ static zend_always_inline bool zend_may_modify_arg_in_place(const zval *arg)
return Z_REFCOUNTED_P(arg) && !(GC_FLAGS(Z_COUNTED_P(arg)) & (GC_IMMUTABLE | GC_PERSISTENT)) && Z_REFCOUNT_P(arg) == 1;
}

static zend_always_inline bool zend_may_modify_string_in_place(const zend_string *arg)
{
return !(GC_FLAGS(arg) & (GC_IMMUTABLE | GC_PERSISTENT)) && GC_REFCOUNT(arg) == 1;
}

#endif /* ZEND_TYPES_H */
37 changes: 35 additions & 2 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -10256,7 +10256,7 @@ ZEND_VM_C_LABEL(fetch_dim_r_index_undef):
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM)
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && !op->extended_value && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM)
{
USE_OPLINE
zval *varptr, *arg;
Expand All @@ -10273,7 +10273,21 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && (op1_i
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, UNUSED|NUM)
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->extended_value /* extended_value implies OP2 UNUSED and OP1 not UNDEF or REF */, ZEND_SEND_VAR_SIMPLE_EXT, CV, NUM)
{
USE_OPLINE
zval *varptr, *arg;

varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
arg = ZEND_CALL_VAR(EX(call), opline->result.var);

ZVAL_COPY_VALUE(arg, varptr);
ZVAL_EMPTY_STRING(varptr);

ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && !op->extended_value && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, UNUSED|NUM)
{
USE_OPLINE
zval *varptr, *arg;
Expand All @@ -10295,6 +10309,25 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && op-
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->extended_value && op->op2.num <= MAX_ARG_FLAG_NUM /* extended_value implies OP2 UNUSED and OP1 not UNDEF or REF */, ZEND_SEND_VAR_EX_SIMPLE_EXT, CV, UNUSED|NUM)
{
USE_OPLINE
zval *varptr, *arg;
uint32_t arg_num = opline->op2.num;

if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
}

varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
arg = ZEND_CALL_VAR(EX(call), opline->result.var);

ZVAL_COPY_VALUE(arg, varptr);
ZVAL_EMPTY_STRING(varptr);

ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAL, op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)), ZEND_SEND_VAL_SIMPLE, CONST, NUM)
{
USE_OPLINE
Expand Down
Loading

0 comments on commit 9ad6e92

Please sign in to comment.