Skip to content

Commit ef202cc

Browse files
committed
Update IR
IR commit: 503018483d8333a3cfb25ab89a1eadefbee665bc
1 parent 32c919b commit ef202cc

File tree

14 files changed

+624
-298
lines changed

14 files changed

+624
-298
lines changed

ext/opcache/jit/ir/LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
MIT License
22

33
Copyright (c) 2022 Zend by Perforce
4+
Copyright (c) 2025 Dmitry Stogov
45

56
Permission is hereby granted, free of charge, to any person obtaining a copy
67
of this software and associated documentation files (the "Software"), to deal

ext/opcache/jit/ir/ir.c

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
227227
#define ir_op_flag_d0 ir_op_flag_d
228228
#define ir_op_flag_d1 (ir_op_flag_d | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
229229
#define ir_op_flag_d1X1 (ir_op_flag_d | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
230+
#define ir_op_flag_d1X2 (ir_op_flag_d | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
230231
#define ir_op_flag_d2 (ir_op_flag_d | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
231232
#define ir_op_flag_d2C (ir_op_flag_d | IR_OP_FLAG_COMMUTATIVE | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
232233
#define ir_op_flag_d3 (ir_op_flag_d | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
@@ -270,6 +271,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
270271
#define ir_op_flag_s3 (ir_op_flag_s | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
271272
#define ir_op_flag_x1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
272273
#define ir_op_flag_x2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
274+
#define ir_op_flag_x2X1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
273275
#define ir_op_flag_x3 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
274276
#define ir_op_flag_xN (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | IR_OP_FLAG_VAR_INPUTS)
275277
#define ir_op_flag_a1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
@@ -392,6 +394,8 @@ void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limi
392394
ctx->insns_limit = insns_limit;
393395
ctx->consts_count = -(IR_TRUE - 1);
394396
ctx->consts_limit = consts_limit;
397+
ctx->const_hash = ctx->_const_hash;
398+
ctx->const_hash_mask = IR_CONST_HASH_SIZE - 1;
395399
ctx->fold_cse_limit = IR_UNUSED + 1;
396400
ctx->flags = flags;
397401

@@ -414,6 +418,9 @@ void ir_free(ir_ctx *ctx)
414418
{
415419
ir_insn *buf = ctx->ir_base - ctx->consts_limit;
416420
ir_mem_free(buf);
421+
if (ctx->value_params) {
422+
ir_mem_free(ctx->value_params);
423+
}
417424
if (ctx->strtab.data) {
418425
ir_strtab_free(&ctx->strtab);
419426
}
@@ -468,6 +475,10 @@ void ir_free(ir_ctx *ctx)
468475
ir_list_free((ir_list*)ctx->osr_entry_loads);
469476
ir_mem_free(ctx->osr_entry_loads);
470477
}
478+
479+
if (ctx->const_hash_mask != IR_CONST_HASH_SIZE - 1) {
480+
ir_mem_free(ctx->const_hash);
481+
}
471482
}
472483

473484
ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t addr)
@@ -479,72 +490,64 @@ ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t addr)
479490
insn->val.u64 = addr;
480491
/* don't insert into constants chain */
481492
insn->prev_const = IR_UNUSED;
482-
#if 0
483-
insn->prev_const = ctx->prev_const_chain[IR_ADDR];
484-
ctx->prev_const_chain[IR_ADDR] = ref;
485-
#endif
486-
#if 0
487-
ir_insn *prev_insn, *next_insn;
488-
ir_ref next;
489-
490-
prev_insn = NULL;
491-
next = ctx->prev_const_chain[IR_ADDR];
492-
while (next) {
493-
next_insn = &ctx->ir_base[next];
494-
if (UNEXPECTED(next_insn->val.u64 >= addr)) {
495-
break;
496-
}
497-
prev_insn = next_insn;
498-
next = next_insn->prev_const;
499-
}
500-
501-
if (prev_insn) {
502-
insn->prev_const = prev_insn->prev_const;
503-
prev_insn->prev_const = ref;
504-
} else {
505-
insn->prev_const = ctx->prev_const_chain[IR_ADDR];
506-
ctx->prev_const_chain[IR_ADDR] = ref;
507-
}
508-
#endif
509493

510494
return ref;
511495
}
512496

497+
IR_ALWAYS_INLINE uintptr_t ir_const_hash(ir_val val, uint32_t optx)
498+
{
499+
return (val.u64 ^ (val.u64 >> 32) ^ optx);
500+
}
501+
502+
static IR_NEVER_INLINE void ir_const_hash_rehash(ir_ctx *ctx)
503+
{
504+
ir_insn *insn;
505+
ir_ref ref;
506+
uintptr_t hash;
507+
508+
if (ctx->const_hash_mask != IR_CONST_HASH_SIZE - 1) {
509+
ir_mem_free(ctx->const_hash);
510+
}
511+
ctx->const_hash_mask = (ctx->const_hash_mask + 1) * 2 - 1;
512+
ctx->const_hash = ir_mem_calloc(ctx->const_hash_mask + 1, sizeof(ir_ref));
513+
for (ref = IR_TRUE - 1; ref > -ctx->consts_count; ref--) {
514+
insn = &ctx->ir_base[ref];
515+
hash = ir_const_hash(insn->val, insn->optx) & ctx->const_hash_mask;
516+
insn->prev_const = ctx->const_hash[hash];
517+
ctx->const_hash[hash] = ref;
518+
}
519+
}
520+
513521
ir_ref ir_const_ex(ir_ctx *ctx, ir_val val, uint8_t type, uint32_t optx)
514522
{
515-
ir_insn *insn, *prev_insn;
523+
ir_insn *insn;
516524
ir_ref ref, prev;
525+
uintptr_t hash;
517526

518527
if (type == IR_BOOL) {
519528
return val.u64 ? IR_TRUE : IR_FALSE;
520529
} else if (type == IR_ADDR && val.u64 == 0) {
521530
return IR_NULL;
522531
}
523-
prev_insn = NULL;
524-
ref = ctx->prev_const_chain[type];
532+
533+
hash = ir_const_hash(val, optx) & ctx->const_hash_mask;
534+
ref = ctx->const_hash[hash];
525535
while (ref) {
526536
insn = &ctx->ir_base[ref];
527-
if (UNEXPECTED(insn->val.u64 >= val.u64)) {
528-
if (insn->val.u64 == val.u64) {
529-
if (insn->optx == optx) {
530-
return ref;
531-
}
532-
} else {
533-
break;
534-
}
537+
if (insn->val.u64 == val.u64 && insn->optx == optx) {
538+
return ref;
535539
}
536-
prev_insn = insn;
537540
ref = insn->prev_const;
538541
}
539542

540-
if (prev_insn) {
541-
prev = prev_insn->prev_const;
542-
prev_insn->prev_const = -ctx->consts_count;
543-
} else {
544-
prev = ctx->prev_const_chain[type];
545-
ctx->prev_const_chain[type] = -ctx->consts_count;
543+
if ((uintptr_t)ctx->consts_count > ctx->const_hash_mask) {
544+
ir_const_hash_rehash(ctx);
545+
hash = ir_const_hash(val, optx) & ctx->const_hash_mask;
546546
}
547547

548+
prev = ctx->const_hash[hash];
549+
ctx->const_hash[hash] = -ctx->consts_count;
550+
548551
ref = ir_next_const(ctx);
549552
insn = &ctx->ir_base[ref];
550553
insn->prev_const = prev;
@@ -2092,10 +2095,10 @@ IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_typ
20922095
if (insn->type == type) {
20932096
return ref; /* load forwarding (L2L) */
20942097
} else if (ir_type_size[insn->type] == ir_type_size[type]) {
2095-
return ir_fold1(ctx, IR_OPT(IR_BITCAST, type), ref); /* load forwarding with bitcast (L2L) */
2098+
return ref; /* load forwarding with bitcast (L2L) */
20962099
} else if (ir_type_size[insn->type] > ir_type_size[type]
20972100
&& IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(insn->type)) {
2098-
return ir_fold1(ctx, IR_OPT(IR_TRUNC, type), ref); /* partial load forwarding (L2L) */
2101+
return ref; /* partial load forwarding (L2L) */
20992102
}
21002103
}
21012104
} else if (insn->op == IR_VSTORE) {
@@ -2105,10 +2108,10 @@ IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_typ
21052108
if (type2 == type) {
21062109
return insn->op3; /* store forwarding (S2L) */
21072110
} else if (ir_type_size[type2] == ir_type_size[type]) {
2108-
return ir_fold1(ctx, IR_OPT(IR_BITCAST, type), insn->op3); /* store forwarding with bitcast (S2L) */
2111+
return insn->op3; /* store forwarding with bitcast (S2L) */
21092112
} else if (ir_type_size[type2] > ir_type_size[type]
21102113
&& IR_IS_TYPE_INT(type) && IR_IS_TYPE_INT(type2)) {
2111-
return ir_fold1(ctx, IR_OPT(IR_TRUNC, type), insn->op3); /* partial store forwarding (S2L) */
2114+
return insn->op3; /* partial store forwarding (S2L) */
21122115
} else {
21132116
break;
21142117
}
@@ -3214,6 +3217,13 @@ ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
32143217
return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list);
32153218
}
32163219

3220+
ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size)
3221+
{
3222+
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);
3225+
}
3226+
32173227
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx)
32183228
{
32193229
IR_ASSERT(ctx->control);

ext/opcache/jit/ir/ir.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ typedef enum _ir_type {
310310
_(PHI, pN, reg, def, def) /* SSA Phi function */ \
311311
_(COPY, d1X1, def, opt, ___) /* COPY (last foldable op) */ \
312312
_(PI, p2, reg, def, ___) /* e-SSA Pi constraint ??? */ \
313+
_(ARGVAL, d1X2, def, num, num) /* pass struct arg by value */ \
314+
/* (op2 - size, op3 - align) */ \
313315
/* (USE, RENAME) */ \
314316
\
315317
/* data ops */ \
@@ -343,7 +345,8 @@ typedef enum _ir_type {
343345
_(VA_START, x2, src, def, ___) /* va_start(va_list) */ \
344346
_(VA_END, x2, src, def, ___) /* va_end(va_list) */ \
345347
_(VA_COPY, x3, src, def, def) /* va_copy(dst, stc) */ \
346-
_(VA_ARG, x2, src, def, ___) /* va_arg(va_list) */ \
348+
_(VA_ARG, x2X1, src, def, opt) /* va_arg(va_list) */ \
349+
/* op3 - (size<<3)+log2(align) */ \
347350
\
348351
/* guards */ \
349352
_(GUARD, c3, src, def, def) /* IF without second successor */ \
@@ -583,19 +586,30 @@ typedef struct _ir_code_buffer {
583586
void *pos;
584587
} ir_code_buffer;
585588

589+
typedef struct {
590+
int size;
591+
int align;
592+
int offset;
593+
} ir_value_param;
594+
595+
#define IR_CONST_HASH_SIZE 64
596+
586597
struct _ir_ctx {
587598
ir_insn *ir_base; /* two directional array - instructions grow down, constants grow up */
588599
ir_ref insns_count; /* number of instructions stored in instructions buffer */
589600
ir_ref insns_limit; /* size of allocated instructions buffer (it's extended when overflow) */
590601
ir_ref consts_count; /* number of constants stored in constants buffer */
591602
ir_ref consts_limit; /* size of allocated constants buffer (it's extended when overflow) */
603+
uintptr_t const_hash_mask;
604+
ir_ref *const_hash;
592605
uint32_t flags; /* IR context flags (see IR_* defines above) */
593606
uint32_t flags2; /* IR context private flags (see IR_* defines in ir_private.h) */
594607
ir_type ret_type; /* Function return type */
595608
uint32_t mflags; /* CPU specific flags (see IR_X86_... macros below) */
596609
int32_t status; /* non-zero error code (see IR_ERROR_... macros), app may use negative codes */
597610
ir_ref fold_cse_limit; /* CSE finds identical insns backward from "insn_count" to "fold_cse_limit" */
598611
ir_insn fold_insn; /* temporary storage for folding engine */
612+
ir_value_param *value_params; /* information about "by-val" struct parameters */
599613
ir_hashtab *binding;
600614
ir_use_list *use_lists; /* def->use lists for each instruction */
601615
ir_ref *use_edges; /* the actual uses: use = ctx->use_edges[ctx->use_lists[def].refs + n] */
@@ -655,7 +669,7 @@ struct _ir_ctx {
655669
ir_loader *loader;
656670
ir_strtab strtab;
657671
ir_ref prev_insn_chain[IR_LAST_FOLDABLE_OP + 1];
658-
ir_ref prev_const_chain[IR_LAST_TYPE];
672+
ir_ref _const_hash[IR_CONST_HASH_SIZE];
659673
};
660674

661675
/* Basic IR Construction API (implementation in ir.c) */
@@ -896,6 +910,7 @@ int ir_load_llvm_asm(ir_loader *loader, const char *filename);
896910
#define IR_SAVE_SAFE_NAMES (1<<5) /* add '@' prefix to symbol names */
897911

898912
void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f);
913+
void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f);
899914
void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f);
900915

901916
/* IR debug dump API (implementation in ir_dump.c) */

0 commit comments

Comments
 (0)