Commit 074cb7c6 authored by Matthias Braun's avatar Matthias Braun
Browse files

amd64: First attempt at x64 calling convention

parent ff9bb612
......@@ -7,6 +7,10 @@
* @file
* @brief calling convention helpers
* @author Matthias Braun
*
* See also:
* - http://www.x86-64.org/documentation/abi.pdf
* - MSDN - "x64 Software Conventions"
*/
#include "be_t.h"
#include "beirg.h"
......@@ -21,19 +25,15 @@
#include "bearch_amd64_t.h"
#include "../ia32/x86_cconv.h"
bool amd64_use_x64_abi;
static const unsigned ignore_regs[] = {
REG_RSP,
REG_EFLAGS,
};
static const arch_register_t* const param_regs[] = {
&amd64_registers[REG_RDI],
&amd64_registers[REG_RSI],
&amd64_registers[REG_RDX],
&amd64_registers[REG_RCX],
&amd64_registers[REG_R8],
&amd64_registers[REG_R9],
};
static const arch_register_t *const *param_regs;
static unsigned n_param_regs;
static const arch_register_t* const float_param_regs[] = {
&amd64_registers[REG_XMM0],
......@@ -45,6 +45,7 @@ static const arch_register_t* const float_param_regs[] = {
&amd64_registers[REG_XMM6],
&amd64_registers[REG_XMM7],
};
static unsigned n_float_param_regs;
static const arch_register_t* const result_regs[] = {
&amd64_registers[REG_RAX],
......@@ -53,37 +54,10 @@ static const arch_register_t* const result_regs[] = {
static const arch_register_t* const float_result_regs[] = {
&amd64_registers[REG_XMM0],
&amd64_registers[REG_XMM1],
};
static const unsigned caller_saves[] = {
REG_RAX,
REG_RCX,
REG_RDX,
REG_RSI,
REG_RDI,
REG_R8,
REG_R9,
REG_R10,
REG_R11,
REG_XMM0,
REG_XMM1,
REG_XMM2,
REG_XMM3,
REG_XMM4,
REG_XMM5,
REG_XMM6,
REG_XMM7,
};
static unsigned default_caller_saves[BITSET_SIZE_ELEMS(N_AMD64_REGISTERS)];
static const unsigned callee_saves[] = {
REG_RBX,
REG_RBP,
REG_R12,
REG_R13,
REG_R14,
REG_R15,
};
static unsigned default_callee_saves[BITSET_SIZE_ELEMS(N_AMD64_REGISTERS)];
static void check_omit_fp(ir_node *node, void *env)
......@@ -122,10 +96,9 @@ x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type,
size_t float_param_regnum = 0;
reg_or_stackslot_t *params = XMALLOCNZ(reg_or_stackslot_t,
n_params);
size_t n_param_regs = ARRAY_SIZE(param_regs);
size_t n_float_param_regs = ARRAY_SIZE(float_param_regs);
unsigned stack_offset = 0;
/* x64 always reserves space to spill the first 4 arguments to have it
* easy in case of variadic functions. */
unsigned stack_offset = amd64_use_x64_abi ? 32 : 0;
for (size_t i = 0; i < n_params; ++i) {
ir_type *param_type = get_method_param_type(function_type,i);
if (is_compound_type(param_type))
......@@ -140,11 +113,15 @@ x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type,
param->reg = reg;
param->reg_offset = float_param_regnum + param_regnum;
++float_param_regnum;
if (amd64_use_x64_abi)
++param_regnum;
} else if (!mode_is_float(mode) && param_regnum < n_param_regs) {
const arch_register_t *reg = param_regs[param_regnum];
param->reg = reg;
param->reg_offset = float_param_regnum + param_regnum;
++param_regnum;
if (amd64_use_x64_abi)
++float_param_regnum;
} else {
param->type = param_type;
param->offset = stack_offset;
......@@ -156,7 +133,8 @@ x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type,
}
unsigned n_param_regs_used = param_regnum + float_param_regnum;
unsigned n_param_regs_used
= amd64_use_x64_abi ? param_regnum : param_regnum + float_param_regnum;
/* determine how results are passed */
size_t n_results = get_method_n_ress(function_type);
......@@ -189,16 +167,16 @@ x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type,
++n_reg_results;
}
x86_cconv_t *cconv = XMALLOCZ(x86_cconv_t);
cconv->parameters = params;
cconv->param_stack_size = stack_offset;
cconv->n_param_regs = n_param_regs_used;
cconv->n_xmm_regs = float_param_regnum;
cconv->results = results;
cconv->omit_fp = omit_fp;
cconv->caller_saves = caller_saves;
cconv->callee_saves = callee_saves;
cconv->n_reg_results = n_reg_results;
x86_cconv_t *cconv = XMALLOCZ(x86_cconv_t);
cconv->parameters = params;
cconv->callframe_size = stack_offset;
cconv->n_param_regs = n_param_regs_used;
cconv->n_xmm_regs = float_param_regnum;
cconv->results = results;
cconv->omit_fp = omit_fp;
cconv->caller_saves = caller_saves;
cconv->callee_saves = callee_saves;
cconv->n_reg_results = n_reg_results;
if (irg != NULL) {
be_irg_t *birg = be_birg_from_irg(irg);
......@@ -219,10 +197,65 @@ x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type,
void amd64_cconv_init(void)
{
for (size_t i = 0; i < ARRAY_SIZE(caller_saves); ++i) {
rbitset_set(default_caller_saves, caller_saves[i]);
static const unsigned common_caller_saves[] = {
REG_RAX,
REG_RCX,
REG_RDX,
REG_R8,
REG_R9,
REG_R10,
REG_R11,
REG_XMM0,
REG_XMM1,
REG_XMM2,
REG_XMM3,
REG_XMM4,
REG_XMM5,
REG_XMM6,
REG_XMM7,
REG_XMM8,
REG_XMM9,
REG_XMM10,
REG_XMM11,
REG_XMM12,
REG_XMM13,
REG_XMM14,
REG_XMM15,
};
for (size_t i = 0; i < ARRAY_SIZE(common_caller_saves); ++i) {
rbitset_set(default_caller_saves, common_caller_saves[i]);
}
if (!amd64_use_x64_abi) {
rbitset_set(default_caller_saves, REG_RSI);
rbitset_set(default_caller_saves, REG_RDI);
}
static const unsigned common_callee_saves[] = {
REG_RBX,
REG_RBP,
REG_R12,
REG_R13,
REG_R14,
REG_R15,
};
for (size_t i = 0; i < ARRAY_SIZE(common_callee_saves); ++i) {
rbitset_set(default_callee_saves, common_callee_saves[i]);
}
for (size_t i = 0; i < ARRAY_SIZE(callee_saves); ++i) {
rbitset_set(default_callee_saves, callee_saves[i]);
if (amd64_use_x64_abi) {
rbitset_set(default_callee_saves, REG_RSI);
rbitset_set(default_callee_saves, REG_RDI);
}
static const arch_register_t* const param_regs_list[] = {
&amd64_registers[REG_RDI],
&amd64_registers[REG_RSI],
&amd64_registers[REG_RDX],
&amd64_registers[REG_RCX],
&amd64_registers[REG_R8],
&amd64_registers[REG_R9],
};
param_regs = amd64_use_x64_abi ? &param_regs_list[2] : param_regs_list;
n_param_regs = ARRAY_SIZE(param_regs) - (amd64_use_x64_abi ? 2 : 0);
n_float_param_regs = amd64_use_x64_abi ? 4 : ARRAY_SIZE(float_param_regs);
}
......@@ -1631,7 +1631,7 @@ static ir_node *gen_Call(ir_node *node)
* aligned even if we don't push arguments on it */
const arch_register_t *sp_reg = &amd64_registers[REG_RSP];
ir_node *incsp = amd64_new_IncSP(new_block, new_frame,
cconv->param_stack_size,
cconv->callframe_size,
AMD64_PO2_STACK_ALIGNMENT);
/* match callee */
......@@ -1817,7 +1817,7 @@ static ir_node *gen_Call(ir_node *node)
/* IncSP to destroy the call stackframe */
ir_node *const call_stack = new_r_Proj(call, mode_gp, pn_amd64_call_stack);
incsp = amd64_new_IncSP(new_block, call_stack, -cconv->param_stack_size, 0);
incsp = amd64_new_IncSP(new_block, call_stack, -cconv->callframe_size, 0);
/* if we are the last IncSP producer in a block then we have to keep
* the stack value.
* Note: This here keeps all producers which is more than necessary */
......
......@@ -24,6 +24,7 @@
#include "irgmod.h"
#include "irgwalk.h"
#include "iropt_t.h"
#include "irtools.h"
#include "lower_alloc.h"
#include "lower_builtins.h"
#include "lower_calls.h"
......@@ -801,6 +802,15 @@ void be_init_arch_amd64(void)
be_register_isa_if("amd64", &amd64_isa_if);
FIRM_DBG_REGISTER(dbg, "firm.be.amd64.cg");
static const lc_opt_table_entry_t options[] = {
LC_OPT_ENT_BOOL("x64abi", "Use x64 ABI (otherwise system V)",
&amd64_use_x64_abi),
LC_OPT_LAST
};
lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
lc_opt_entry_t *x86_64_grp = lc_opt_get_grp(be_grp, "x86_64");
lc_opt_add_table(x86_64_grp, options);
amd64_init_finish();
amd64_init_transform();
}
......@@ -19,6 +19,8 @@ extern ir_mode *amd64_mode_E;
extern ir_type *amd64_type_E;
extern ir_mode *amd64_mode_xmm;
extern bool amd64_use_x64_abi;
#define AMD64_REGISTER_SIZE 8
/** power of two stack alignment on calls */
#define AMD64_PO2_STACK_ALIGNMENT 4
......
......@@ -210,18 +210,18 @@ align_stack:;
calling_convention cc = get_method_calling_convention(function_type);
x86_cconv_t *cconv = XMALLOCZ(x86_cconv_t);
cconv->sp_delta = (cc & cc_compound_ret) && !(cc & cc_reg_param)
? IA32_REGISTER_SIZE : 0;
cconv->parameters = params;
cconv->param_stack_size = stack_offset;
cconv->n_param_regs = n_param_regs_used;
cconv->n_xmm_regs = float_param_regnum;
cconv->results = results;
cconv->omit_fp = omit_fp;
cconv->caller_saves = caller_saves;
cconv->callee_saves = callee_saves;
cconv->n_reg_results = n_reg_results;
x86_cconv_t *cconv = XMALLOCZ(x86_cconv_t);
cconv->sp_delta = (cc & cc_compound_ret) && !(cc & cc_reg_param)
? IA32_REGISTER_SIZE : 0;
cconv->parameters = params;
cconv->callframe_size = stack_offset;
cconv->n_param_regs = n_param_regs_used;
cconv->n_xmm_regs = float_param_regnum;
cconv->results = results;
cconv->omit_fp = omit_fp;
cconv->caller_saves = caller_saves;
cconv->callee_saves = callee_saves;
cconv->n_reg_results = n_reg_results;
if (irg != NULL) {
be_irg_t *birg = be_birg_from_irg(irg);
......
......@@ -4932,7 +4932,7 @@ static ir_node *gen_Call(ir_node *node)
ir_node *const block = be_transform_node(old_block);
ir_node *const new_frame = get_stack_pointer_for(node);
unsigned const po2_stack_alignment = ia32_cg_config.po2_stack_alignment;
unsigned const callframe_size = cconv->param_stack_size;
unsigned const callframe_size = cconv->callframe_size;
ir_node *const callframe =
callframe_size == 0 && po2_stack_alignment == 0 ? new_frame:
ia32_new_IncSP(block, new_frame, callframe_size, ia32_cg_config.po2_stack_alignment);
......@@ -5833,9 +5833,9 @@ static void ia32_create_stacklayout(ir_graph *irg, const x86_cconv_t *cconv)
set_entity_offset(param->entity, param->offset);
}
if (va_start_entity != NULL) {
set_entity_offset(va_start_entity, cconv->param_stack_size);
set_entity_offset(va_start_entity, cconv->callframe_size);
}
set_type_size_bytes(arg_type, cconv->param_stack_size);
set_type_size_bytes(arg_type, cconv->callframe_size);
memset(layout, 0, sizeof(*layout));
layout->frame_type = frame_type;
......
......@@ -34,7 +34,7 @@ typedef struct x86_cconv_t
save/restore) */
unsigned sp_delta;
reg_or_stackslot_t *parameters; /**< parameter info. */
unsigned param_stack_size; /**< stack size for parameters */
unsigned callframe_size; /**< stack size for parameters */
unsigned n_param_regs; /**< number of values passed in a
register (gp + xmm) */
unsigned n_xmm_regs; /**< number of xmm registers used */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment