Fix spilling code for arguments passed theought stack and change RA to

prefer reusing the same register for splitted intervals
i#	utils/
This commit is contained in:
Dmitry Stogov 2023-04-06 00:16:49 +03:00
parent 1e5e9e08ce
commit efa8a83153
4 changed files with 71 additions and 36 deletions

View File

@ -942,6 +942,7 @@ struct _ir_live_range {
#define IR_LIVE_INTERVAL_MEM_LOAD (1<<6)
#define IR_LIVE_INTERVAL_REG_LOAD (1<<7)
#define IR_LIVE_INTERVAL_SPILL_SPECIAL (1<<8) /* spill slot is pre-allocated in a special area (see ir_ctx.spill_reserved_base) */
#define IR_LIVE_INTERVAL_SPILLED (1<<9)
struct _ir_live_interval {
uint8_t type;

49
ir_ra.c
View File

@ -694,7 +694,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
/* We may reuse parameter stack slot for spilling */
ctx->live_intervals[ctx->vregs[ref]]->flags |= IR_LIVE_INTERVAL_MEM_PARAM;
} else if (insn->op == IR_VLOAD) {
/* Load may be fused into the useage instruction */
/* Load may be fused into the usage instruction */
ctx->live_intervals[ctx->vregs[ref]]->flags |= IR_LIVE_INTERVAL_MEM_LOAD;
}
def_pos = IR_DEF_LIVE_POS_FROM_REF(ref);
@ -1495,7 +1495,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
ir_live_pos _start = _ival->range.start; \
ir_live_pos _end = ir_ival_end(_ival); \
fprintf(stderr, action " R%d [%d.%d...%d.%d)" comment "\n", \
_ival->vreg, \
(_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end)); \
} \
@ -1506,7 +1506,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
ir_live_pos _start = _ival->range.start; \
ir_live_pos _end = ir_ival_end(_ival); \
fprintf(stderr, action " R%d [%d.%d...%d.%d) to %s" comment "\n", \
_ival->vreg, \
(_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
ir_reg_name(_ival->reg, _ival->type)); \
@ -1519,7 +1519,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
ir_live_pos _end = ir_ival_end(_ival); \
ir_live_pos _pos = (pos); \
fprintf(stderr, " ---- Split R%d [%d.%d...%d.%d) at %d.%d\n", \
_ival->vreg, \
(_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
IR_LIVE_POS_TO_REF(_pos), IR_LIVE_POS_TO_SUB_REF(_pos)); \
@ -1532,7 +1532,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
ir_live_pos _end = ir_ival_end(_ival); \
ir_live_pos _pos = (pos); \
fprintf(stderr, action " R%d [%d.%d...%d.%d) assigned to %s at %d.%d\n", \
_ival->vreg, \
(_ival->flags & IR_LIVE_INTERVAL_TEMP) ? 0 : _ival->vreg, \
IR_LIVE_POS_TO_REF(_start), IR_LIVE_POS_TO_SUB_REF(_start), \
IR_LIVE_POS_TO_REF(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
ir_reg_name(_ival->reg, _ival->type), \
@ -2077,6 +2077,7 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
other = other->list_next;
}
if (ival->flags & IR_LIVE_INTERVAL_HAS_HINTS) {
/* Try to use hint */
reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos);
if (reg != IR_REG_NONE) {
@ -2086,6 +2087,21 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
*active = ival;
return reg;
}
}
if (ival->top && ival->top != ival) {
/* Try to reuse the register previously allocated for splited interval */
reg = ival->top->reg;
if (reg >= 0
&& IR_REGSET_IN(available, reg)
&& ir_ival_end(ival) <= freeUntilPos[reg]) {
ival->reg = reg;
IR_LOG_LSRA_ASSIGN(" ---- Assign", ival, " (available without spilling)");
ival->list_next = *active;
*active = ival;
return reg;
}
}
/* reg = register with highest freeUntilPos */
reg = IR_REG_NONE;
@ -2120,16 +2136,19 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
ir_live_pos split_pos = ir_last_use_pos_before(ival, pos,
IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
if (split_pos > ival->range.start) {
ir_reg pref_reg;
split_pos = ir_find_optimal_split_position(ctx, ival, split_pos, pos, 0);
other = ir_split_interval_at(ctx, ival, split_pos);
pref_reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos);
if (ival->flags & IR_LIVE_INTERVAL_HAS_HINTS) {
ir_reg pref_reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos);
if (pref_reg != IR_REG_NONE) {
ival->reg = pref_reg;
} else {
ival->reg = reg;
}
} else {
ival->reg = reg;
}
IR_LOG_LSRA_ASSIGN(" ---- Assign", ival, " (available without spilling for the first part)");
ival->list_next = *active;
*active = ival;
@ -2285,7 +2304,10 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li
}
/* register hinting */
reg = IR_REG_NONE;
if (ival->flags & IR_LIVE_INTERVAL_HAS_HINTS) {
reg = ir_get_preferred_reg(ctx, ival, available);
}
if (reg == IR_REG_NONE) {
select_register:
reg = IR_REGSET_FIRST(available);
@ -2565,7 +2587,7 @@ static void ir_assign_bound_spill_slots(ir_ctx *ctx)
if (b->val < 0) {
/* special spill slot */
ival->stack_spill_pos = -b->val;
ival->flags |= IR_LIVE_INTERVAL_SPILL_SPECIAL;
ival->flags |= IR_LIVE_INTERVAL_SPILLED | IR_LIVE_INTERVAL_SPILL_SPECIAL;
} else {
/* node is bound to VAR node */
ir_live_interval *var_ival;
@ -2576,6 +2598,7 @@ static void ir_assign_bound_spill_slots(ir_ctx *ctx)
var_ival->stack_spill_pos = ir_allocate_spill_slot(ctx, var_ival->type, ctx->data);
}
ival->stack_spill_pos = var_ival->stack_spill_pos;
ival->flags |= IR_LIVE_INTERVAL_SPILLED;
}
}
}
@ -2782,8 +2805,9 @@ static int ir_linear_scan(ir_ctx *ctx)
ival = ctx->live_intervals[j];
if (ival
&& (ival->next || ival->reg == IR_REG_NONE)
&& ival->stack_spill_pos == -1
&& !(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)) {
&& ival->stack_spill_pos == -1) {
ival->flags |= IR_LIVE_INTERVAL_SPILLED;
if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)) {
ir_live_range *r;
other = ival;
@ -2798,6 +2822,7 @@ static int ir_linear_scan(ir_ctx *ctx)
ir_add_to_unhandled_spill(&unhandled, ival);
}
}
}
if (unhandled) {
uint8_t size;
@ -2885,7 +2910,7 @@ static void assign_regs(ir_ctx *ctx)
/* load op1 directly into result (valid only when op1 register is not reused) */
ctx->regs[ref][1] = reg | IR_REG_SPILL_LOAD;
}
if (ival->top->stack_spill_pos != -1) {
if (ival->top->flags & IR_LIVE_INTERVAL_SPILLED) {
// TODO: Insert spill loads and stotres in optimal positons (resolution)
if (use_pos->op_num == 0) {

View File

@ -86,6 +86,7 @@ test:
je .L3
movl %edx, %eax
movl 4(%esp), %ebp
movl %ebp, 0x30(%esp)
.L2:
cmpl $0, 0x40(%esp)
jne .L1
@ -96,9 +97,12 @@ test:
addl %ebx, %eax
movl (%esp), %edi
addl %edi, %eax
movl 0x30(%esp), %ebp
addl %ebp, %eax
movl 0x34(%esp), %ecx
addl %ecx, %eax
addl %ecx, %eax
movl 0x38(%esp), %edi
addl %edi, %eax
leal 1(%eax, %esi), %eax
movl 0x14(%esp), %ebx
movl 0x10(%esp), %ebp
@ -109,6 +113,9 @@ test:
.L3:
movl %eax, %esi
imull %ecx, %esi
movl %esi, 0x34(%esp)
movl 0x34(%esp), %esi
leal 1(%esi), %edi
movl %edi, 0x38(%esp)
movl %edx, %ebx
jmp .L2

View File

@ -47,7 +47,9 @@ test:
addl %ebx, %eax
addl %ebp, %eax
addl %esi, %eax
movl 0x2c(%esp), %ecx
addl %ecx, %eax
movl 0x30(%esp), %ecx
addl %ecx, %eax
addl %edi, %eax
subl 0x38(%esp), %eax