Skip to content

Commit 800c350

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: Update IR (#20710)
2 parents 284e202 + 8867294 commit 800c350

File tree

15 files changed

+1032
-385
lines changed

15 files changed

+1032
-385
lines changed

ext/opcache/jit/ir/ir.c

Lines changed: 169 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
118118
{
119119
char buf[128];
120120

121-
if (insn->op == IR_FUNC || insn->op == IR_SYM) {
121+
if (insn->op == IR_FUNC || insn->op == IR_SYM || insn->op == IR_LABEL) {
122122
fprintf(f, "%s", ir_get_str(ctx, insn->val.name));
123123
return;
124124
} else if (insn->op == IR_STR) {
@@ -290,6 +290,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
290290
#define ir_op_kind_prb IR_OPND_PROB
291291
#define ir_op_kind_opt IR_OPND_PROB
292292
#define ir_op_kind_pro IR_OPND_PROTO
293+
#define ir_op_kind_lbl IR_OPND_LABEL_REF
293294

294295
#define _IR_OP_FLAGS(name, flags, op1, op2, op3) \
295296
IR_OP_FLAGS(ir_op_flag_ ## flags, ir_op_kind_ ## op1, ir_op_kind_ ## op2, ir_op_kind_ ## op3),
@@ -689,6 +690,13 @@ ir_ref ir_const_str(ir_ctx *ctx, ir_ref str)
689690
return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_STR, IR_ADDR, 0));
690691
}
691692

693+
ir_ref ir_const_label(ir_ctx *ctx, ir_ref str)
694+
{
695+
ir_val val;
696+
val.u64 = str;
697+
return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_LABEL, IR_ADDR, 0));
698+
}
699+
692700
ir_ref ir_str(ir_ctx *ctx, const char *s)
693701
{
694702
size_t len;
@@ -879,6 +887,17 @@ static ir_ref _ir_fold_cse(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir
879887
return IR_UNUSED;
880888
}
881889

890+
IR_ALWAYS_INLINE ir_ref _ir_fold_cast(ir_ctx *ctx, ir_ref ref, ir_type type)
891+
{
892+
if (ctx->ir_base[ref].type == type) {
893+
return ref;
894+
} else if (IR_IS_CONST_REF(ref) && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)) {
895+
return ir_const(ctx, ctx->ir_base[ref].val, type);
896+
} else {
897+
return ir_emit1(ctx, IR_OPT(IR_BITCAST, type), ref);
898+
}
899+
}
900+
882901
#define IR_FOLD(X) IR_FOLD1(X, __LINE__)
883902
#define IR_FOLD1(X, Y) IR_FOLD2(X, Y)
884903
#define IR_FOLD2(X, Y) case IR_RULE_ ## Y:
@@ -1158,7 +1177,7 @@ ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def)
11581177
IR_ASSERT(var < 0);
11591178
if (!ir_hashtab_add(ctx->binding, def, var)) {
11601179
/* Add a copy with different binding */
1161-
def = ir_emit2(ctx, IR_OPT(IR_COPY, ctx->ir_base[def].type), def, 1);
1180+
def = ir_emit2(ctx, IR_OPT(IR_COPY, ctx->ir_base[def].type), def, IR_COPY_HARD);
11621181
ir_hashtab_add(ctx->binding, def, var);
11631182
}
11641183
return def;
@@ -1836,8 +1855,49 @@ int ir_mem_flush(void *ptr, size_t size)
18361855
return 1;
18371856
}
18381857
#else
1858+
1859+
#if defined(__linux__) && defined(__x86_64__) && defined(PKEY_DISABLE_WRITE)
1860+
# define HAVE_PKEY_MPROTECT 1
1861+
#endif
1862+
1863+
#ifdef HAVE_PKEY_MPROTECT
1864+
1865+
#ifndef PKEY_DISABLE_EXECUTE
1866+
# define PKEY_DISABLE_EXECUTE 0
1867+
#endif
1868+
1869+
int pkey_mprotect(void* addr, size_t len, int prot, int pkey) __attribute__((weak));
1870+
int pkey_alloc(unsigned int, unsigned int) __attribute__((weak));
1871+
int pkey_free(int) __attribute__((weak));
1872+
int pkey_set(int, unsigned) __attribute__((weak));
1873+
1874+
static int ir_pkey = 0;
1875+
#endif
1876+
18391877
void *ir_mem_mmap(size_t size)
18401878
{
1879+
#ifdef HAVE_PKEY_MPROTECT
1880+
if (!ir_pkey && pkey_mprotect) {
1881+
int key = pkey_alloc(0, PKEY_DISABLE_WRITE);
1882+
if (key > 0) {
1883+
ir_pkey = key;
1884+
}
1885+
}
1886+
if (ir_pkey > 0) {
1887+
void *ret = mmap(NULL, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1888+
if (ret == MAP_FAILED) {
1889+
return NULL;
1890+
}
1891+
if (pkey_mprotect(ret, size, PROT_EXEC|PROT_READ|PROT_WRITE, ir_pkey) != 0) {
1892+
#ifdef IR_DEBUG
1893+
fprintf(stderr, "pkey_mprotect() failed\n");
1894+
#endif
1895+
munmap(ret, size);
1896+
return NULL;
1897+
}
1898+
return ret;
1899+
}
1900+
#endif
18411901
int prot_flags = PROT_EXEC;
18421902
#if defined(__NetBSD__)
18431903
prot_flags |= PROT_MPROTECT(PROT_READ|PROT_WRITE);
@@ -1852,11 +1912,28 @@ void *ir_mem_mmap(size_t size)
18521912
int ir_mem_unmap(void *ptr, size_t size)
18531913
{
18541914
munmap(ptr, size);
1915+
#ifdef HAVE_PKEY_MPROTECT
1916+
// if (ir_pkey > 0) {
1917+
// pkey_free(ir_pkey);
1918+
// ir_pkey = 0;
1919+
// }
1920+
#endif
18551921
return 1;
18561922
}
18571923

18581924
int ir_mem_protect(void *ptr, size_t size)
18591925
{
1926+
#ifdef HAVE_PKEY_MPROTECT
1927+
if (ir_pkey > 0) {
1928+
if (pkey_set(ir_pkey, PKEY_DISABLE_WRITE)) {
1929+
#ifdef IR_DEBUG
1930+
fprintf(stderr, "mprotect() failed\n");
1931+
#endif
1932+
return 0;
1933+
}
1934+
return 1;
1935+
}
1936+
#endif
18601937
if (mprotect(ptr, size, PROT_READ | PROT_EXEC) != 0) {
18611938
#ifdef IR_DEBUG
18621939
fprintf(stderr, "mprotect() failed\n");
@@ -1868,6 +1945,17 @@ int ir_mem_protect(void *ptr, size_t size)
18681945

18691946
int ir_mem_unprotect(void *ptr, size_t size)
18701947
{
1948+
#ifdef HAVE_PKEY_MPROTECT
1949+
if (ir_pkey > 0) {
1950+
if (pkey_set(ir_pkey, PKEY_DISABLE_EXECUTE)) {
1951+
#ifdef IR_DEBUG
1952+
fprintf(stderr, "mprotect() failed\n");
1953+
#endif
1954+
return 0;
1955+
}
1956+
return 1;
1957+
}
1958+
#endif
18711959
if (mprotect(ptr, size, PROT_READ | PROT_WRITE) != 0) {
18721960
#ifdef IR_DEBUG
18731961
fprintf(stderr, "mprotect() failed\n");
@@ -2070,7 +2158,26 @@ IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(ir_ctx *ctx, ir_ref ref, ir_type
20702158
}
20712159
} else if (insn->op == IR_RSTORE) {
20722160
modified_regset |= (1 << insn->op3);
2073-
} else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_VSTORE) {
2161+
} else if (insn->op == IR_CALL) {
2162+
ir_insn *func = &ctx->ir_base[insn->op2];
2163+
ir_ref func_proto;
2164+
const ir_proto_t *proto;
2165+
2166+
if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
2167+
func_proto = func->proto;
2168+
} else if (func->op == IR_PROTO) {
2169+
func_proto = func->op2;
2170+
} else {
2171+
break;
2172+
}
2173+
if (!func_proto) {
2174+
break;
2175+
}
2176+
proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
2177+
if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) {
2178+
break;
2179+
}
2180+
} else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_VSTORE) {
20742181
return IR_UNUSED;
20752182
}
20762183
ref = insn->op1;
@@ -2116,7 +2223,26 @@ IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_typ
21162223
break;
21172224
}
21182225
}
2119-
} else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_STORE) {
2226+
} else if (insn->op == IR_CALL) {
2227+
ir_insn *func = &ctx->ir_base[insn->op2];
2228+
ir_ref func_proto;
2229+
const ir_proto_t *proto;
2230+
2231+
if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
2232+
func_proto = func->proto;
2233+
} else if (func->op == IR_PROTO) {
2234+
func_proto = func->op2;
2235+
} else {
2236+
break;
2237+
}
2238+
if (!func_proto) {
2239+
break;
2240+
}
2241+
proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
2242+
if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) {
2243+
break;
2244+
}
2245+
} else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_STORE) {
21202246
break;
21212247
}
21222248
ref = insn->op1;
@@ -3013,6 +3139,16 @@ void _ir_IJMP(ir_ctx *ctx, ir_ref addr)
30133139
ctx->control = IR_UNUSED;
30143140
}
30153141

3142+
ir_ref _ir_IGOTO(ir_ctx *ctx, ir_ref addr)
3143+
{
3144+
ir_ref ref;
3145+
3146+
IR_ASSERT(ctx->control);
3147+
ctx->control = ref = ir_emit2(ctx, IR_IGOTO, ctx->control, addr);
3148+
ctx->control = IR_UNUSED;
3149+
return ref;
3150+
}
3151+
30163152
ir_ref _ir_ADD_OFFSET(ir_ctx *ctx, ir_ref addr, uintptr_t offset)
30173153
{
30183154
if (offset) {
@@ -3135,6 +3271,18 @@ void _ir_VSTORE(ir_ctx *ctx, ir_ref var, ir_ref val)
31353271
ctx->control = ir_emit3(ctx, IR_VSTORE, ctx->control, var, val);
31363272
}
31373273

3274+
ir_ref _ir_VLOAD_v(ir_ctx *ctx, ir_type type, ir_ref var)
3275+
{
3276+
IR_ASSERT(ctx->control);
3277+
return ctx->control = ir_emit2(ctx, IR_OPT(IR_VLOAD_v, type), ctx->control, var);
3278+
}
3279+
3280+
void _ir_VSTORE_v(ir_ctx *ctx, ir_ref var, ir_ref val)
3281+
{
3282+
IR_ASSERT(ctx->control);
3283+
ctx->control = ir_emit3(ctx, IR_VSTORE_v, ctx->control, var, val);
3284+
}
3285+
31383286
ir_ref _ir_TLS(ir_ctx *ctx, ir_ref index, ir_ref offset)
31393287
{
31403288
IR_ASSERT(ctx->control);
@@ -3193,6 +3341,18 @@ void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val)
31933341
ctx->control = ir_emit3(ctx, IR_STORE, ctx->control, addr, val);
31943342
}
31953343

3344+
ir_ref _ir_LOAD_v(ir_ctx *ctx, ir_type type, ir_ref addr)
3345+
{
3346+
IR_ASSERT(ctx->control);
3347+
return ctx->control = ir_emit2(ctx, IR_OPT(IR_LOAD_v, type), ctx->control, addr);
3348+
}
3349+
3350+
void _ir_STORE_v(ir_ctx *ctx, ir_ref addr, ir_ref val)
3351+
{
3352+
IR_ASSERT(ctx->control);
3353+
ctx->control = ir_emit3(ctx, IR_STORE_v, ctx->control, addr, val);
3354+
}
3355+
31963356
void _ir_VA_START(ir_ctx *ctx, ir_ref list)
31973357
{
31983358
IR_ASSERT(ctx->control);
@@ -3217,11 +3377,13 @@ ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
32173377
return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list);
32183378
}
32193379

3220-
ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size)
3380+
ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size, size_t align)
32213381
{
32223382
IR_ASSERT(ctx->control);
3223-
IR_ASSERT(size <= 0x7fffffff);
3224-
return ctx->control = ir_emit3(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list, (ir_ref)size);
3383+
IR_ASSERT(size <= 0x0fffffff);
3384+
IR_ASSERT(align != 0 && ((align & (align - 1)) == 0) && align <= 128);
3385+
return ctx->control = ir_emit3(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list,
3386+
(ir_ref)IR_VA_ARG_OP3(size, align));
32253387
}
32263388

32273389
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx)

ext/opcache/jit/ir/ir.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ typedef enum _ir_type {
216216
* prb - branch probability 1-99 (0 - unspecified): (IF_TRUE, IF_FALSE, CASE_VAL, CASE_DEFAULT)
217217
* opt - optional number
218218
* pro - function prototype
219+
* lbl - label used as value (a reference to constant): (BEGIN)
219220
*
220221
* The order of IR opcodes is carefully selected for efficient folding.
221222
* - foldable instruction go first
@@ -322,6 +323,7 @@ typedef enum _ir_type {
322323
_(FUNC_ADDR, r0, ___, ___, ___) /* constant func ref */ \
323324
_(FUNC, r0, ___, ___, ___) /* constant func ref */ \
324325
_(SYM, r0, ___, ___, ___) /* constant symbol ref */ \
326+
_(LABEL, r0, ___, ___, ___) /* label address ref */ \
325327
_(STR, r0, ___, ___, ___) /* constant str ref */ \
326328
\
327329
/* call ops */ \
@@ -334,11 +336,15 @@ typedef enum _ir_type {
334336
_(BLOCK_BEGIN, a1, src, ___, ___) /* stacksave */ \
335337
_(BLOCK_END, a2, src, def, ___) /* stackrestore */ \
336338
_(VLOAD, l2, src, var, ___) /* load value of local var */ \
339+
_(VLOAD_v, l2, src, var, ___) /* volatile variant of VLOAD */ \
337340
_(VSTORE, s3, src, var, def) /* store value to local var */ \
341+
_(VSTORE_v, s3, src, var, def) /* volatile variant of VSTORE */ \
338342
_(RLOAD, l1X2, src, num, opt) /* load value from register */ \
339343
_(RSTORE, s2X1, src, def, num) /* store value into register */ \
340344
_(LOAD, l2, src, ref, ___) /* load from memory */ \
345+
_(LOAD_v, l2, src, ref, ___) /* volatile variant of VLOAD */ \
341346
_(STORE, s3, src, ref, def) /* store to memory */ \
347+
_(STORE_v, s3, src, ref, def) /* volatile variant of VSTORE */ \
342348
_(TLS, l1X2, src, num, num) /* thread local variable */ \
343349
_(TRAP, x1, src, ___, ___) /* DebugBreak */ \
344350
/* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ??? */ \
@@ -360,7 +366,7 @@ typedef enum _ir_type {
360366
/* control-flow nodes */ \
361367
_(START, S0X1, ret, ___, ___) /* function start */ \
362368
_(ENTRY, S1X1, src, num, ___) /* entry with a fake src edge */ \
363-
_(BEGIN, S1, src, ___, ___) /* block start */ \
369+
_(BEGIN, S1X1, src, lbl, ___) /* block start, optional &&lbl */ \
364370
_(IF_TRUE, S1X1, src, prb, ___) /* IF TRUE proj. */ \
365371
_(IF_FALSE, S1X1, src, prb, ___) /* IF FALSE proj. */ \
366372
_(CASE_VAL, S2X1, src, def, prb) /* switch proj. */ \
@@ -372,8 +378,9 @@ typedef enum _ir_type {
372378
_(LOOP_END, E1, src, ___, ___) /* loop end */ \
373379
_(IF, E2, src, def, ___) /* conditional control split */ \
374380
_(SWITCH, E2, src, def, ___) /* multi-way control split */ \
381+
_(IGOTO, E2, src, def, ___) /* computed goto (internal) */ \
382+
_(IJMP, T2X1, src, def, ret) /* computed goto (terminating) */ \
375383
_(RETURN, T2X1, src, def, ret) /* function return */ \
376-
_(IJMP, T2X1, src, def, ret) /* computed goto */ \
377384
_(UNREACHABLE, T1X2, src, ___, ret) /* unreachable (tailcall, etc) */ \
378385
\
379386
/* deoptimization helper */ \
@@ -400,6 +407,13 @@ typedef enum _ir_op {
400407
#define IR_OPTX(op, type, n) ((uint32_t)(op) | ((uint32_t)(type) << IR_OPT_TYPE_SHIFT) | ((uint32_t)(n) << IR_OPT_INPUTS_SHIFT))
401408
#define IR_OPT_TYPE(opt) (((opt) & IR_OPT_TYPE_MASK) >> IR_OPT_TYPE_SHIFT)
402409

410+
/* "opt" modifiers */
411+
#define IR_COPY_HARD (1<<0)
412+
413+
#define IR_VA_ARG_SIZE(op3) (((uint32_t)(op3) >> 3))
414+
#define IR_VA_ARG_ALIGN(op3) (1U << ((uint32_t)(op3) & 0x7))
415+
#define IR_VA_ARG_OP3(s, a) (((s) << 3) | ir_ntzl(a))
416+
403417
/* IR References */
404418
typedef int32_t ir_ref;
405419

@@ -533,6 +547,9 @@ void ir_strtab_free(ir_strtab *strtab);
533547
#define IR_EXTERN (1<<5)
534548
#define IR_CONST (1<<6)
535549

550+
#define IR_CONST_FUNC (1<<6)
551+
#define IR_PURE_FUNC (1<<7)
552+
536553
#define IR_INITIALIZED (1<<7) /* sym data flag: constant or an initialized variable */
537554
#define IR_CONST_STRING (1<<8) /* sym data flag: constant string */
538555

@@ -648,7 +665,6 @@ struct _ir_ctx {
648665
ir_ref vars; /* list of VARs (used by register allocator) */
649666
};
650667
ir_snapshot_create_t snapshot_create;
651-
int32_t stack_frame_alignment;
652668
int32_t stack_frame_size; /* spill stack frame size (used by register allocator and code generator) */
653669
int32_t call_stack_size; /* stack for parameter passing (used by register allocator and code generator) */
654670
uint64_t used_preserved_regs;
@@ -698,6 +714,7 @@ ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto);
698714
ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto);
699715
ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str);
700716
ir_ref ir_const_str(ir_ctx *ctx, ir_ref str);
717+
ir_ref ir_const_label(ir_ctx *ctx, ir_ref str);
701718

702719
ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t c);
703720

@@ -893,6 +910,7 @@ struct _ir_loader {
893910
void*(*resolve_sym_name) (ir_loader *loader, const char *name, uint32_t flags);
894911
bool (*has_sym) (ir_loader *loader, const char *name);
895912
bool (*add_sym) (ir_loader *loader, const char *name, void *addr);
913+
bool (*add_label) (ir_loader *loader, const char *name, void *addr);
896914
};
897915

898916
void ir_loader_init(void);

0 commit comments

Comments
 (0)