From 009e9c4a53788594175992dc3cdd577034f828f6 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 20 Jun 2023 08:34:54 +0300 Subject: [PATCH] Split assign_regs() loop into two versions (with and without spilling). --- ir_ra.c | 141 ++++++++++++++++++++++++----------------- tests/debug/ra_002.irt | 39 ++++++++++++ tests/debug/ra_003.irt | 40 ++++++++++++ 3 files changed, 163 insertions(+), 57 deletions(-) create mode 100644 tests/debug/ra_002.irt create mode 100644 tests/debug/ra_003.irt diff --git a/ir_ra.c b/ir_ra.c index 747813f..2016083 100644 --- a/ir_ra.c +++ b/ir_ra.c @@ -3525,78 +3525,105 @@ static void assign_regs(ir_ctx *ctx) memset(ctx->regs, IR_REG_NONE, sizeof(ir_regs) * ctx->insns_count); } - for (i = 1; i <= ctx->vregs_count; i++) { - top_ival = ival = ctx->live_intervals[i]; - if (ival) { - do { - if (ival->reg != IR_REG_NONE) { - use_pos = ival->use_pos; - while (use_pos) { - ref = IR_LIVE_POS_TO_REF(use_pos->pos); + if (!(ctx->flags & (IR_RA_HAVE_SPLITS|IR_RA_HAVE_SPILLS))) { + for (i = 1; i <= ctx->vregs_count; i++) { + top_ival = ival = ctx->live_intervals[i]; + if (ival) { + do { + if (ival->reg != IR_REG_NONE) { reg = ival->reg; - if (use_pos->op_num == 0 - && (use_pos->flags & IR_DEF_REUSES_OP1_REG) - && ctx->regs[ref][1] != IR_REG_NONE - && IR_REG_SPILLED(ctx->regs[ref][1]) - && (ctx->regs[ref][2] == IR_REG_NONE || IR_REG_NUM(ctx->regs[ref][2]) != reg) - && (ctx->regs[ref][3] == IR_REG_NONE || IR_REG_NUM(ctx->regs[ref][3]) != reg)) { - /* load op1 directly into result (valid only when op1 register is not reused) */ - if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { - ctx->regs[ref][1] = reg | IR_REG_SPILL_SPECIAL; - } else { - ctx->regs[ref][1] = reg | IR_REG_SPILL_LOAD; - } + use_pos = ival->use_pos; + while (use_pos) { + ref = (use_pos->hint_ref < 0) ? -use_pos->hint_ref : IR_LIVE_POS_TO_REF(use_pos->pos); + ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); + use_pos = use_pos->next; } - if (top_ival->flags & IR_LIVE_INTERVAL_SPILLED) { - // TODO: Insert spill loads and stotres in optimal positons (resolution) + } + ival = ival->next; + } while (ival); + } + } + } else { + for (i = 1; i <= ctx->vregs_count; i++) { + top_ival = ival = ctx->live_intervals[i]; + if (ival) { + do { + if (ival->reg != IR_REG_NONE) { + use_pos = ival->use_pos; + while (use_pos) { + reg = ival->reg; + ref = (use_pos->hint_ref < 0) ? -use_pos->hint_ref : IR_LIVE_POS_TO_REF(use_pos->pos); + if (use_pos->op_num == 0 + && (use_pos->flags & IR_DEF_REUSES_OP1_REG) + && ctx->regs[ref][1] != IR_REG_NONE + && IR_REG_SPILLED(ctx->regs[ref][1]) + && IR_REG_NUM(ctx->regs[ref][1]) != reg + && IR_REG_NUM(ctx->regs[ref][2]) != reg + && IR_REG_NUM(ctx->regs[ref][3]) != reg) { + /* load op1 directly into result (valid only when op1 register is not reused) */ + ir_reg old_reg = IR_REG_NUM(ctx->regs[ref][1]); - if (use_pos->op_num == 0) { - if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { - reg |= IR_REG_SPILL_SPECIAL; + if (ctx->live_intervals[ctx->vregs[ctx->ir_base[ref].op1]]->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { + ctx->regs[ref][1] = reg | IR_REG_SPILL_SPECIAL; } else { - reg |= IR_REG_SPILL_STORE; + ctx->regs[ref][1] = reg | IR_REG_SPILL_LOAD; } - } else { - if ((use_pos->flags & IR_USE_MUST_BE_IN_REG) - || ctx->ir_base[ref].op == IR_CALL - || ctx->ir_base[ref].op == IR_TAILCALL - || ctx->ir_base[ref].op == IR_SNAPSHOT - || (use_pos->op_num == 2 - && ctx->ir_base[ref].op1 == ctx->ir_base[ref].op2 - && IR_REG_NUM(ctx->regs[ref][1]) == reg)) { + if (IR_REG_NUM(ctx->regs[ref][2]) == old_reg) { + ctx->regs[ref][2] = reg; + } + if (IR_REG_NUM(ctx->regs[ref][3]) == old_reg) { + ctx->regs[ref][3] = reg; + } + } + if (top_ival->flags & IR_LIVE_INTERVAL_SPILLED) { + // TODO: Insert spill loads and stotres in optimal positons (resolution) + + if (use_pos->op_num == 0) { if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { reg |= IR_REG_SPILL_SPECIAL; } else { - reg |= IR_REG_SPILL_LOAD; + reg |= IR_REG_SPILL_STORE; } } else { - /* fuse spill load (valid only when register is not reused) */ - reg = IR_REG_NONE; + if ((use_pos->flags & IR_USE_MUST_BE_IN_REG) + || ctx->ir_base[ref].op == IR_CALL + || ctx->ir_base[ref].op == IR_TAILCALL + || ctx->ir_base[ref].op == IR_SNAPSHOT) { + if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { + reg |= IR_REG_SPILL_SPECIAL; + } else { + reg |= IR_REG_SPILL_LOAD; + } + } else if (use_pos->op_num == 2 + && ctx->ir_base[ref].op1 == ctx->ir_base[ref].op2 + && IR_REG_NUM(ctx->regs[ref][1]) == reg) { + /* pass */ + } else { + /* fuse spill load (valid only when register is not reused) */ + reg = IR_REG_NONE; + } } } - } - if (use_pos->hint_ref < 0) { - ref = -use_pos->hint_ref; - } - ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); - - use_pos = use_pos->next; - } - } else if ((top_ival->flags & IR_LIVE_INTERVAL_SPILLED) - && !(top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL)) { - use_pos = ival->use_pos; - while (use_pos) { - ref = IR_LIVE_POS_TO_REF(use_pos->pos); - if (ctx->ir_base[ref].op == IR_SNAPSHOT) { - /* A reference to a CPU spill slot */ - reg = IR_REG_SPILL_STORE | IR_REG_STACK_POINTER; ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); + + use_pos = use_pos->next; + } + } else if ((top_ival->flags & IR_LIVE_INTERVAL_SPILLED) + && !(top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL)) { + use_pos = ival->use_pos; + while (use_pos) { + ref = (use_pos->hint_ref < 0) ? -use_pos->hint_ref : IR_LIVE_POS_TO_REF(use_pos->pos); + if (ctx->ir_base[ref].op == IR_SNAPSHOT) { + /* A reference to a CPU spill slot */ + reg = IR_REG_SPILL_STORE | IR_REG_STACK_POINTER; + ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); + } + use_pos = use_pos->next; } - use_pos = use_pos->next; } - } - ival = ival->next; - } while (ival); + ival = ival->next; + } while (ival); + } } } diff --git a/tests/debug/ra_002.irt b/tests/debug/ra_002.irt new file mode 100644 index 0000000..7b3b5c9 --- /dev/null +++ b/tests/debug/ra_002.irt @@ -0,0 +1,39 @@ +--TEST-- +002: Register Allocation (spill load into result - movsd (%rsp), %xmm1) +--TARGET-- +x86_64 +--ARGS-- +-S +--CODE-- +{ + uintptr_t fn = func(printf); + uintptr_t format = "hello\n"; + l_1 = START(l_3); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + double z = PARAM(l_1, "z", 2); + l_2 = CALL(l_1, fn, format); + double ret1 = SUB(x, y); + double ret2 = SUB(y, z); + double ret = ADD(ret1, ret2); + l_3 = RETURN(l_2, ret); +} +--EXPECT-- +test: + subq $0x18, %rsp + movsd %xmm0, (%rsp) + movsd %xmm1, 8(%rsp) + movsd %xmm2, 0x10(%rsp) + leaq .L1(%rip), %rdi + movabsq $_IO_printf, %rax + callq *%rax + movsd (%rsp), %xmm1 + subsd 8(%rsp), %xmm1 + movsd 8(%rsp), %xmm0 + subsd 0x10(%rsp), %xmm0 + addsd %xmm1, %xmm0 + addq $0x18, %rsp + retq +.rodata +.L1: + .db 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 diff --git a/tests/debug/ra_003.irt b/tests/debug/ra_003.irt new file mode 100644 index 0000000..5640aba --- /dev/null +++ b/tests/debug/ra_003.irt @@ -0,0 +1,40 @@ +--TEST-- +003: Register Allocation (spill load into result - movsd (%rsp), %xmm1) +--TARGET-- +x86_64 +--ARGS-- +-S +--CODE-- +{ + uintptr_t fn = func(printf); + uintptr_t format = "hello\n"; + l_1 = START(l_3); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + double z = PARAM(l_1, "z", 2); + l_2 = CALL(l_1, fn, format); + double ret1 = ADD(x, x); + double ret2 = SUB(y, z); + double ret = ADD(ret1, ret2); + l_3 = RETURN(l_2, ret); +} +--EXPECT-- +test: + subq $0x18, %rsp + movsd %xmm0, (%rsp) + movsd %xmm1, 8(%rsp) + movsd %xmm2, 0x10(%rsp) + leaq .L1(%rip), %rdi + movabsq $_IO_printf, %rax + callq *%rax + movsd (%rsp), %xmm1 + addsd %xmm1, %xmm1 + movsd 8(%rsp), %xmm0 + subsd 0x10(%rsp), %xmm0 + addsd %xmm1, %xmm0 + addq $0x18, %rsp + retq +.rodata + .db 0x90, 0x90 +.L1: + .db 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00