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_MEM_LOAD (1<<6)
#define IR_LIVE_INTERVAL_REG_LOAD (1<<7) #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_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 { struct _ir_live_interval {
uint8_t type; uint8_t type;

95
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 */ /* We may reuse parameter stack slot for spilling */
ctx->live_intervals[ctx->vregs[ref]]->flags |= IR_LIVE_INTERVAL_MEM_PARAM; ctx->live_intervals[ctx->vregs[ref]]->flags |= IR_LIVE_INTERVAL_MEM_PARAM;
} else if (insn->op == IR_VLOAD) { } 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; ctx->live_intervals[ctx->vregs[ref]]->flags |= IR_LIVE_INTERVAL_MEM_LOAD;
} }
def_pos = IR_DEF_LIVE_POS_FROM_REF(ref); 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 _start = _ival->range.start; \
ir_live_pos _end = ir_ival_end(_ival); \ ir_live_pos _end = ir_ival_end(_ival); \
fprintf(stderr, action " R%d [%d.%d...%d.%d)" comment "\n", \ 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(_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(_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 _start = _ival->range.start; \
ir_live_pos _end = ir_ival_end(_ival); \ ir_live_pos _end = ir_ival_end(_ival); \
fprintf(stderr, action " R%d [%d.%d...%d.%d) to %s" comment "\n", \ 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(_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(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
ir_reg_name(_ival->reg, _ival->type)); \ 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 _end = ir_ival_end(_ival); \
ir_live_pos _pos = (pos); \ ir_live_pos _pos = (pos); \
fprintf(stderr, " ---- Split R%d [%d.%d...%d.%d) at %d.%d\n", \ 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(_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(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
IR_LIVE_POS_TO_REF(_pos), IR_LIVE_POS_TO_SUB_REF(_pos)); \ 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 _end = ir_ival_end(_ival); \
ir_live_pos _pos = (pos); \ ir_live_pos _pos = (pos); \
fprintf(stderr, action " R%d [%d.%d...%d.%d) assigned to %s at %d.%d\n", \ 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(_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(_end), IR_LIVE_POS_TO_SUB_REF(_end), \
ir_reg_name(_ival->reg, _ival->type), \ ir_reg_name(_ival->reg, _ival->type), \
@ -2077,14 +2077,30 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
other = other->list_next; other = other->list_next;
} }
/* Try to use hint */ if (ival->flags & IR_LIVE_INTERVAL_HAS_HINTS) {
reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos); /* Try to use hint */
if (reg != IR_REG_NONE) { reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos);
ival->reg = reg; if (reg != IR_REG_NONE) {
IR_LOG_LSRA_ASSIGN(" ---- Assign", ival, " (hint available without spilling)"); ival->reg = reg;
ival->list_next = *active; IR_LOG_LSRA_ASSIGN(" ---- Assign", ival, " (hint available without spilling)");
*active = ival; ival->list_next = *active;
return reg; *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 = register with highest freeUntilPos */
@ -2120,13 +2136,16 @@ 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_live_pos split_pos = ir_last_use_pos_before(ival, pos,
IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG); IR_USE_MUST_BE_IN_REG | IR_USE_SHOULD_BE_IN_REG);
if (split_pos > ival->range.start) { if (split_pos > ival->range.start) {
ir_reg pref_reg;
split_pos = ir_find_optimal_split_position(ctx, ival, split_pos, pos, 0); split_pos = ir_find_optimal_split_position(ctx, ival, split_pos, pos, 0);
other = ir_split_interval_at(ctx, ival, split_pos); 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) {
if (pref_reg != IR_REG_NONE) { ir_reg pref_reg = ir_try_allocate_preferred_reg(ctx, ival, available, freeUntilPos);
ival->reg = pref_reg;
if (pref_reg != IR_REG_NONE) {
ival->reg = pref_reg;
} else {
ival->reg = reg;
}
} else { } else {
ival->reg = reg; ival->reg = reg;
} }
@ -2285,7 +2304,10 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li
} }
/* register hinting */ /* register hinting */
reg = ir_get_preferred_reg(ctx, ival, available); 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) { if (reg == IR_REG_NONE) {
select_register: select_register:
reg = IR_REGSET_FIRST(available); reg = IR_REGSET_FIRST(available);
@ -2506,7 +2528,7 @@ static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_
IR_ASSERT(ival->top == ival && !ival->next && use_pos && use_pos->op_num == 0); IR_ASSERT(ival->top == ival && !ival->next && use_pos && use_pos->op_num == 0);
insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)]; insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)];
IR_ASSERT(insn->op == IR_PARAM); IR_ASSERT(insn->op == IR_PARAM);
use_pos =use_pos->next; use_pos = use_pos->next;
if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) { if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) {
return 0; return 0;
} }
@ -2524,7 +2546,7 @@ static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_
insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)]; insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)];
IR_ASSERT(insn->op == IR_VLOAD); IR_ASSERT(insn->op == IR_VLOAD);
use_pos =use_pos->next; use_pos = use_pos->next;
if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) { if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) {
return 0; return 0;
} }
@ -2565,7 +2587,7 @@ static void ir_assign_bound_spill_slots(ir_ctx *ctx)
if (b->val < 0) { if (b->val < 0) {
/* special spill slot */ /* special spill slot */
ival->stack_spill_pos = -b->val; 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 { } else {
/* node is bound to VAR node */ /* node is bound to VAR node */
ir_live_interval *var_ival; 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); 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->stack_spill_pos = var_ival->stack_spill_pos;
ival->flags |= IR_LIVE_INTERVAL_SPILLED;
} }
} }
} }
@ -2782,20 +2805,22 @@ static int ir_linear_scan(ir_ctx *ctx)
ival = ctx->live_intervals[j]; ival = ctx->live_intervals[j];
if (ival if (ival
&& (ival->next || ival->reg == IR_REG_NONE) && (ival->next || ival->reg == IR_REG_NONE)
&& ival->stack_spill_pos == -1 && ival->stack_spill_pos == -1) {
&& !(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)) { ival->flags |= IR_LIVE_INTERVAL_SPILLED;
ir_live_range *r; if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)) {
ir_live_range *r;
other = ival; other = ival;
while (other->next) { while (other->next) {
other = other->next; other = other->next;
}
r = &other->range;
while (r->next) {
r = r->next;
}
ival->end = r->end;
ir_add_to_unhandled_spill(&unhandled, ival);
} }
r = &other->range;
while (r->next) {
r = r->next;
}
ival->end = r->end;
ir_add_to_unhandled_spill(&unhandled, ival);
} }
} }
@ -2885,7 +2910,7 @@ static void assign_regs(ir_ctx *ctx)
/* load op1 directly into result (valid only when op1 register is not reused) */ /* load op1 directly into result (valid only when op1 register is not reused) */
ctx->regs[ref][1] = reg | IR_REG_SPILL_LOAD; 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) // TODO: Insert spill loads and stotres in optimal positons (resolution)
if (use_pos->op_num == 0) { if (use_pos->op_num == 0) {

View File

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

View File

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