From 71194ea76793d67ac15d6d38e0cb9cb7f922e935 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 23 Apr 2024 23:14:54 +0300 Subject: [PATCH] Update IR IR commit: 65586bd4cf9cd2d3b41492f52823c5083cea77e4 --- ext/opcache/jit/ir/ir.c | 92 +++++++----- ext/opcache/jit/ir/ir.h | 12 +- ext/opcache/jit/ir/ir_aarch64.dasc | 6 +- ext/opcache/jit/ir/ir_check.c | 12 +- ext/opcache/jit/ir/ir_fold.h | 221 ++++++++++++++++++++++++++++- ext/opcache/jit/ir/ir_private.h | 2 + ext/opcache/jit/ir/ir_ra.c | 33 ++++- ext/opcache/jit/ir/ir_x86.dasc | 2 +- 8 files changed, 320 insertions(+), 60 deletions(-) diff --git a/ext/opcache/jit/ir/ir.c b/ext/opcache/jit/ir/ir.c index 2c2f7c3d04d..211d2b8c866 100644 --- a/ext/opcache/jit/ir/ir.c +++ b/ext/opcache/jit/ir/ir.c @@ -75,7 +75,7 @@ const char *ir_op_name[IR_LAST_OP] = { #endif }; -static void ir_print_escaped_str(const char *s, size_t len, FILE *f) +void ir_print_escaped_str(const char *s, size_t len, FILE *f) { char ch; @@ -95,10 +95,14 @@ static void ir_print_escaped_str(const char *s, size_t len, FILE *f) case '\v': fputs("\\v", f); break; case '\?': fputs("\\?", f); break; default: +#ifdef __aarch64__ if (ch < 32) { +#else + if (ch >= 0 && ch < 32) { +#endif fprintf(f, "\\%c%c%c", - '0' + ((ch >> 3) % 8), '0' + ((ch >> 6) % 8), + '0' + ((ch >> 3) % 8), '0' + (ch % 8)); break; } else { @@ -1784,48 +1788,64 @@ static ir_alias ir_check_aliasing(ir_ctx *ctx, ir_ref addr1, ir_ref addr2) static ir_alias ir_check_partial_aliasing(const ir_ctx *ctx, ir_ref addr1, ir_ref addr2, ir_type type1, ir_type type2) { ir_insn *insn1, *insn2; + ir_ref base1, base2, off1, off2; /* this must be already check */ IR_ASSERT(addr1 != addr2); insn1 = &ctx->ir_base[addr1]; insn2 = &ctx->ir_base[addr2]; - if (insn1->op == IR_ADD && IR_IS_CONST_REF(insn1->op2)) { - if (insn1->op1 == addr2) { - uintptr_t offset1 = ctx->ir_base[insn1->op2].val.addr; - uintptr_t size2 = ir_type_size[type2]; + if (insn1->op != IR_ADD) { + base1 = addr1; + off1 = IR_UNUSED; + } else if (ctx->ir_base[insn1->op2].op == IR_SYM) { + base1 = insn1->op2; + off1 = insn1->op1; + } else { + base1 = insn1->op1; + off1 = insn1->op2; + } + if (insn2->op != IR_ADD) { + base2 = addr2; + off2 = IR_UNUSED; + } else if (ctx->ir_base[insn2->op2].op == IR_SYM) { + base2 = insn2->op2; + off2 = insn2->op1; + } else { + base2 = insn2->op1; + off2 = insn2->op2; + } + if (base1 == base2) { + uintptr_t offset1, offset2; - return (offset1 < size2) ? IR_MUST_ALIAS : IR_NO_ALIAS; - } else if (insn2->op == IR_ADD && IR_IS_CONST_REF(insn1->op2) && insn1->op1 == insn2->op1) { - if (insn1->op2 == insn2->op2) { - return IR_MUST_ALIAS; - } else if (IR_IS_CONST_REF(insn1->op2) && IR_IS_CONST_REF(insn2->op2)) { - uintptr_t offset1 = ctx->ir_base[insn1->op2].val.addr; - uintptr_t offset2 = ctx->ir_base[insn2->op2].val.addr; - - if (offset1 == offset2) { - return IR_MUST_ALIAS; - } else if (type1 == type2) { - return IR_NO_ALIAS; - } else { - /* check for partail intersection */ - uintptr_t size1 = ir_type_size[type1]; - uintptr_t size2 = ir_type_size[type2]; - - if (offset1 > offset2) { - return offset1 < offset2 + size2 ? IR_MUST_ALIAS : IR_NO_ALIAS; - } else { - return offset2 < offset1 + size1 ? IR_MUST_ALIAS : IR_NO_ALIAS; - } - } - } + if (!off1) { + offset1 = 0; + } else if (IR_IS_CONST_REF(off1) && !IR_IS_SYM_CONST(ctx->ir_base[off1].op)) { + offset1 = ctx->ir_base[off1].val.addr; + } else { + return IR_MAY_ALIAS; } - } else if (insn2->op == IR_ADD && IR_IS_CONST_REF(insn2->op2)) { - if (insn2->op1 == addr1) { - uintptr_t offset2 = ctx->ir_base[insn2->op2].val.addr; - uintptr_t size1 = ir_type_size[type1]; - - return (offset2 < size1) ? IR_MUST_ALIAS : IR_NO_ALIAS; + if (!off2) { + offset2 = 0; + } else if (IR_IS_CONST_REF(off2) && !IR_IS_SYM_CONST(ctx->ir_base[off2].op)) { + offset2 = ctx->ir_base[off2].val.addr; + } else { + return IR_MAY_ALIAS; + } + if (offset1 == offset2) { + return IR_MUST_ALIAS; + } else if (offset1 < offset2) { + return offset1 + ir_type_size[type1] <= offset2 ? IR_NO_ALIAS : IR_MUST_ALIAS; + } else { + return offset2 + ir_type_size[type2] <= offset1 ? IR_NO_ALIAS : IR_MUST_ALIAS; + } + } else { + insn1 = &ctx->ir_base[base1]; + insn2 = &ctx->ir_base[base2]; + if ((insn1->op == IR_ALLOCA && (insn2->op == IR_ALLOCA || insn2->op == IR_SYM || insn2->op == IR_PARAM)) + || (insn1->op == IR_SYM && (insn2->op == IR_ALLOCA || insn2->op == IR_SYM)) + || (insn1->op == IR_PARAM && insn2->op == IR_ALLOCA)) { + return IR_NO_ALIAS; } } return IR_MAY_ALIAS; diff --git a/ext/opcache/jit/ir/ir.h b/ext/opcache/jit/ir/ir.h index 728714d5452..6c8cb7db944 100644 --- a/ext/opcache/jit/ir/ir.h +++ b/ext/opcache/jit/ir/ir.h @@ -513,6 +513,9 @@ void ir_strtab_free(ir_strtab *strtab); #define IR_EXTERN (1<<5) #define IR_CONST (1<<6) +#define IR_INITIALIZED (1<<7) /* sym data flag: constant or an initialized variable */ +#define IR_CONST_STRING (1<<8) /* sym data flag: constant string */ + #define IR_SKIP_PROLOGUE (1<<8) /* Don't generate function prologue. */ #define IR_USE_FRAME_POINTER (1<<9) #define IR_PREALLOCATED_STACK (1<<10) @@ -825,11 +828,12 @@ struct _ir_loader { uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types); bool (*forward_func_dcl) (ir_loader *loader, const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types); - bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size, bool has_data); + bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size); bool (*sym_data) (ir_loader *loader, ir_type type, uint32_t count, const void *data); + bool (*sym_data_str) (ir_loader *loader, const char *str, size_t len); bool (*sym_data_pad) (ir_loader *loader, size_t offset); bool (*sym_data_ref) (ir_loader *loader, ir_op op, const char *ref, uintptr_t offset); - bool (*sym_data_end) (ir_loader *loader); + bool (*sym_data_end) (ir_loader *loader, uint32_t flags); bool (*func_init) (ir_loader *loader, ir_ctx *ctx, const char *name); bool (*func_process) (ir_loader *loader, ir_ctx *ctx, const char *name); void*(*resolve_sym_name) (ir_loader *loader, const char *name, bool add_thunk); @@ -867,12 +871,12 @@ void ir_dump_codegen(const ir_ctx *ctx, FILE *f); /* IR to C conversion (implementation in ir_emit_c.c) */ int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f); void ir_emit_c_func_decl(const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f); -void ir_emit_c_sym_decl(const char *name, uint32_t flags, bool has_data, FILE *f); +void ir_emit_c_sym_decl(const char *name, uint32_t flags, FILE *f); /* IR to LLVM conversion (implementation in ir_emit_llvm.c) */ int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f); void ir_emit_llvm_func_decl(const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f); -void ir_emit_llvm_sym_decl(const char *name, uint32_t flags, bool has_data, FILE *f); +void ir_emit_llvm_sym_decl(const char *name, uint32_t flags, FILE *f); /* IR verification API (implementation in ir_check.c) */ bool ir_check(const ir_ctx *ctx); diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc index 33f5b88258c..4184d003444 100644 --- a/ext/opcache/jit/ir/ir_aarch64.dasc +++ b/ext/opcache/jit/ir/ir_aarch64.dasc @@ -1057,7 +1057,7 @@ binop_fp: return insn->op; case IR_VA_START: ctx->flags2 |= IR_HAS_VA_START; - if (ctx->ir_base[insn->op2].op == IR_ALLOCA) { + if ((ctx->ir_base[insn->op2].op == IR_ALLOCA) || (ctx->ir_base[insn->op2].op == IR_VADDR)) { ir_use_list *use_list = &ctx->use_lists[insn->op2]; ir_ref *p, n = use_list->count; for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { @@ -1092,7 +1092,7 @@ binop_fp: for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { if (ctx->ir_base[*p].op != IR_VA_END) { - return IR_VADDR; + return IR_STATIC_ALLOCA; } } } @@ -3802,7 +3802,7 @@ static ir_mem ir_fuse_addr(ir_ctx *ctx, ir_ref root, ir_ref ref) return IR_MEM_BO(reg, ctx->ir_base[addr_insn->op2].val.i32); } } else { - IR_ASSERT(addr_insn->op == IR_ALLOCA); + IR_ASSERT(addr_insn->op == IR_ALLOCA || addr_insn->op == IR_VADDR); reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; offset = IR_SPILL_POS_TO_OFFSET(ctx->ir_base[ref].op3); return IR_MEM_BO(reg, offset); diff --git a/ext/opcache/jit/ir/ir_check.c b/ext/opcache/jit/ir/ir_check.c index b54e2eb26b0..f41957a2647 100644 --- a/ext/opcache/jit/ir/ir_check.c +++ b/ext/opcache/jit/ir/ir_check.c @@ -178,14 +178,10 @@ bool ir_check(const ir_ctx *ctx) /* boolean not */ break; } - if (sizeof(void*) == 8) { - if (insn->type == IR_ADDR && (use_insn->type == IR_U64 || use_insn->type == IR_I64)) { - break; - } - } else { - if (insn->type == IR_ADDR && (use_insn->type == IR_U32 || use_insn->type == IR_I32)) { - break; - } + if (insn->type == IR_ADDR && (use_insn->type == IR_UINTPTR_T || use_insn->type == IR_INTPTR_T)) { + break; + } else if (use_insn->type == IR_ADDR && (insn->type == IR_UINTPTR_T || insn->type == IR_INTPTR_T)) { + break; } fprintf(stderr, "ir_base[%d].ops[%d] (%d) type is incompatible with result type (%d != %d)\n", i, j, use, use_insn->type, insn->type); diff --git a/ext/opcache/jit/ir/ir_fold.h b/ext/opcache/jit/ir/ir_fold.h index 2e78990c7ce..cb65ca505ac 100644 --- a/ext/opcache/jit/ir/ir_fold.h +++ b/ext/opcache/jit/ir/ir_fold.h @@ -2501,10 +2501,230 @@ IR_FOLD(ADD(ADD, C_I64)) IR_FOLD_NEXT; } +IR_FOLD(ADD(SUB, C_U8)) +IR_FOLD(ADD(SUB, C_U16)) +IR_FOLD(ADD(SUB, C_U32)) +IR_FOLD(ADD(SUB, C_U64)) +IR_FOLD(ADD(SUB, C_ADDR)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { + /* (x - c1) + c2 => x + (c2 - c1) */ + val.u64 = op2_insn->val.u64 - ctx->ir_base[op1_insn->op2].val.u64; + op1 = op1_insn->op1; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) { + /* (c1 - x) + c2 => (c1 + c2) - x */ + val.u64 = ctx->ir_base[op1_insn->op1].val.u64 + op2_insn->val.u64; + opt++; /* ADD -> SUB */ + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op1_insn->op2; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(ADD(SUB, C_I8)) +IR_FOLD(ADD(SUB, C_I16)) +IR_FOLD(ADD(SUB, C_I32)) +IR_FOLD(ADD(SUB, C_I64)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { + /* (x - c1) + c2 => x + (c2 - c1) */ + val.i64 = op2_insn->val.i64 - ctx->ir_base[op1_insn->op2].val.i64; + if (val.i64 < 0 && val.i64 - 1 < 0) { + val.i64 = -val.i64; + opt++; /* ADD -> SUB */ + } + op1 = op1_insn->op1; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) { + /* (c1 - x) + c2 => (c1 + c2) - x */ + val.i64 = ctx->ir_base[op1_insn->op1].val.i64 + op2_insn->val.i64; + opt++; /* ADD -> SUB */ + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op1_insn->op2; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(ADD, C_U8)) +IR_FOLD(SUB(ADD, C_U16)) +IR_FOLD(SUB(ADD, C_U32)) +IR_FOLD(SUB(ADD, C_U64)) +IR_FOLD(SUB(ADD, C_ADDR)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { + /* (x + c1) - c2 => x + (c1 - c2) */ + val.u64 = ctx->ir_base[op1_insn->op2].val.u64 - op2_insn->val.u64; + opt--; /* SUB -> ADD */ + op1 = op1_insn->op1; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(ADD, C_I8)) +IR_FOLD(SUB(ADD, C_I16)) +IR_FOLD(SUB(ADD, C_I32)) +IR_FOLD(SUB(ADD, C_I64)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { + /* (x + c1) - c2 => x + (c1 - c2) */ + val.i64 = ctx->ir_base[op1_insn->op2].val.i64 - op2_insn->val.i64; + if (val.i64 < 0 && val.i64 - 1 < 0) { + val.i64 = -val.i64; + } else { + opt--; /* SUB -> ADD */ + } + op1 = op1_insn->op1; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(C_U8, ADD)) +IR_FOLD(SUB(C_U16, ADD)) +IR_FOLD(SUB(C_U32, ADD)) +IR_FOLD(SUB(C_U64, ADD)) +IR_FOLD(SUB(C_ADDR, ADD)) +{ + if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) { + /* c1 - (x + c2) => (c1 - c2) - x */ + val.u64 = op1_insn->val.u64 - ctx->ir_base[op2_insn->op2].val.u64; + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op2_insn->op1; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(C_I8, ADD)) +IR_FOLD(SUB(C_I16, ADD)) +IR_FOLD(SUB(C_I32, ADD)) +IR_FOLD(SUB(C_I64, ADD)) +{ + if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) { + /* c1 - (x + c2) => (c1 - c2) - x */ + val.i64 = op1_insn->val.i64 - ctx->ir_base[op2_insn->op2].val.i64; + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op2_insn->op1; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(SUB, C_U8)) +IR_FOLD(SUB(SUB, C_U16)) +IR_FOLD(SUB(SUB, C_U32)) +IR_FOLD(SUB(SUB, C_U64)) +IR_FOLD(SUB(SUB, C_ADDR)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { + /* (x - c1) - c2 => x - (c1 + c2) */ + val.u64 = ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64; + if (val.i64 < 0 && val.i64 - 1 < 0) { + val.i64 = -val.i64; + opt--; /* SUB -> ADD */ + } + op1 = op1_insn->op1; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) { + /* (c1 - x) - c2 => (c1 - c2) - x */ + val.u64 = ctx->ir_base[op1_insn->op1].val.u64 - op2_insn->val.u64; + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op1_insn->op2; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(SUB, C_I8)) +IR_FOLD(SUB(SUB, C_I16)) +IR_FOLD(SUB(SUB, C_I32)) +IR_FOLD(SUB(SUB, C_I64)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { + /* (x - c1) - c2 => x - (c1 + c2) */ + val.i64 = ctx->ir_base[op1_insn->op2].val.i64 + op2_insn->val.i64; + if (val.i64 < 0 && val.i64 - 1 < 0) { + val.i64 = -val.i64; + opt--; /* SUB -> ADD */ + } + op1 = op1_insn->op1; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) { + /* (c1 - x) - c2 => (c1 - c2) - x */ + val.i64 = ctx->ir_base[op1_insn->op1].val.i64 - op2_insn->val.i64; + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op1_insn->op2; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(C_U8, SUB)) +IR_FOLD(SUB(C_U16, SUB)) +IR_FOLD(SUB(C_U32, SUB)) +IR_FOLD(SUB(C_U64, SUB)) +IR_FOLD(SUB(C_ADDR, SUB)) +{ + if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) { + /* c1 - (x - c2) => (c1 + c2) - x */ + val.u64 = op1_insn->val.u64 + ctx->ir_base[op2_insn->op2].val.u64; + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op2_insn->op1; + IR_FOLD_RESTART; + } else if (IR_IS_CONST_REF(op2_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op1].op)) { + /* c1 - (c2 - x) => x + (c1 - c2) */ + val.u64 = op1_insn->val.u64 - ctx->ir_base[op2_insn->op1].val.u64; + if (val.i64 < 0 && val.i64 - 1 < 0) { + val.i64 = -val.i64; + opt++; /* ADD -> SUB */ + } + op1 = op2_insn->op2; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + +IR_FOLD(SUB(C_I8, SUB)) +IR_FOLD(SUB(C_I16, SUB)) +IR_FOLD(SUB(C_I32, SUB)) +IR_FOLD(SUB(C_I64, SUB)) +{ + if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) { + /* c1 - (x - c2) => (c1 + c2) - x */ + val.i64 = op1_insn->val.i64 + ctx->ir_base[op2_insn->op2].val.i64; + op1 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + op2 = op2_insn->op1; + IR_FOLD_RESTART; + } else if (IR_IS_CONST_REF(op2_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op1].op)) { + /* c1 - (c2 - x) => x + (c1 - c2) */ + val.i64 = op1_insn->val.i64 - ctx->ir_base[op2_insn->op1].val.i64; + if (val.i64 < 0 && val.i64 - 1 < 0) { + val.i64 = -val.i64; + opt++; /* ADD -> SUB */ + } + op1 = op2_insn->op2; + op2 = ir_const(ctx, val, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + IR_FOLD(MUL(MUL, C_U8)) IR_FOLD(MUL(MUL, C_U16)) IR_FOLD(MUL(MUL, C_U32)) IR_FOLD(MUL(MUL, C_U64)) +IR_FOLD(MUL(MUL, C_ADDR)) { if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { /* (x * c1) * c2 => x * (c1 * c2) */ @@ -2520,7 +2740,6 @@ IR_FOLD(MUL(MUL, C_I8)) IR_FOLD(MUL(MUL, C_I16)) IR_FOLD(MUL(MUL, C_I32)) IR_FOLD(MUL(MUL, C_I64)) -IR_FOLD(MUL(MUL, C_ADDR)) { if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) { /* (x * c1) * c2 => x * (c1 * c2) */ diff --git a/ext/opcache/jit/ir/ir_private.h b/ext/opcache/jit/ir/ir_private.h index 42624574585..ed3ba9777e8 100644 --- a/ext/opcache/jit/ir/ir_private.h +++ b/ext/opcache/jit/ir/ir_private.h @@ -855,6 +855,8 @@ extern const uint8_t ir_type_size[IR_LAST_TYPE]; extern const uint32_t ir_op_flags[IR_LAST_OP]; extern const char *ir_op_name[IR_LAST_OP]; +void ir_print_escaped_str(const char *s, size_t len, FILE *f); + #define IR_IS_CONST_OP(op) ((op) > IR_NOP && (op) <= IR_C_FLOAT) #define IR_IS_FOLDABLE_OP(op) ((op) <= IR_LAST_FOLDABLE_OP) #define IR_IS_SYM_CONST(op) ((op) == IR_STR || (op) == IR_SYM || (op) == IR_FUNC) diff --git a/ext/opcache/jit/ir/ir_ra.c b/ext/opcache/jit/ir/ir_ra.c index 07789563e6c..789e9c5612d 100644 --- a/ext/opcache/jit/ir/ir_ra.c +++ b/ext/opcache/jit/ir/ir_ra.c @@ -722,8 +722,10 @@ int ir_compute_live_ranges(ir_ctx *ctx) || (ctx->rules[ref] & IR_RULE_MASK) == IR_ALLOCA) && ctx->use_lists[ref].count > 0) { insn = &ctx->ir_base[ref]; - insn->op3 = ctx->vars; - ctx->vars = ref; + if (insn->op != IR_VADDR) { + insn->op3 = ctx->vars; + ctx->vars = ref; + } } continue; } @@ -1338,8 +1340,10 @@ int ir_compute_live_ranges(ir_ctx *ctx) || (ctx->rules[ref] & IR_RULE_MASK) == IR_ALLOCA) && ctx->use_lists[ref].count > 0) { insn = &ctx->ir_base[ref]; - insn->op3 = ctx->vars; - ctx->vars = ref; + if (insn->op != IR_VADDR) { + insn->op3 = ctx->vars; + ctx->vars = ref; + } } continue; } @@ -3507,13 +3511,27 @@ static int ir_linear_scan(ir_ctx *ctx) data.handled = NULL; while (vars) { - ir_insn *insn = &ctx->ir_base[vars]; + ir_ref var = vars; + ir_insn *insn = &ctx->ir_base[var]; IR_ASSERT(insn->op == IR_VAR || insn->op == IR_ALLOCA); vars = insn->op3; /* list next */ if (insn->op == IR_VAR) { - insn->op3 = ir_allocate_spill_slot(ctx, insn->type, &data); + ir_ref slot = ir_allocate_spill_slot(ctx, insn->type, &data);; + ir_use_list *use_list; + ir_ref n, *p; + + insn->op3 = slot; + use_list = &ctx->use_lists[var]; + n = use_list->count; + p = &ctx->use_edges[use_list->refs]; + for (; n > 0; p++, n--) { + insn = &ctx->ir_base[*p]; + if (insn->op == IR_VADDR) { + insn->op3 = slot; + } + } } else { ir_insn *val = &ctx->ir_base[insn->op2]; @@ -4060,7 +4078,8 @@ static void assign_regs(ir_ctx *ctx) if (IR_IS_CONST_REF(ops[ival->tmp_op_num])) { /* constant rematerialization */ reg |= IR_REG_SPILL_LOAD; - } else if (ctx->ir_base[ops[ival->tmp_op_num]].op == IR_ALLOCA) { + } else if (ctx->ir_base[ops[ival->tmp_op_num]].op == IR_ALLOCA + || ctx->ir_base[ops[ival->tmp_op_num]].op == IR_VADDR) { /* local address rematerialization */ reg |= IR_REG_SPILL_LOAD; } diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc index e5822d8323b..66ca2ecad04 100644 --- a/ext/opcache/jit/ir/ir_x86.dasc +++ b/ext/opcache/jit/ir/ir_x86.dasc @@ -2810,7 +2810,7 @@ store_int: for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { if (ctx->ir_base[*p].op != IR_VA_END) { - return IR_VADDR; + return IR_STATIC_ALLOCA; } } }