diff --git a/ir_x86.dasc b/ir_x86.dasc index 503fae4..579c22d 100644 --- a/ir_x86.dasc +++ b/ir_x86.dasc @@ -3556,6 +3556,42 @@ static int ir_parallel_copy(ir_ctx *ctx, ir_copy *copies, int count, ir_reg tmp_ return 1; } +static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn) +{ + int j, n; + ir_type type; + int int_param = 0; + int fp_param = 0; + int int_reg_params_count = IR_REG_INT_ARGS; + int fp_reg_params_count = IR_REG_FP_ARGS; + int32_t used_stack = 0; + + 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) { + used_stack += sizeof(void*); + } + int_param++; + } else if (IR_IS_TYPE_FP(type)) { + if (fp_param >= fp_reg_params_count) { + used_stack += sizeof(void*); + } + fp_param++; + } else { + IR_ASSERT(0); + } + } + + if (used_stack % 16 != 0) { + /* Stack must be 16 byte aligned */ + used_stack += 8; + } + + return used_stack; +} + static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg tmp_reg) { ir_backend_data *data = ctx->data; @@ -3572,11 +3608,21 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg int fp_reg_params_count = IR_REG_FP_ARGS; const int8_t *int_reg_params = _ir_int_reg_params; const int8_t *fp_reg_params = _ir_fp_reg_params; - int32_t used_stack = 0; + int32_t used_stack, stack_offset = 0; ir_copy *copies; bool has_mem_const_args = 0; ir_reg tmp_fp_reg = IR_REG_FP_LAST; /* Temporary register for FP loads and swap */ + if (0) { + // TODO: support for preallocated stack + used_stack = 0; + } else { + used_stack = ir_call_used_stack(ctx, insn); + if (used_stack) { + | lea rsp, [rsp-used_stack] + } + } + n = ir_input_edges_count(ctx, insn); copies = ir_mem_malloc((n - 2) * sizeof(ir_copy)); for (j = 3; j <= n; j++) { @@ -3620,43 +3666,42 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } } else { /* Pass argument through stack */ - if (0) { - // TODO: support for preallocated stack - } else { - used_stack += sizeof(void*); - if (IR_IS_TYPE_INT(type)) { - if (IR_IS_CONST_REF(arg)) { - ir_val *val = &ctx->ir_base[arg].val; - if (IR_IS_SIGNED_32BIT(val->i64)) { - | push val->i32 + if (IR_IS_TYPE_INT(type)) { + if (IR_IS_CONST_REF(arg)) { + ir_val *val = &ctx->ir_base[arg].val; + if (IR_IS_SIGNED_32BIT(val->i64)) { + if (ir_type_size[type] <= 4) { + | mov dword [rsp+stack_offset], val->i32 } else { - IR_ASSERT(tmp_reg != IR_REG_NONE); - | mov64 Ra(tmp_reg), val->i64 - | push Ra(tmp_reg) + | mov qword [rsp+stack_offset], val->i32 } } else { - IR_ASSERT(src_reg != IR_REG_NONE); - if (src_reg & IR_REG_SPILL_LOAD) { - src_reg &= ~IR_REG_SPILL_LOAD; - ir_emit_load(ctx, type, src_reg, arg); - } - | push Ra(src_reg) + IR_ASSERT(tmp_reg != IR_REG_NONE); + | mov64 Ra(tmp_reg), val->i64 + | mov [rsp+stack_offset], Ra(tmp_reg) } } else { - if (IR_IS_CONST_REF(arg)) { - ir_emit_load(ctx, type, tmp_fp_reg, arg); - src_reg = tmp_fp_reg; - } else { - IR_ASSERT(src_reg != IR_REG_NONE); - if (src_reg & IR_REG_SPILL_LOAD) { - src_reg &= ~IR_REG_SPILL_LOAD; - ir_emit_load(ctx, type, src_reg, arg); - } + IR_ASSERT(src_reg != IR_REG_NONE); + if (src_reg & IR_REG_SPILL_LOAD) { + src_reg &= ~IR_REG_SPILL_LOAD; + ir_emit_load(ctx, type, src_reg, arg); } - | sub rsp, sizeof(void*) - | ASM_FP_MEM_REG_OP movss, movsd, vmovss, vmovsd, type, [rsp], src_reg + | ASM_MEM_REG_OP, mov, type, [rsp+stack_offset], src_reg } + } else { + if (IR_IS_CONST_REF(arg)) { + ir_emit_load(ctx, type, tmp_fp_reg, arg); + src_reg = tmp_fp_reg; + } else { + IR_ASSERT(src_reg != IR_REG_NONE); + if (src_reg & IR_REG_SPILL_LOAD) { + src_reg &= ~IR_REG_SPILL_LOAD; + ir_emit_load(ctx, type, src_reg, arg); + } + } + | ASM_FP_MEM_REG_OP movss, movsd, vmovss, vmovsd, type, [rsp+stack_offset], src_reg } + stack_offset += sizeof(void*); } } if (count) { @@ -3691,6 +3736,9 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } if (dst_reg != IR_REG_NONE && (IR_IS_CONST_REF(arg) || src_reg == IR_REG_NONE)) { if (IR_IS_TYPE_INT(type)) { + if (IR_IS_CONST_REF(arg) && ir_type_size[type] == 1) { + type = IR_ADDR; + } ir_emit_load(ctx, type, dst_reg, arg); } else { ir_emit_load(ctx, type, dst_reg, arg); @@ -3735,8 +3783,7 @@ static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn) } if (used_stack) { - // TODO: support for preallocated stack - | add rsp, used_stack + | lea rsp, [rsp+used_stack] } if (insn->type != IR_VOID) { diff --git a/tests/debug/args_001.irt b/tests/debug/args_001.irt new file mode 100644 index 0000000..165b953 --- /dev/null +++ b/tests/debug/args_001.irt @@ -0,0 +1,47 @@ +--TEST-- +001: Argument Passing +--ARGS-- +-S --run +--CODE-- +{ + int8_t c_1 = 1; + int16_t c_2 = 2; + int32_t c_3 = 3; + int64_t c_4 = 4; + int64_t c_5 = 0x100000000; + uint8_t c_6 = 6; + uint16_t c_7 = 7; + uint32_t c_8 = 8; + int64_t c_9 = 9; + int64_t c_10 = 0x100000000; + uintptr_t f = func(printf); + uintptr_t fmt = "%d %d %d %lld 0x%llx %d %d %d %lld 0x%llx\n"; + l_1 = START(l_3); + int32_t d_2, l_2 = CALL/11(l_1, f, fmt, c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10); + l_3 = RETURN(l_2, d_2); +} +--EXPECT-- +test: + subq $8, %rsp + leaq -0x30(%rsp), %rsp + movl $6, (%rsp) + movl $7, 8(%rsp) + movl $8, 0x10(%rsp) + movq $9, 0x18(%rsp) + movabsq $0x100000000, %rax + movq %rax, 0x20(%rsp) + leaq 0x39(%rip), %rdi + movq $1, %rsi + movw $2, %dx + movl $3, %ecx + movq $4, %r8 + movabsq $0x100000000, %r9 + movabsq $_IO_printf, %rax + callq *%rax + leaq 0x30(%rsp), %rsp + addq $8, %rsp + retq + +1 2 3 4 0x100000000 6 7 8 9 0x100000000 + +exit code = 40 diff --git a/tests/debug/args_002.irt b/tests/debug/args_002.irt new file mode 100644 index 0000000..279749f --- /dev/null +++ b/tests/debug/args_002.irt @@ -0,0 +1,48 @@ +--TEST-- +002: Argument Passing +--ARGS-- +-S --run +--CODE-- +{ + double c_1 = 0.1; + double c_2 = 0.2; + double c_3 = 0.3; + double c_4 = 0.4; + double c_5 = 0.5; + double c_6 = 0.6; + double c_7 = 0.7; + double c_8 = 0.8; + double c_9 = 0.9; + double c_10 = 0.0; + uintptr_t f = func(printf); + uintptr_t fmt = "%g %g %g %g %g %g %g %g %g %g\n"; + l_1 = START(l_3); + int32_t d_2, l_2 = CALL/11(l_1, f, fmt, c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10); + l_3 = RETURN(l_2, d_2); +} +--EXPECT-- +test: + subq $8, %rsp + leaq -0x10(%rsp), %rsp + movsd 0xb6(%rip), %xmm15 + movsd %xmm15, (%rsp) + xorpd %xmm15, %xmm15 + movsd %xmm15, 8(%rsp) + leaq 0xa5(%rip), %rdi + movsd 0x55(%rip), %xmm0 + movsd 0x55(%rip), %xmm1 + movsd 0x55(%rip), %xmm2 + movsd 0x55(%rip), %xmm3 + movsd 0x55(%rip), %xmm4 + movsd 0x55(%rip), %xmm5 + movsd 0x55(%rip), %xmm6 + movsd 0x55(%rip), %xmm7 + movabsq $_IO_printf, %rax + callq *%rax + leaq 0x10(%rsp), %rsp + addq $8, %rsp + retq + +0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0 + +exit code = 38