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

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  Update IR
This commit is contained in:
Dmitry Stogov
2025-10-08 23:37:16 +03:00
8 changed files with 261 additions and 64 deletions

View File

@@ -1032,6 +1032,7 @@ IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size)
#define IR_ERROR_UNSUPPORTED_CODE_RULE 3
#define IR_ERROR_LINK 4
#define IR_ERROR_ENCODE 5
#define IR_ERROR_TOO_LARGE 6
/* IR Memmory Allocation */
#ifndef ir_mem_malloc

View File

@@ -658,16 +658,35 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co
flags = IR_OP2_MUST_BE_IN_REG;
constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 1;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
constraints->tmp_regs[1] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 2;
}
break;
case IR_VA_ARG:
flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG;
constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_SAVE_SUB_REF);
n = 1;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
constraints->tmp_regs[1] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 2;
}
break;
case IR_VA_COPY:
flags = IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG;
constraints->tmp_regs[0] = IR_TMP_REG(1, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 1;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
constraints->tmp_regs[n] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
if (IR_IS_CONST_REF(insn->op3)) {
constraints->tmp_regs[n] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
break;
}
constraints->tmps_count = n;
@@ -6143,6 +6162,14 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
dasm_setup(&data.dasm_state, dasm_actions);
/* labels for each block + for each constant + rodata label + jmp_table label + for each entry + exit_table label */
dasm_growpc(&data.dasm_state, ctx->cfg_blocks_count + 1 + ctx->consts_count + 1 + 1 + 1 + ctx->entries_count + 1);
if (data.dasm_state->status != DASM_S_OK) {
IR_ASSERT(data.dasm_state->status == DASM_S_NOMEM);
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_TOO_LARGE;
return NULL;
}
data.emit_constants = ir_bitset_malloc(ctx->consts_count);
if (!(ctx->flags & IR_SKIP_PROLOGUE)) {
@@ -6509,12 +6536,20 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
return NULL;
}
ret = dasm_link(&data.dasm_state, size_ptr);
if (ret != DASM_S_OK) {
IR_ASSERT(0);
if (data.dasm_state->status != DASM_S_OK) {
IR_ASSERT(data.dasm_state->status == DASM_S_NOMEM);
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_LINK;
ctx->status = IR_ERROR_TOO_LARGE;
return NULL;
}
ret = dasm_link(&data.dasm_state, size_ptr);
if (ret != DASM_S_OK) {
IR_ASSERT(ret == DASM_S_NOMEM);
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = (ret == DASM_S_NOMEM) ? IR_ERROR_TOO_LARGE : IR_ERROR_LINK;
return NULL;
}
size = *size_ptr;

View File

@@ -40,12 +40,41 @@ void ir_consistency_check(void)
IR_ASSERT(IR_ADD + 1 == IR_SUB);
}
static bool ir_check_use_list(const ir_ctx *ctx, ir_ref from, ir_ref to)
typedef struct {
ir_arena *arena;
ir_bitset *use_set;
ir_bitset *input_set;
} ir_check_ctx;
static bool ir_check_use_list(ir_check_ctx *check_ctx, const ir_ctx *ctx, ir_ref from, ir_ref to)
{
ir_ref n, *p;
ir_use_list *use_list = &ctx->use_lists[from];
n = use_list->count;
if (n > 16) {
/* Avoid quadratic complexity by maintaining a temporary bit-set */
ir_bitset set;
if (!check_ctx->use_set || !(set = check_ctx->use_set[from])) {
if (!check_ctx->arena) {
check_ctx->arena = ir_arena_create(sizeof(ir_arena) +
ctx->insns_count * sizeof(ir_bitset) +
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
}
if (!check_ctx->use_set) {
check_ctx->use_set = ir_arena_alloc(&check_ctx->arena, ctx->insns_count * sizeof(ir_bitset));
memset(check_ctx->use_set, 0, ctx->insns_count * sizeof(ir_bitset));
}
check_ctx->use_set[from] = set = (ir_bitset)ir_arena_alloc(&check_ctx->arena,
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
memset(set, 0, ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
ir_bitset_incl(set, *p);
}
}
return ir_bitset_in(set, to);
}
for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
if (*p == to) {
return 1;
@@ -54,12 +83,35 @@ static bool ir_check_use_list(const ir_ctx *ctx, ir_ref from, ir_ref to)
return 0;
}
static bool ir_check_input_list(const ir_ctx *ctx, ir_ref from, ir_ref to)
static bool ir_check_input_list(ir_check_ctx *check_ctx, const ir_ctx *ctx, ir_ref from, ir_ref to)
{
ir_insn *insn = &ctx->ir_base[to];
ir_ref n, j, *p;
n = ir_input_edges_count(ctx, insn);
if (n > 16) {
/* Avoid quadratic complexity by maintaining a temporary bit-set */
ir_bitset set;
if (!check_ctx->input_set || !(set = check_ctx->input_set[to])) {
if (!check_ctx->arena) {
check_ctx->arena = ir_arena_create(sizeof(ir_arena) +
ctx->insns_count * sizeof(ir_bitset) +
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
}
if (!check_ctx->input_set) {
check_ctx->input_set = ir_arena_alloc(&check_ctx->arena, ctx->insns_count * sizeof(ir_bitset));
memset(check_ctx->input_set, 0, ctx->insns_count * sizeof(ir_bitset));
}
check_ctx->input_set[to] = set = (ir_bitset)ir_arena_alloc(&check_ctx->arena,
ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
memset(set, 0, ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
if (*p > 0) ir_bitset_incl(set, *p);
}
}
return ir_bitset_in(set, from);
}
for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
if (*p == from) {
return 1;
@@ -93,6 +145,11 @@ bool ir_check(const ir_ctx *ctx)
ir_type type;
uint32_t flags;
bool ok = 1;
ir_check_ctx check_ctx;
check_ctx.arena = NULL;
check_ctx.use_set = NULL;
check_ctx.input_set = NULL;
for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
if (insn->op >= IR_LAST_OP) {
@@ -255,7 +312,7 @@ bool ir_check(const ir_ctx *ctx)
}
if (ctx->use_lists
&& use > 0
&& !ir_check_use_list(ctx, use, i)) {
&& !ir_check_use_list(&check_ctx, ctx, use, i)) {
fprintf(stderr, "ir_base[%d].ops[%d] is not in use list (%d)\n", i, j, use);
ok = 0;
}
@@ -313,7 +370,7 @@ bool ir_check(const ir_ctx *ctx)
for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
use = *p;
if (!ir_check_input_list(ctx, i, use)) {
if (!ir_check_input_list(&check_ctx, ctx, i, use)) {
fprintf(stderr, "ir_base[%d] is in use list of ir_base[%d]\n", use, i);
ok = 0;
}
@@ -393,6 +450,10 @@ bool ir_check(const ir_ctx *ctx)
insn += n;
}
if (check_ctx.arena) {
ir_arena_free(check_ctx.arena);
}
// if (!ok) {
// ir_dump_codegen(ctx, stderr);
// }

View File

@@ -32,8 +32,14 @@
do { \
size_t _sz = (sz), _need = (need); \
if (_sz < _need) { \
size_t _limit = sizeof(t) * DASM_SEC2POS(1); \
if (_need > _limit) { \
Dst_REF->status = DASM_S_NOMEM; \
return; \
} \
if (_sz < 16) _sz = 16; \
while (_sz < _need) _sz += _sz; \
if (_sz > _limit) _sz = _limit; \
(p) = (t *)ir_mem_realloc((p), _sz); \
(sz) = _sz; \
} \

View File

@@ -538,7 +538,8 @@ IR_FOLD(DIV(C_ADDR, C_ADDR))
IR_FOLD(DIV(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
if (op2_insn->val.i64 == 0) {
if (op2_insn->val.i64 == 0
|| (op2_insn->val.i64 == -1 && op1_insn->val.u8 == 0x80)) {
/* division by zero */
IR_FOLD_EMIT;
}
@@ -548,7 +549,8 @@ IR_FOLD(DIV(C_I8, C_I8))
IR_FOLD(DIV(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
if (op2_insn->val.i64 == 0) {
if (op2_insn->val.i64 == 0
|| (op2_insn->val.i64 == -1 && op1_insn->val.u16 == 0x8000)) {
/* division by zero */
IR_FOLD_EMIT;
}
@@ -558,7 +560,8 @@ IR_FOLD(DIV(C_I16, C_I16))
IR_FOLD(DIV(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
if (op2_insn->val.i64 == 0) {
if (op2_insn->val.i64 == 0
|| (op2_insn->val.i64 == -1 && op1_insn->val.u32 == 0x80000000)) {
/* division by zero */
IR_FOLD_EMIT;
}
@@ -568,7 +571,8 @@ IR_FOLD(DIV(C_I32, C_I32))
IR_FOLD(DIV(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
if (op2_insn->val.i64 == 0) {
if (op2_insn->val.i64 == 0
|| (op2_insn->val.i64 == -1 && op1_insn->val.u64 == 0x8000000000000000)) {
/* division by zero */
IR_FOLD_EMIT;
}
@@ -615,12 +619,27 @@ IR_FOLD(MOD(C_I64, C_I64))
}
IR_FOLD(NEG(C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int8_t)(0 - op1_insn->val.u8));
}
IR_FOLD(NEG(C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int16_t)(0 -op1_insn->val.u16));
}
IR_FOLD(NEG(C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int32_t)(0 - op1_insn->val.u32));
}
IR_FOLD(NEG(C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(-op1_insn->val.u64);
IR_FOLD_CONST_I(0 - op1_insn->val.u64);
}
IR_FOLD(NEG(C_DOUBLE))
@@ -1841,6 +1860,12 @@ IR_FOLD(ADD(SUB, _))
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
if (op1_insn->op2 == op2) {
/* (a - b) + b => a */
if (ctx->ir_base[op1_insn->op1].type != IR_OPT_TYPE(opt)) {
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
op1 = op1_insn->op1;
op2 = IR_UNUSED;
IR_FOLD_RESTART;
}
IR_FOLD_COPY(op1_insn->op1);
}
}
@@ -1852,6 +1877,12 @@ IR_FOLD(ADD(_, SUB))
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
if (op2_insn->op2 == op1) {
/* a + (b - a) => b */
if (ctx->ir_base[op2_insn->op1].type != IR_OPT_TYPE(opt)) {
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
op1 = op2_insn->op1;
op2 = IR_UNUSED;
IR_FOLD_RESTART;
}
IR_FOLD_COPY(op2_insn->op1);
}
}
@@ -1863,9 +1894,21 @@ IR_FOLD(SUB(ADD, _))
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
if (op1_insn->op1 == op2) {
/* (a + b) - a => b */
if (ctx->ir_base[op1_insn->op2].type != IR_OPT_TYPE(opt)) {
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
op1 = op1_insn->op2;
op2 = IR_UNUSED;
IR_FOLD_RESTART;
}
IR_FOLD_COPY(op1_insn->op2);
} else if (op1_insn->op2 == op2) {
/* (a + b) - a => b */
if (ctx->ir_base[op1_insn->op1].type != IR_OPT_TYPE(opt)) {
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
op1 = op1_insn->op1;
op2 = IR_UNUSED;
IR_FOLD_RESTART;
}
IR_FOLD_COPY(op1_insn->op1);
}
}
@@ -1911,6 +1954,12 @@ IR_FOLD(SUB(_, SUB))
if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))) {
if (op2_insn->op1 == op1) {
/* a - (a - b) => b */
if (ctx->ir_base[op2_insn->op2].type != IR_OPT_TYPE(opt)) {
opt = IR_BITCAST | (opt & IR_OPT_TYPE_MASK);
op1 = op2_insn->op2;
op2 = IR_UNUSED;
IR_FOLD_RESTART;
}
IR_FOLD_COPY(op2_insn->op2);
}
}

View File

@@ -238,6 +238,7 @@ IR_ALWAYS_INLINE ir_arena* ir_arena_create(size_t size)
IR_ASSERT(size >= IR_ALIGNED_SIZE(sizeof(ir_arena), 8));
arena = (ir_arena*)ir_mem_malloc(size);
if (UNEXPECTED(!arena))return NULL;
arena->ptr = (char*) arena + IR_ALIGNED_SIZE(sizeof(ir_arena), 8);
arena->end = (char*) arena + size;
arena->prev = NULL;
@@ -267,6 +268,7 @@ IR_ALWAYS_INLINE void* ir_arena_alloc(ir_arena **arena_ptr, size_t size)
(size_t)(arena->end - (char*) arena);
ir_arena *new_arena = (ir_arena*)ir_mem_malloc(arena_size);
if (UNEXPECTED(!new_arena)) return NULL;
ptr = (char*) new_arena + IR_ALIGNED_SIZE(sizeof(ir_arena), 8);
new_arena->ptr = (char*) new_arena + IR_ALIGNED_SIZE(sizeof(ir_arena), 8) + size;
new_arena->end = (char*) new_arena + arena_size;

View File

@@ -583,6 +583,15 @@ static IR_NEVER_INLINE void ir_sccp_analyze(ir_ctx *ctx, ir_insn *_values, ir_bi
}
} else {
IR_MAKE_BOTTOM_EX(i);
n = IR_INPUT_EDGES_COUNT(flags);
for (p = insn->ops + 1; n > 0; p++, n--) {
ir_ref input = *p;
if (input > 0) {
if (_values[input].op == IR_TOP) {
ir_sccp_add_input(ctx, _values, worklist, input);
}
}
}
}
} else if (flags & IR_OP_FLAG_BB_START) {
if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_BEGIN) {
@@ -717,52 +726,32 @@ static IR_NEVER_INLINE void ir_sccp_analyze(ir_ctx *ctx, ir_insn *_values, ir_bi
ir_bitqueue_add(iter_worklist, i);
IR_MAKE_BOTTOM(i);
} else {
if (_values[i].op == IR_TOP) {
bool has_top = 0;
/* control, call, load and store instructions may have unprocessed inputs */
n = IR_INPUT_EDGES_COUNT(flags);
if (IR_OP_HAS_VAR_INPUTS(flags) && (n = insn->inputs_count) > 3) {
for (j = 0; j < (n>>2); j++) {
_values[i+j+1].optx = IR_BOTTOM; /* keep the tail of a long multislot instruction */
}
for (j = 2, p = insn->ops + j; j <= n; j++, p++) {
IR_ASSERT(IR_OPND_KIND(flags, j) == IR_OPND_DATA);
use = *p;
if (use > 0 && _values[use].op == IR_TOP) {
has_top = 1;
ir_sccp_add_input(ctx, _values, worklist, use);
}
}
} else if (n >= 2) {
IR_ASSERT(IR_OPND_KIND(flags, 2) == IR_OPND_DATA);
use = insn->op2;
/* control, call, load and store instructions may have unprocessed inputs */
n = IR_INPUT_EDGES_COUNT(flags);
if (IR_OP_HAS_VAR_INPUTS(flags) && (n = insn->inputs_count) > 3) {
for (j = 0; j < (n>>2); j++) {
_values[i+j+1].optx = IR_BOTTOM; /* keep the tail of a long multislot instruction */
}
for (j = 2, p = insn->ops + j; j <= n; j++, p++) {
IR_ASSERT(IR_OPND_KIND(flags, j) == IR_OPND_DATA);
use = *p;
if (use > 0 && _values[use].op == IR_TOP) {
has_top = 1;
ir_sccp_add_input(ctx, _values, worklist, use);
}
if (n > 2) {
IR_ASSERT(n == 3);
IR_ASSERT(IR_OPND_KIND(flags, 3) == IR_OPND_DATA);
use = insn->op3;
if (use > 0 && _values[use].op == IR_TOP) {
has_top = 1;
ir_sccp_add_input(ctx, _values, worklist, use);
}
}
}
if (has_top && !(flags & IR_OP_FLAG_BB_END)) {
use = ir_next_control(ctx, i);
if (_values[use].op == IR_TOP) {
has_top = 1;
/* do forward control propagaton only once */
if (!_values[use].op1) {
_values[use].op1 = 1;
ir_bitqueue_add(worklist, use);
}
} else if (n >= 2) {
IR_ASSERT(IR_OPND_KIND(flags, 2) == IR_OPND_DATA);
use = insn->op2;
if (use > 0 && _values[use].op == IR_TOP) {
ir_sccp_add_input(ctx, _values, worklist, use);
}
if (n > 2) {
IR_ASSERT(n == 3);
IR_ASSERT(IR_OPND_KIND(flags, 3) == IR_OPND_DATA);
use = insn->op3;
if (use > 0 && _values[use].op == IR_TOP) {
ir_sccp_add_input(ctx, _values, worklist, use);
}
continue;
}
}
IR_MAKE_BOTTOM(i);
@@ -1325,8 +1314,8 @@ static ir_ref ir_iter_find_cse(ir_ctx *ctx, ir_ref ref, uint32_t opt, ir_ref op1
}
}
} else if (n < 2) {
IR_ASSERT(n == 1);
if (!IR_IS_CONST_REF(op1)) {
if (op1 > 0) {
IR_ASSERT(n == 1);
use_list = &ctx->use_lists[op1];
n = use_list->count;
for (p = ctx->use_edges + use_list->refs; n > 0; p++, n--) {

View File

@@ -1238,6 +1238,9 @@ op2_const:
if (IR_IS_CONST_REF(insn->op2) && insn->op1 != insn->op2) {
constraints->tmp_regs[n] = IR_TMP_REG(2, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
} else if (ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA) {
constraints->tmp_regs[n] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 1;
}
break;
case IR_CMP_INT:
@@ -1564,16 +1567,35 @@ op2_const:
flags = IR_OP2_MUST_BE_IN_REG;
constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 1;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
constraints->tmp_regs[1] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 2;
}
break;
case IR_VA_ARG:
flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG;
constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_SAVE_SUB_REF);
n = 1;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
constraints->tmp_regs[1] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 2;
}
break;
case IR_VA_COPY:
flags = IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG;
constraints->tmp_regs[0] = IR_TMP_REG(1, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n = 1;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
constraints->tmp_regs[n] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
if (IR_IS_CONST_REF(insn->op3)) {
constraints->tmp_regs[n] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
break;
case IR_SSE_SQRT:
case IR_SSE_RINT:
@@ -3573,7 +3595,13 @@ static ir_mem ir_fuse_addr(ir_ctx *ctx, ir_ref root, ir_ref ref)
case IR_LEA_B_SI_O:
offset_insn = insn;
op1_insn = &ctx->ir_base[insn->op1];
base_reg_ref = insn->op1 * sizeof(ir_ref) + 1;
if (ir_rule(ctx, op1_insn->op1) == IR_STATIC_ALLOCA) {
offset = ir_local_offset(ctx, &ctx->ir_base[op1_insn->op1]);
base_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER;
base_reg_ref = IR_UNUSED;
} else {
base_reg_ref = insn->op1 * sizeof(ir_ref) + 1;
}
index_reg_ref = op1_insn->op2 * sizeof(ir_ref) + 1;
op2_insn = &ctx->ir_base[op1_insn->op2];
scale = ctx->ir_base[op2_insn->op2].val.i32;
@@ -3582,7 +3610,13 @@ static ir_mem ir_fuse_addr(ir_ctx *ctx, ir_ref root, ir_ref ref)
offset_insn = insn;
op1_insn = &ctx->ir_base[insn->op1];
index_reg_ref = op1_insn->op1 * sizeof(ir_ref) + 1;
base_reg_ref = insn->op1 * sizeof(ir_ref) + 2;
if (ir_rule(ctx, op1_insn->op2) == IR_STATIC_ALLOCA) {
offset = ir_local_offset(ctx, &ctx->ir_base[op1_insn->op2]);
base_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER;
base_reg_ref = IR_UNUSED;
} else {
base_reg_ref = insn->op1 * sizeof(ir_ref) + 2;
}
op1_insn = &ctx->ir_base[op1_insn->op1];
scale = ctx->ir_base[op1_insn->op2].val.i32;
break;
@@ -3620,7 +3654,7 @@ static ir_mem ir_fuse_addr(ir_ctx *ctx, ir_ref root, ir_ref ref)
offset += (int64_t)(intptr_t)(addr);
} else {
if (offset_insn->op == IR_SUB) {
offset = -addr_insn->val.i32;
offset -= addr_insn->val.i32;
} else {
offset += addr_insn->val.i32;
}
@@ -8596,7 +8630,11 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn)
| add Ra(tmp_reg), sizeof(void*)
| mov aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))], Ra(tmp_reg)
|2:
| mov Ra(def_reg), aword [Ra(tmp_reg)-sizeof(void*)]
if (ir_type_size[type] == 8) {
| mov Rq(def_reg), qword [Ra(tmp_reg)-sizeof(void*)]
} else {
| mov Rd(def_reg), dword [Ra(tmp_reg)-sizeof(void*)]
}
} else {
| mov Rd(tmp_reg), dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, fp_offset))]
| cmp Rd(tmp_reg), sizeof(void*) * IR_REG_INT_ARGS + 16 * IR_REG_FP_ARGS
@@ -11019,6 +11057,14 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
dasm_setup(&data.dasm_state, dasm_actions);
/* labels for each block + for each constant + rodata label + jmp_table label + for each entry */
dasm_growpc(&data.dasm_state, ctx->cfg_blocks_count + 1 + ctx->consts_count + 1 + 1 + 1 + ctx->entries_count);
if (data.dasm_state->status != DASM_S_OK) {
IR_ASSERT(data.dasm_state->status == DASM_S_NOMEM);
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_TOO_LARGE;
return NULL;
}
data.emit_constants = ir_bitset_malloc(ctx->consts_count);
if ((ctx->flags & IR_GEN_ENDBR) && (ctx->flags & IR_START_BR_TARGET)) {
@@ -11515,12 +11561,20 @@ next_block:;
return NULL;
}
ret = dasm_link(&data.dasm_state, size_ptr);
if (ret != DASM_S_OK) {
IR_ASSERT(0);
if (data.dasm_state->status != DASM_S_OK) {
IR_ASSERT(data.dasm_state->status == DASM_S_NOMEM);
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_LINK;
ctx->status = IR_ERROR_TOO_LARGE;
return NULL;
}
ret = dasm_link(&data.dasm_state, size_ptr);
if (ret != DASM_S_OK) {
IR_ASSERT(ret == DASM_S_NOMEM);
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = (ret == DASM_S_NOMEM) ? IR_ERROR_TOO_LARGE : IR_ERROR_LINK;
return NULL;
}
size = *size_ptr;