Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions ext/opcache/jit/ir/ir_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,33 @@ static IR_NEVER_INLINE void ir_collect_irreducible_loops(ir_ctx *ctx, uint32_t *
}
}

static IR_NEVER_INLINE void ir_check_loop_entry_in_preds(ir_ctx *ctx, uint32_t hdr, ir_worklist *work)
{
ir_block *blocks = ctx->cfg_blocks;
uint32_t *edges = ctx->cfg_edges;

ir_worklist_clear(work);
ir_bitset_incl(work->visited, blocks[hdr].idom);
ir_worklist_push(work, hdr);
while (ir_worklist_len(work)) {
ir_block *bb = &blocks[ir_worklist_pop(work)];

if (bb->flags & IR_BB_ENTRY) {
blocks[hdr].flags |= IR_BB_LOOP_WITH_ENTRY_IN_PREDS;
break;
}

uint32_t *p = &edges[bb->predecessors];
uint32_t count = bb->predecessors_count;

for (; count > 0; p++, count--) {
if (!ir_dominates(blocks, hdr, *p)) {
ir_worklist_push(work, *p);
}
}
}
}

int ir_find_loops(ir_ctx *ctx)
{
uint32_t b, j, n;
Expand Down Expand Up @@ -1284,6 +1311,12 @@ int ir_find_loops(ir_ctx *ctx)
}
}
}
bb = &blocks[b];
if (ctx->entries_count
&& (bb->flags & (IR_BB_LOOP_HEADER|IR_BB_LOOP_WITH_ENTRY)) == IR_BB_LOOP_HEADER
&& (bb->predecessors_count > 2 || (bb->flags & IR_BB_IRREDUCIBLE_LOOP))) {
ir_check_loop_entry_in_preds(ctx, b, &work);
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions ext/opcache/jit/ir/ir_fold.h
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,8 @@ IR_FOLD(MUL_OV(C_I64, C_I64))
int64_t res;
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
res = op1_insn->val.u64 * op2_insn->val.u64;
if ((op1_insn->val.i64 != 0 && res / op1_insn->val.i64 != op2_insn->val.i64) || res < min || res > max) {
if ((op1_insn->val.i64 == -1 && res == INT64_MIN)
|| (op1_insn->val.i64 != 0 && res / op1_insn->val.i64 != op2_insn->val.i64) || res < min || res > max) {
IR_FOLD_NEXT;
}
IR_FOLD_CONST_U(res);
Expand Down Expand Up @@ -3333,7 +3334,7 @@ IR_FOLD(MIN(MIN, _))
IR_FOLD(MAX(MAX, _))
{
if (op1_insn->op1 == op2 || op1_insn->op2 == op2) {
IR_FOLD_COPY(op2);
IR_FOLD_COPY(op1);
}
IR_FOLD_NEXT;
}
Expand Down
4 changes: 2 additions & 2 deletions ext/opcache/jit/ir/ir_gcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ static uint32_t ir_gcm_select_best_block(ir_ctx *ctx, ir_ref ref, uint32_t lca)
#endif

flags = (bb->flags & IR_BB_LOOP_HEADER) ? bb->flags : ctx->cfg_blocks[bb->loop_header].flags;
if ((flags & IR_BB_LOOP_WITH_ENTRY)
if ((flags & (IR_BB_LOOP_WITH_ENTRY|IR_BB_LOOP_WITH_ENTRY_IN_PREDS))
&& !(ctx->binding && ir_binding_find(ctx, ref))) {
/* Don't move loop invariant code across an OSR ENTRY if we can't restore it */
return lca;
Expand Down Expand Up @@ -135,7 +135,7 @@ static uint32_t ir_gcm_select_best_block(ir_ctx *ctx, ir_ref ref, uint32_t lca)
break;
}
flags = (bb->flags & IR_BB_LOOP_HEADER) ? bb->flags : ctx->cfg_blocks[bb->loop_header].flags;
if ((flags & IR_BB_LOOP_WITH_ENTRY)
if ((flags & (IR_BB_LOOP_WITH_ENTRY|IR_BB_LOOP_WITH_ENTRY_IN_PREDS))
&& !(ctx->binding && ir_binding_find(ctx, ref))) {
break;
}
Expand Down
1 change: 1 addition & 0 deletions ext/opcache/jit/ir/ir_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ void ir_iter_cleanup(ir_ctx *ctx);
#define IR_BB_PREV_EMPTY_ENTRY (1<<7)
#define IR_BB_OSR_ENTRY_LOADS (1<<8) /* OSR Entry-point with register LOADs */
#define IR_BB_LOOP_WITH_ENTRY (1<<9) /* set together with LOOP_HEADER if there is an ENTRY in the loop */
#define IR_BB_LOOP_WITH_ENTRY_IN_PREDS (1<<18) /* set together with LOOP_HEADER if an ENTRY reaches the loop bypassing its immediate dominator */

/* The following flags are set by GCM */
#define IR_BB_HAS_PHI (1<<10)
Expand Down
24 changes: 24 additions & 0 deletions ext/opcache/tests/jit/bw_and_or_fold.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
JIT: IR folding of (a op b) op a for BW_AND and BW_OR
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit_buffer_size=64M
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
function or1(int $b) { return $b | ($b | 7); }
function or2(int $b) { return ($b | 7) | $b; }
function and1(int $b) { return $b & ($b & 7); }
function and2(int $b) { return ($b & 7) & $b; }

var_dump(or1(2), or2(2), and1(10), and2(10));
?>
--EXPECT--
int(7)
int(7)
int(2)
int(2)
31 changes: 31 additions & 0 deletions ext/opcache/tests/jit/gh25037.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
GH-25037 (Function JIT: "ENTRY - live var" for a namespaced function call with a recursive self:: call argument)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit_buffer_size=32M
opcache.jit=1205
--EXTENSIONS--
opcache
mbstring
--FILE--
<?php
namespace Reproduce;

class Entry
{
public static function chr(int $ord, string $encoding = 'UTF-8'): string
{
if ($encoding === 'UCS-4BE') {
return pack('N', $ord);
}

return mb_convert_encoding(self::chr($ord, 'UCS-4BE'), $encoding, 'UCS-4BE');
}
}

var_dump(bin2hex(Entry::chr(0x1F35E)));
?>
--EXPECT--
string(8) "f09f8d9e"
Loading