1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Update IR

IR commit: 0108cdf808d1e7dd6b702738949e095151f49040
This commit is contained in:
Dmitry Stogov
2024-01-25 22:50:30 +03:00
parent b8ff8c04f8
commit 136a972ccb
5 changed files with 2050 additions and 2018 deletions

View File

@@ -23,6 +23,9 @@
# if defined(__linux__) || defined(__sun)
# include <alloca.h>
# endif
# if defined(__APPLE__) && defined(__aarch64__)
# include <libkern/OSCacheControl.h>
# endif
#else
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
@@ -109,6 +112,8 @@ static void ir_print_escaped_str(const char *s, size_t len, FILE *f)
void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted)
{
char buf[128];
if (insn->op == IR_FUNC || insn->op == IR_SYM) {
fprintf(f, "%s", ir_get_str(ctx, insn->val.name));
return;
@@ -182,14 +187,28 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
if (isnan(insn->val.d)) {
fprintf(f, "nan");
} else {
fprintf(f, "%g", insn->val.d);
sprintf(buf, "%g", insn->val.d);
if (strtod(buf, NULL) != insn->val.d) {
sprintf(buf, "%.53e", insn->val.d);
if (strtod(buf, NULL) != insn->val.d) {
IR_ASSERT(0 && "can't format double");
}
}
fprintf(f, "%s", buf);
}
break;
case IR_FLOAT:
if (isnan(insn->val.f)) {
fprintf(f, "nan");
} else {
fprintf(f, "%g", insn->val.f);
sprintf(buf, "%g", insn->val.f);
if (strtod(buf, NULL) != insn->val.f) {
sprintf(buf, "%.24e", insn->val.f);
if (strtod(buf, NULL) != insn->val.f) {
IR_ASSERT(0 && "can't format float");
}
}
fprintf(f, "%s", buf);
}
break;
default:
@@ -1556,7 +1575,11 @@ int ir_mem_flush(void *ptr, size_t size)
#else
void *ir_mem_mmap(size_t size)
{
void *ret = mmap(NULL, size, PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
int prot_flags = PROT_EXEC;
#if defined(__NetBSD__)
prot_flags |= PROT_MPROTECT(PROT_READ|PROT_WRITE);
#endif
void *ret = mmap(NULL, size, prot_flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ret == MAP_FAILED) {
ret = NULL;
}
@@ -1596,6 +1619,9 @@ int ir_mem_flush(void *ptr, size_t size)
#if ((defined(__GNUC__) && ZEND_GCC_VERSION >= 4003) || __has_builtin(__builtin___clear_cache))
__builtin___clear_cache((char*)(ptr), (char*)(ptr) + size);
#endif
#if defined(__APPLE__) && defined(__aarch64__)
sys_icache_invalidate(ptr, size);
#endif
#ifdef HAVE_VALGRIND
VALGRIND_DISCARD_TRANSLATIONS(ptr, size);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,10 @@
# include <psapi.h>
#endif
#if defined(__linux__) || defined(__sun)
# include <alloca.h>
#endif
#define DASM_M_GROW(ctx, t, p, sz, need) \
do { \
size_t _sz = (sz), _need = (need); \
@@ -351,22 +355,21 @@ static void *ir_jmp_addr(ir_ctx *ctx, ir_insn *insn, ir_insn *addr_insn)
return addr;
}
static int8_t ir_get_fused_reg(ir_ctx *ctx, ir_ref root, ir_ref ref, uint8_t op_num)
static int8_t ir_get_fused_reg(ir_ctx *ctx, ir_ref root, ir_ref ref_and_op)
{
if (ctx->fused_regs) {
char key[10];
ir_ref val;
memcpy(key, &root, sizeof(ir_ref));
memcpy(key + 4, &ref, sizeof(ir_ref));
memcpy(key + 8, &op_num, sizeof(uint8_t));
memcpy(key + 4, &ref_and_op, sizeof(ir_ref));
val = ir_strtab_find(ctx->fused_regs, key, 9);
val = ir_strtab_find(ctx->fused_regs, key, 8);
if (val) {
return val;
}
}
return ctx->regs[ref][op_num];
return ((int8_t*)ctx->regs)[ref_and_op];
}
#if defined(__GNUC__)
@@ -393,6 +396,7 @@ static int ir_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, ui
/* Forward Declarations */
static void ir_emit_osr_entry_loads(ir_ctx *ctx, int b, ir_block *bb);
static int ir_parallel_copy(ir_ctx *ctx, ir_copy *copies, int count, ir_reg tmp_reg, ir_reg tmp_fp_reg);
static void ir_emit_dessa_moves(ir_ctx *ctx, int b, ir_block *bb);
typedef struct _ir_common_backend_data {
@@ -452,17 +456,200 @@ static IR_NEVER_INLINE void ir_emit_osr_entry_loads(ir_ctx *ctx, int b, ir_block
int32_t offset = -ir_binding_find(ctx, ref);
IR_ASSERT(offset > 0);
if (IR_IS_TYPE_INT(type)) {
ir_emit_load_mem_int(ctx, type, reg, ctx->spill_base, offset);
} else {
ir_emit_load_mem_fp(ctx, type, reg, ctx->spill_base, offset);
}
ir_emit_load_mem(ctx, type, reg, IR_MEM_BO(ctx->spill_base, offset));
} else {
IR_ASSERT(ctx->live_intervals[ctx->vregs[ref]]->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL);
}
}
}
/*
* Parallel copy sequentialization algorithm
*
* The implementation is based on algorithm 1 desriebed in
* "Revisiting Out-of-SSA Translation for Correctness, Code Quality and Efficiency",
* Benoit Boissinot, Alain Darte, Fabrice Rastello, Benoit Dupont de Dinechin, Christophe Guillon.
* 2009 International Symposium on Code Generation and Optimization, Seattle, WA, USA, 2009,
* pp. 114-125, doi: 10.1109/CGO.2009.19.
*/
static int ir_parallel_copy(ir_ctx *ctx, ir_copy *copies, int count, ir_reg tmp_reg, ir_reg tmp_fp_reg)
{
int i;
int8_t *pred, *loc, *types;
ir_reg to, from;
ir_type type;
ir_regset todo, ready, srcs;
ir_reg last_reg, last_fp_reg;
if (count == 1) {
to = copies[0].to;
from = copies[0].from;
IR_ASSERT(from != to);
type = copies[0].type;
if (IR_IS_TYPE_INT(type)) {
ir_emit_mov(ctx, type, to, from);
} else {
ir_emit_fp_mov(ctx, type, to, from);
}
return 1;
}
loc = alloca(IR_REG_NUM * 3 * sizeof(int8_t));
pred = loc + IR_REG_NUM;
types = pred + IR_REG_NUM;
todo = IR_REGSET_EMPTY;
srcs = IR_REGSET_EMPTY;
for (i = 0; i < count; i++) {
from = copies[i].from;
to = copies[i].to;
IR_ASSERT(from != to);
IR_REGSET_INCL(srcs, from);
loc[from] = from;
pred[to] = from;
types[from] = copies[i].type;
IR_ASSERT(!IR_REGSET_IN(todo, to));
IR_REGSET_INCL(todo, to);
}
ready = IR_REGSET_DIFFERENCE(todo, srcs);
if (ready == todo) {
for (i = 0; i < count; i++) {
from = copies[i].from;
to = copies[i].to;
IR_ASSERT(from != to);
type = copies[i].type;
if (IR_IS_TYPE_INT(type)) {
ir_emit_mov(ctx, type, to, from);
} else {
ir_emit_fp_mov(ctx, type, to, from);
}
}
return 1;
}
while (ready != IR_REGSET_EMPTY) {
ir_reg r;
to = ir_regset_pop_first(&ready);
from = pred[to];
r = loc[from];
type = types[from];
if (IR_IS_TYPE_INT(type)) {
ir_emit_mov_ext(ctx, type, to, r);
} else {
ir_emit_fp_mov(ctx, type, to, r);
}
IR_REGSET_EXCL(todo, to);
loc[from] = to;
if (from == r && IR_REGSET_IN(todo, from)) {
IR_REGSET_INCL(ready, from);
}
}
if (todo == IR_REGSET_EMPTY) {
return 1;
}
/* temporary registers may be the same as some of the destinations */
last_reg = IR_REG_NONE;
if (tmp_reg != IR_REG_NONE) {
IR_ASSERT(!IR_REGSET_IN(srcs, tmp_reg));
if (IR_REGSET_IN(todo, tmp_reg)) {
last_reg = tmp_reg;
IR_REGSET_EXCL(todo, tmp_reg);
}
}
last_fp_reg = IR_REG_NONE;
if (tmp_fp_reg != IR_REG_NONE) {
IR_ASSERT(!IR_REGSET_IN(srcs, tmp_fp_reg));
if (IR_REGSET_IN(todo, tmp_fp_reg)) {
last_fp_reg = tmp_fp_reg;
IR_REGSET_EXCL(todo, tmp_fp_reg);
}
}
while (todo != IR_REGSET_EMPTY) {
to = ir_regset_pop_first(&todo);
from = pred[to];
IR_ASSERT(to != loc[from]);
type = types[from];
if (IR_IS_TYPE_INT(type)) {
#ifdef IR_HAVE_SWAP_INT
if (pred[from] == to) {
ir_emit_swap(ctx, type, to, from);
IR_REGSET_EXCL(todo, from);
loc[to] = from;
loc[from] = to;
continue;
}
#endif
IR_ASSERT(tmp_reg != IR_REG_NONE);
IR_ASSERT(tmp_reg >= IR_REG_GP_FIRST && tmp_reg <= IR_REG_GP_LAST);
ir_emit_mov(ctx, type, tmp_reg, to);
loc[to] = tmp_reg;
} else {
#ifdef IR_HAVE_SWAP_FP
if (pred[from] == to) {
ir_emit_swap_fp(ctx, type, to, from);
IR_REGSET_EXCL(todo, from);
loc[to] = from;
loc[from] = to;
continue;
}
#endif
IR_ASSERT(tmp_fp_reg != IR_REG_NONE);
IR_ASSERT(tmp_fp_reg >= IR_REG_FP_FIRST && tmp_fp_reg <= IR_REG_FP_LAST);
ir_emit_fp_mov(ctx, type, tmp_fp_reg, to);
loc[to] = tmp_fp_reg;
}
while (1) {
ir_reg r;
from = pred[to];
r = loc[from];
type = types[from];
if (IR_IS_TYPE_INT(type)) {
ir_emit_mov_ext(ctx, type, to, r);
} else {
ir_emit_fp_mov(ctx, type, to, r);
}
IR_REGSET_EXCL(todo, to);
loc[from] = to;
if (from == r && IR_REGSET_IN(todo, from)) {
to = from;
} else {
break;
}
}
}
if (last_reg != IR_REG_NONE) {
to = last_reg;
from = pred[to];
type = types[from];
from = loc[from];
if (to != from) {
IR_ASSERT(IR_IS_TYPE_INT(type));
ir_emit_mov_ext(ctx, type, to, from);
}
}
if (last_fp_reg != IR_REG_NONE) {
to = last_fp_reg;
from = pred[to];
type = types[from];
from = loc[from];
if (to != from) {
IR_ASSERT(!IR_IS_TYPE_INT(type));
ir_emit_fp_mov(ctx, type, to, from);
}
}
return 1;
}
static void ir_emit_dessa_moves(ir_ctx *ctx, int b, ir_block *bb)
{
uint32_t succ, k, n = 0, n2 = 0;

View File

@@ -1596,48 +1596,41 @@ static void ir_vregs_join(ir_ctx *ctx, uint32_t r1, uint32_t r2)
//ir_mem_free(ival);
}
static bool ir_try_coalesce(ir_ctx *ctx, ir_ref from, ir_ref to)
static void ir_vregs_coalesce(ir_ctx *ctx, uint32_t v1, uint32_t v2, ir_ref from, ir_ref to)
{
ir_ref i;
uint32_t v1 = ctx->vregs[from];
uint32_t v2 = ctx->vregs[to];
uint16_t f1 = ctx->live_intervals[v1]->flags;
uint16_t f2 = ctx->live_intervals[v2]->flags;
if (v1 != v2 && !ir_vregs_overlap(ctx, v1, v2)) {
uint16_t f1 = ctx->live_intervals[v1]->flags;
uint16_t f2 = ctx->live_intervals[v2]->flags;
if ((f1 & IR_LIVE_INTERVAL_COALESCED) && !(f2 & IR_LIVE_INTERVAL_COALESCED)) {
ir_vregs_join(ctx, v1, v2);
ctx->vregs[to] = v1;
} else if ((f2 & IR_LIVE_INTERVAL_COALESCED) && !(f1 & IR_LIVE_INTERVAL_COALESCED)) {
ir_vregs_join(ctx, v2, v1);
ctx->vregs[from] = v2;
} else if (from < to) {
ir_vregs_join(ctx, v1, v2);
if (f2 & IR_LIVE_INTERVAL_COALESCED) {
for (i = 1; i < ctx->insns_count; i++) {
if (ctx->vregs[i] == v2) {
ctx->vregs[i] = v1;
}
if ((f1 & IR_LIVE_INTERVAL_COALESCED) && !(f2 & IR_LIVE_INTERVAL_COALESCED)) {
ir_vregs_join(ctx, v1, v2);
ctx->vregs[to] = v1;
} else if ((f2 & IR_LIVE_INTERVAL_COALESCED) && !(f1 & IR_LIVE_INTERVAL_COALESCED)) {
ir_vregs_join(ctx, v2, v1);
ctx->vregs[from] = v2;
} else if (from < to) {
ir_vregs_join(ctx, v1, v2);
if (f2 & IR_LIVE_INTERVAL_COALESCED) {
for (i = 1; i < ctx->insns_count; i++) {
if (ctx->vregs[i] == v2) {
ctx->vregs[i] = v1;
}
} else {
ctx->vregs[to] = v1;
}
} else {
ir_vregs_join(ctx, v2, v1);
if (f1 & IR_LIVE_INTERVAL_COALESCED) {
for (i = 1; i < ctx->insns_count; i++) {
if (ctx->vregs[i] == v1) {
ctx->vregs[i] = v2;
}
}
} else {
ctx->vregs[from] = v2;
}
ctx->vregs[to] = v1;
}
} else {
ir_vregs_join(ctx, v2, v1);
if (f1 & IR_LIVE_INTERVAL_COALESCED) {
for (i = 1; i < ctx->insns_count; i++) {
if (ctx->vregs[i] == v1) {
ctx->vregs[i] = v2;
}
}
} else {
ctx->vregs[from] = v2;
}
return 1;
}
return 0;
}
static void ir_add_phi_move(ir_ctx *ctx, uint32_t b, ir_ref from, ir_ref to)
@@ -1879,10 +1872,40 @@ int ir_coalesce(ir_ctx *ctx)
if (insn->op == IR_PHI) {
input = ir_insn_op(insn, k);
if (input > 0) {
if (!ir_try_coalesce(ctx, input, use)) {
ir_add_phi_move(ctx, b, input, use);
uint32_t v1 = ctx->vregs[input];
uint32_t v2 = ctx->vregs[use];
if (v1 == v2) {
/* already coalesced */
} else {
compact = 1;
if (!ir_vregs_overlap(ctx, v1, v2)) {
ir_vregs_coalesce(ctx, v1, v2, input, use);
compact = 1;
} else {
#if 1
ir_insn *input_insn = &ctx->ir_base[input];
if ((ir_op_flags[input_insn->op] & IR_OP_FLAG_COMMUTATIVE)
&& input_insn->op2 == use
&& input_insn->op1 != use
&& (ctx->live_intervals[v1]->use_pos->flags & IR_DEF_REUSES_OP1_REG)
&& ctx->live_intervals[v2]->end == IR_USE_LIVE_POS_FROM_REF(input)) {
ir_live_range *r = &ctx->live_intervals[v2]->range;
while (r->next) {
r = r->next;
}
r->end = IR_LOAD_LIVE_POS_FROM_REF(input);
ctx->live_intervals[v2]->end = IR_LOAD_LIVE_POS_FROM_REF(input);
ir_swap_operands(ctx, input, input_insn);
IR_ASSERT(!ir_vregs_overlap(ctx, v1, v2));
ir_vregs_coalesce(ctx, v1, v2, input, use);
compact = 1;
continue;
}
#endif
ir_add_phi_move(ctx, b, input, use);
}
}
} else {
/* Move for constant input */

File diff suppressed because it is too large Load Diff