From 8496780ece35018eaa50235ea3b86ea64039b99b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 16 May 2022 15:34:36 +0300 Subject: [PATCH] Fix temporary register usage for parralel arguments passing --- TODO | 8 +++---- ir_x86.dasc | 56 ++++++++++++++++++++++++++++++++++++------- tests/debug/call3.irt | 34 ++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 tests/debug/call3.irt diff --git a/TODO b/TODO index e110552..f3630f7 100644 --- a/TODO +++ b/TODO @@ -36,10 +36,10 @@ - kill - restricted regset + must be in register - ? temporary registers + + temporary registers + switch - - arguments loading - - parameter passing + ? arguments loading + + parameter passing + dessa ? spills + spill everywhere code placement @@ -63,7 +63,7 @@ + temporary register (e.g. for unsupported immediate operand in mul, div, and 64-bit constants) + temporary register for swap (dessa3.ir) + temporary register for spill loads and stores - - temporary register for swap during parallel parameter pssing + + temporary register for swap during parallel parameter pssing + IR_CMP_AND_BRANCH_FP invalid position of tmp variables (fib.ir) - stack arguments and parameters - return merge/split diff --git a/ir_x86.dasc b/ir_x86.dasc index 7f30e21..29ddaae 100644 --- a/ir_x86.dasc +++ b/ir_x86.dasc @@ -730,6 +730,31 @@ ir_reg ir_uses_fixed_reg(ir_ctx *ctx, ir_ref ref, int op_num) return IR_REG_NONE; } +static bool ir_may_need_tmp_reg_for_int_args_swap(ir_ctx *ctx, ir_ref ref) +{ + ir_insn *insn = &ctx->ir_base[ref]; + int j, n; + ir_type type; + int int_param = 0; + int int_reg_params_count = IR_REG_INT_ARGS; + + n = ir_input_edges_count(ctx, insn); + for (j = 3; j <= n; j++) { + type = ctx->ir_base[insn->ops[j]].type; + if (IR_IS_TYPE_INT(type)) { + if (int_param < int_reg_params_count) { + if (int_param > 0) { + return 1; + } + } else { + return 0; + } + int_param++; + } + } + return 0; +} + bool ir_result_reuses_op1_reg(ir_ctx *ctx, ir_ref ref) { ir_ref rule; @@ -983,6 +1008,16 @@ cmp_fp: n++; } return n; + case IR_CALL: + case IR_TAILCALL: + if (ir_may_need_tmp_reg_for_int_args_swap(ctx, ref)) { + tmp_regs[0].num = 1; + tmp_regs[0].type = IR_ADDR; + tmp_regs[0].start = IR_LOAD_SUB_REF; + tmp_regs[0].end = IR_USE_SUB_REF; + return 1; + } + break; case IR_SKIP: insn = &ctx->ir_base[ref]; switch (insn->op) { @@ -3442,7 +3477,7 @@ typedef struct _ir_copy { ir_reg to; } ir_copy; -static int ir_parallel_copy(ir_ctx *ctx, ir_copy *copies, int count) +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; @@ -3499,11 +3534,16 @@ static int ir_parallel_copy(ir_ctx *ctx, ir_copy *copies, int count) if (to != loc[from_reg]) { type = types[to]; if (IR_IS_TYPE_INT(type)) { - ir_emit_mov(ctx, type, IR_REG_R0, to); // TODO: Temporary register + 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 { - ir_emit_fp_mov(ctx, type, IR_REG_XMM7, to); // TODO: Temporary register + 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; } - loc[to] = 0; IR_REGSET_INCL(ready, to); } } @@ -3513,7 +3553,7 @@ static int ir_parallel_copy(ir_ctx *ctx, ir_copy *copies, int count) return 1; } -static void ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn) +static void ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg tmp_reg) { int j, n; ir_ref arg; @@ -3575,7 +3615,7 @@ static void ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn) } } if (count) { - ir_parallel_copy(ctx, copies, count); + ir_parallel_copy(ctx, copies, count, tmp_reg, IR_REG_FP_LAST); } ir_mem_free(copies); @@ -3625,7 +3665,7 @@ static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn) dasm_State **Dst = &data->dasm_state; ir_reg def_reg; - ir_emit_arguments(ctx, def, insn); + ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]); if (IR_IS_CONST_REF(insn->op2)) { const char *name = ir_get_str(ctx, ctx->ir_base[insn->op2].val.addr); @@ -3688,7 +3728,7 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - ir_emit_arguments(ctx, def, insn); + ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]); ir_emit_epilogue(ctx); diff --git a/tests/debug/call3.irt b/tests/debug/call3.irt new file mode 100644 index 0000000..3c2ac2d --- /dev/null +++ b/tests/debug/call3.irt @@ -0,0 +1,34 @@ +--TEST-- +CALL with parallel argument passing +--ARGS-- +-S +--CODE-- +{ + uintptr_t c_6 = "hello %d!\n"; + l_1 = START(l_4); + int32_t p_1 = PARAM(l_1, "p1", 1); + int32_t p_2 = PARAM(l_1, "p2", 2); + int32_t p_3 = PARAM(l_1, "p3", 3); + int32_t p_4 = PARAM(l_1, "p4", 4); + uintptr_t fp = PARAM(l_1, "fp", 5); + uintptr_t f, l_11 = LOAD(l_1, fp); + int32_t d_2, l_2 = CALL/4(l_11, f, c_6, p_3, p_4, p_2); + int32_t d_3 = ADD(d_2, p_1); + l_4 = RETURN(l_2, d_3); +} +--EXPECT-- +test: + subq $8, %rsp + movq %rbx, (%rsp) + movl %edi, %ebx + movq (%r8), %rax + movl %ecx, %r8d + movl %esi, %ecx + movl %edx, %esi + movl %r8d, %edx + leaq 0x12(%rip), %rdi + callq *%rax + leal (%rax, %rbx), %eax + movq (%rsp), %rbx + addq $8, %rsp + retq