Skip to content

Commit 4b2bb20

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Update IR
2 parents 50b3222 + f77be08 commit 4b2bb20

File tree

8 files changed

+257
-60
lines changed

8 files changed

+257
-60
lines changed

ext/opcache/jit/ir/ir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,7 @@ IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size)
10321032
#define IR_ERROR_UNSUPPORTED_CODE_RULE 3
10331033
#define IR_ERROR_LINK 4
10341034
#define IR_ERROR_ENCODE 5
1035+
#define IR_ERROR_TOO_LARGE 6
10351036

10361037
/* IR Memmory Allocation */
10371038
#ifndef ir_mem_malloc

ext/opcache/jit/ir/ir_aarch64.dasc

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,16 +658,35 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co
658658
flags = IR_OP2_MUST_BE_IN_REG;
659659
constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
660660
n = 1;
661+
insn = &ctx->ir_base[ref];
662+
if (IR_IS_CONST_REF(insn->op2)) {
663+
constraints->tmp_regs[1] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
664+
n = 2;
665+
}
661666
break;
662667
case IR_VA_ARG:
663668
flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG;
664669
constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_SAVE_SUB_REF);
665670
n = 1;
671+
insn = &ctx->ir_base[ref];
672+
if (IR_IS_CONST_REF(insn->op2)) {
673+
constraints->tmp_regs[1] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
674+
n = 2;
675+
}
666676
break;
667677
case IR_VA_COPY:
668678
flags = IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG;
669679
constraints->tmp_regs[0] = IR_TMP_REG(1, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
670680
n = 1;
681+
insn = &ctx->ir_base[ref];
682+
if (IR_IS_CONST_REF(insn->op2)) {
683+
constraints->tmp_regs[n] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
684+
n++;
685+
}
686+
if (IR_IS_CONST_REF(insn->op3)) {
687+
constraints->tmp_regs[n] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
688+
n++;
689+
}
671690
break;
672691
}
673692
constraints->tmps_count = n;
@@ -6143,6 +6162,14 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
61436162
dasm_setup(&data.dasm_state, dasm_actions);
61446163
/* labels for each block + for each constant + rodata label + jmp_table label + for each entry + exit_table label */
61456164
dasm_growpc(&data.dasm_state, ctx->cfg_blocks_count + 1 + ctx->consts_count + 1 + 1 + 1 + ctx->entries_count + 1);
6165+
if (data.dasm_state->status != DASM_S_OK) {
6166+
IR_ASSERT(data.dasm_state->status == DASM_S_NOMEM);
6167+
dasm_free(&data.dasm_state);
6168+
ctx->data = NULL;
6169+
ctx->status = IR_ERROR_TOO_LARGE;
6170+
return NULL;
6171+
}
6172+
61466173
data.emit_constants = ir_bitset_malloc(ctx->consts_count);
61476174

61486175
if (!(ctx->flags & IR_SKIP_PROLOGUE)) {
@@ -6509,12 +6536,20 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
65096536
return NULL;
65106537
}
65116538

6539+
if (data.dasm_state->status != DASM_S_OK) {
6540+
IR_ASSERT(data.dasm_state->status == DASM_S_NOMEM);
6541+
dasm_free(&data.dasm_state);
6542+
ctx->data = NULL;
6543+
ctx->status = IR_ERROR_TOO_LARGE;
6544+
return NULL;
6545+
}
6546+
65126547
ret = dasm_link(&data.dasm_state, size_ptr);
65136548
if (ret != DASM_S_OK) {
6514-
IR_ASSERT(0);
6549+
IR_ASSERT(ret == DASM_S_NOMEM);
65156550
dasm_free(&data.dasm_state);
65166551
ctx->data = NULL;
6517-
ctx->status = IR_ERROR_LINK;
6552+
ctx->status = (ret == DASM_S_NOMEM) ? IR_ERROR_TOO_LARGE : IR_ERROR_LINK;
65186553
return NULL;
65196554
}
65206555
size = *size_ptr;

ext/opcache/jit/ir/ir_check.c

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,41 @@ void ir_consistency_check(void)
4040
IR_ASSERT(IR_ADD + 1 == IR_SUB);
4141
}
4242

43-
static bool ir_check_use_list(const ir_ctx *ctx, ir_ref from, ir_ref to)
43+
typedef struct {
44+
ir_arena *arena;
45+
ir_bitset *use_set;
46+
ir_bitset *input_set;
47+
} ir_check_ctx;
48+
49+
static bool ir_check_use_list(ir_check_ctx *check_ctx, const ir_ctx *ctx, ir_ref from, ir_ref to)
4450
{
4551
ir_ref n, *p;
4652
ir_use_list *use_list = &ctx->use_lists[from];
4753

4854
n = use_list->count;
55+
if (n > 16) {
56+
/* Avoid quadratic complexity by maintaining a temporary bit-set */
57+
ir_bitset set;
58+
59+
if (!check_ctx->use_set || !(set = check_ctx->use_set[from])) {
60+
if (!check_ctx->arena) {
61+
check_ctx->arena = ir_arena_create(sizeof(ir_arena) +
62+
ctx->insns_count * sizeof(ir_bitset) +
63+
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
64+
}
65+
if (!check_ctx->use_set) {
66+
check_ctx->use_set = ir_arena_alloc(&check_ctx->arena, ctx->insns_count * sizeof(ir_bitset));
67+
memset(check_ctx->use_set, 0, ctx->insns_count * sizeof(ir_bitset));
68+
}
69+
check_ctx->use_set[from] = set = (ir_bitset)ir_arena_alloc(&check_ctx->arena,
70+
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
71+
memset(set, 0, ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
72+
for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
73+
ir_bitset_incl(set, *p);
74+
}
75+
}
76+
return ir_bitset_in(set, to);
77+
}
4978
for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
5079
if (*p == to) {
5180
return 1;
@@ -54,12 +83,35 @@ static bool ir_check_use_list(const ir_ctx *ctx, ir_ref from, ir_ref to)
5483
return 0;
5584
}
5685

57-
static bool ir_check_input_list(const ir_ctx *ctx, ir_ref from, ir_ref to)
86+
static bool ir_check_input_list(ir_check_ctx *check_ctx, const ir_ctx *ctx, ir_ref from, ir_ref to)
5887
{
5988
ir_insn *insn = &ctx->ir_base[to];
6089
ir_ref n, j, *p;
6190

6291
n = ir_input_edges_count(ctx, insn);
92+
if (n > 16) {
93+
/* Avoid quadratic complexity by maintaining a temporary bit-set */
94+
ir_bitset set;
95+
96+
if (!check_ctx->input_set || !(set = check_ctx->input_set[to])) {
97+
if (!check_ctx->arena) {
98+
check_ctx->arena = ir_arena_create(sizeof(ir_arena) +
99+
ctx->insns_count * sizeof(ir_bitset) +
100+
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
101+
}
102+
if (!check_ctx->input_set) {
103+
check_ctx->input_set = ir_arena_alloc(&check_ctx->arena, ctx->insns_count * sizeof(ir_bitset));
104+
memset(check_ctx->input_set, 0, ctx->insns_count * sizeof(ir_bitset));
105+
}
106+
check_ctx->input_set[to] = set = (ir_bitset)ir_arena_alloc(&check_ctx->arena,
107+
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
108+
memset(set, 0, ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
109+
for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
110+
if (*p > 0) ir_bitset_incl(set, *p);
111+
}
112+
}
113+
return ir_bitset_in(set, from);
114+
}
63115
for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
64116
if (*p == from) {
65117
return 1;
@@ -93,6 +145,11 @@ bool ir_check(const ir_ctx *ctx)
93145
ir_type type;
94146
uint32_t flags;
95147
bool ok = 1;
148+
ir_check_ctx check_ctx;
149+
150+
check_ctx.arena = NULL;
151+
check_ctx.use_set = NULL;
152+
check_ctx.input_set = NULL;
96153

97154
for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
98155
if (insn->op >= IR_LAST_OP) {
@@ -255,7 +312,7 @@ bool ir_check(const ir_ctx *ctx)
255312
}
256313
if (ctx->use_lists
257314
&& use > 0
258-
&& !ir_check_use_list(ctx, use, i)) {
315+
&& !ir_check_use_list(&check_ctx, ctx, use, i)) {
259316
fprintf(stderr, "ir_base[%d].ops[%d] is not in use list (%d)\n", i, j, use);
260317
ok = 0;
261318
}
@@ -313,7 +370,7 @@ bool ir_check(const ir_ctx *ctx)
313370

314371
for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
315372
use = *p;
316-
if (!ir_check_input_list(ctx, i, use)) {
373+
if (!ir_check_input_list(&check_ctx, ctx, i, use)) {
317374
fprintf(stderr, "ir_base[%d] is in use list of ir_base[%d]\n", use, i);
318375
ok = 0;
319376
}
@@ -393,6 +450,10 @@ bool ir_check(const ir_ctx *ctx)
393450
insn += n;
394451
}
395452

453+
if (check_ctx.arena) {
454+
ir_arena_free(check_ctx.arena);
455+
}
456+
396457
// if (!ok) {
397458
// ir_dump_codegen(ctx, stderr);
398459
// }

ext/opcache/jit/ir/ir_emit.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@
3232
do { \
3333
size_t _sz = (sz), _need = (need); \
3434
if (_sz < _need) { \
35+
size_t _limit = sizeof(t) * DASM_SEC2POS(1); \
36+
if (_need > _limit) { \
37+
Dst_REF->status = DASM_S_NOMEM; \
38+
return; \
39+
} \
3540
if (_sz < 16) _sz = 16; \
3641
while (_sz < _need) _sz += _sz; \
42+
if (_sz > _limit) _sz = _limit; \
3743
(p) = (t *)ir_mem_realloc((p), _sz); \
3844
(sz) = _sz; \
3945
} \

ext/opcache/jit/ir/ir_fold.h

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,8 @@ IR_FOLD(DIV(C_ADDR, C_ADDR))
538538
IR_FOLD(DIV(C_I8, C_I8))
539539
{
540540
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
541-
if (op2_insn->val.i64 == 0) {
541+
if (op2_insn->val.i64 == 0
542+
|| (op2_insn->val.i64 == -1 && op1_insn->val.u8 == 0x80)) {
542543
/* division by zero */
543544
IR_FOLD_EMIT;
544545
}
@@ -548,7 +549,8 @@ IR_FOLD(DIV(C_I8, C_I8))
548549
IR_FOLD(DIV(C_I16, C_I16))
549550
{
550551
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
551-
if (op2_insn->val.i64 == 0) {
552+
if (op2_insn->val.i64 == 0
553+
|| (op2_insn->val.i64 == -1 && op1_insn->val.u16 == 0x8000)) {
552554
/* division by zero */
553555
IR_FOLD_EMIT;
554556
}
@@ -558,7 +560,8 @@ IR_FOLD(DIV(C_I16, C_I16))
558560
IR_FOLD(DIV(C_I32, C_I32))
559561
{
560562
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
561-
if (op2_insn->val.i64 == 0) {
563+
if (op2_insn->val.i64 == 0
564+
|| (op2_insn->val.i64 == -1 && op1_insn->val.u32 == 0x80000000)) {
562565
/* division by zero */
563566
IR_FOLD_EMIT;
564567
}
@@ -568,7 +571,8 @@ IR_FOLD(DIV(C_I32, C_I32))
568571
IR_FOLD(DIV(C_I64, C_I64))
569572
{
570573
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
571-
if (op2_insn->val.i64 == 0) {
574+
if (op2_insn->val.i64 == 0
575+
|| (op2_insn->val.i64 == -1 && op1_insn->val.u64 == 0x8000000000000000)) {
572576
/* division by zero */
573577
IR_FOLD_EMIT;
574578
}
@@ -615,12 +619,27 @@ IR_FOLD(MOD(C_I64, C_I64))
615619
}
616620

617621
IR_FOLD(NEG(C_I8))
622+
{
623+
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
624+
IR_FOLD_CONST_I((int8_t)(0 - op1_insn->val.u8));
625+
}
626+
618627
IR_FOLD(NEG(C_I16))
628+
{
629+
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
630+
IR_FOLD_CONST_I((int16_t)(0 -op1_insn->val.u16));
631+
}
632+
619633
IR_FOLD(NEG(C_I32))
634+
{
635+
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
636+
IR_FOLD_CONST_I((int32_t)(0 - op1_insn->val.u32));
637+
}
638+
620639
IR_FOLD(NEG(C_I64))
621640
{
622641
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
623-
IR_FOLD_CONST_I(-op1_insn->val.u64);
642+
IR_FOLD_CONST_I(0 - op1_insn->val.u64);
624643
}
625644

626645
IR_FOLD(NEG(C_DOUBLE))
@@ -1841,6 +1860,12 @@ IR_FOLD(ADD(SUB, _))
18411860
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
18421861
if (op1_insn->op2 == op2) {
18431862
/* (a - b) + b => a */
1863+
if (ctx->ir_base[op1_insn->op1].type != IR_OPT_TYPE(opt)) {
1864+
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
1865+
op1 = op1_insn->op1;
1866+
op2 = IR_UNUSED;
1867+
IR_FOLD_RESTART;
1868+
}
18441869
IR_FOLD_COPY(op1_insn->op1);
18451870
}
18461871
}
@@ -1852,6 +1877,12 @@ IR_FOLD(ADD(_, SUB))
18521877
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
18531878
if (op2_insn->op2 == op1) {
18541879
/* a + (b - a) => b */
1880+
if (ctx->ir_base[op2_insn->op1].type != IR_OPT_TYPE(opt)) {
1881+
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
1882+
op1 = op2_insn->op1;
1883+
op2 = IR_UNUSED;
1884+
IR_FOLD_RESTART;
1885+
}
18551886
IR_FOLD_COPY(op2_insn->op1);
18561887
}
18571888
}
@@ -1863,9 +1894,21 @@ IR_FOLD(SUB(ADD, _))
18631894
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
18641895
if (op1_insn->op1 == op2) {
18651896
/* (a + b) - a => b */
1897+
if (ctx->ir_base[op1_insn->op2].type != IR_OPT_TYPE(opt)) {
1898+
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
1899+
op1 = op1_insn->op2;
1900+
op2 = IR_UNUSED;
1901+
IR_FOLD_RESTART;
1902+
}
18661903
IR_FOLD_COPY(op1_insn->op2);
18671904
} else if (op1_insn->op2 == op2) {
18681905
/* (a + b) - a => b */
1906+
if (ctx->ir_base[op1_insn->op1].type != IR_OPT_TYPE(opt)) {
1907+
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
1908+
op1 = op1_insn->op1;
1909+
op2 = IR_UNUSED;
1910+
IR_FOLD_RESTART;
1911+
}
18691912
IR_FOLD_COPY(op1_insn->op1);
18701913
}
18711914
}
@@ -1911,6 +1954,12 @@ IR_FOLD(SUB(_, SUB))
19111954
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
19121955
if (op2_insn->op1 == op1) {
19131956
/* a - (a - b) => b */
1957+
if (ctx->ir_base[op2_insn->op2].type != IR_OPT_TYPE(opt)) {
1958+
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
1959+
op1 = op2_insn->op2;
1960+
op2 = IR_UNUSED;
1961+
IR_FOLD_RESTART;
1962+
}
19141963
IR_FOLD_COPY(op2_insn->op2);
19151964
}
19161965
}

ext/opcache/jit/ir/ir_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ IR_ALWAYS_INLINE ir_arena* ir_arena_create(size_t size)
238238

239239
IR_ASSERT(size >= IR_ALIGNED_SIZE(sizeof(ir_arena), 8));
240240
arena = (ir_arena*)ir_mem_malloc(size);
241+
if (UNEXPECTED(!arena))return NULL;
241242
arena->ptr = (char*) arena + IR_ALIGNED_SIZE(sizeof(ir_arena), 8);
242243
arena->end = (char*) arena + size;
243244
arena->prev = NULL;
@@ -267,6 +268,7 @@ IR_ALWAYS_INLINE void* ir_arena_alloc(ir_arena **arena_ptr, size_t size)
267268
(size_t)(arena->end - (char*) arena);
268269
ir_arena *new_arena = (ir_arena*)ir_mem_malloc(arena_size);
269270

271+
if (UNEXPECTED(!new_arena)) return NULL;
270272
ptr = (char*) new_arena + IR_ALIGNED_SIZE(sizeof(ir_arena), 8);
271273
new_arena->ptr = (char*) new_arena + IR_ALIGNED_SIZE(sizeof(ir_arena), 8) + size;
272274
new_arena->end = (char*) new_arena + arena_size;

0 commit comments

Comments
 (0)