Commit ad8c4178 authored by Michael Beck's avatar Michael Beck
Browse files

Removed the callee/caller saved flag from register specification.

The callee/caller saved information is not constant accross different
ABI's, so don't make it constant. Instead, all BE that still use beabi
provide a callback now.
This allows to implement support for x64_64/Win32 and is a necessary step
for the combined x86 BE.
parent d0c092c7
......@@ -61,47 +61,48 @@ $mode_fp = "mode_E"; # mode used by floatingpoint registers
#
# register types:
# 0 - no special type
# 1 - caller save (register must be saved by the caller of a function)
# 2 - callee save (register must be saved by the called function)
# 4 - ignore (do not assign this register)
# 1 - ignore (do not assign this register)
# 2 - emitter can choose an arbitrary register of this class
# 4 - the register is a virtual one
# 8 - register represents a state
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
%reg_classes = (
gp => [
{ name => "r0", type => 1 },
{ name => "r1", type => 1 },
{ name => "r2", type => 1 },
{ name => "r3", type => 1 },
{ name => "r4", type => 1 },
{ name => "r5", type => 1 },
{ name => "r6", type => 1 },
{ name => "r7", type => 2 },
{ name => "r8", type => 2 },
{ name => "r9", type => 2 },
{ name => "r10", type => 2 },
{ name => "r11", type => 2 },
{ name => "r12", type => 2 },
{ name => "r13", type => 2 },
{ name => "sp", realname => "r14", type => 4 }, # stackpointer
{ name => "bp", realname => "r15", type => 4 }, # basepointer
{ name => "r0" },
{ name => "r1" },
{ name => "r2" },
{ name => "r3" },
{ name => "r4" },
{ name => "r5" },
{ name => "r6" },
{ name => "r7" },
{ name => "r8" },
{ name => "r9" },
{ name => "r10" },
{ name => "r11" },
{ name => "r12" },
{ name => "r13" },
{ name => "sp", realname => "r14", type => 1 }, # stackpointer
{ name => "bp", realname => "r15", type => 1 }, # basepointer
{ mode => $mode_gp }
],
fp => [
{ name => "f0", type => 1 },
{ name => "f1", type => 1 },
{ name => "f2", type => 1 },
{ name => "f3", type => 1 },
{ name => "f4", type => 1 },
{ name => "f5", type => 1 },
{ name => "f6", type => 1 },
{ name => "f7", type => 1 },
{ name => "f8", type => 1 },
{ name => "f9", type => 1 },
{ name => "f10", type => 1 },
{ name => "f11", type => 1 },
{ name => "f12", type => 1 },
{ name => "f13", type => 1 },
{ name => "f14", type => 1 },
{ name => "f15", type => 1 },
{ name => "f0" },
{ name => "f1" },
{ name => "f2" },
{ name => "f3" },
{ name => "f4" },
{ name => "f5" },
{ name => "f6" },
{ name => "f7" },
{ name => "f8" },
{ name => "f9" },
{ name => "f10" },
{ name => "f11" },
{ name => "f12" },
{ name => "f13" },
{ name => "f14" },
{ name => "f15" },
{ mode => $mode_fp }
]
);
......
......@@ -351,6 +351,50 @@ static int TEMPLATE_is_valid_clobber(const char *clobber)
return 0;
}
/**
* Check if the given register is callee or caller save.
*/
static int TEMPLATE_register_saved_by(const arch_register_t *reg, int callee)
{
if (callee) {
/* check for callee saved */
if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp]) {
switch (reg->index) {
case REG_GP_R7:
case REG_GP_R8:
case REG_GP_R9:
case REG_GP_R10:
case REG_GP_R11:
case REG_GP_R12:
case REG_GP_R13:
return 1;
default:
return 0;
}
}
} else {
/* check for caller saved */
if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp]) {
switch (reg->index) {
case REG_GP_R0:
case REG_GP_R1:
case REG_GP_R2:
case REG_GP_R3:
case REG_GP_R4:
case REG_GP_R5:
case REG_GP_R6:
return 1;
default:
return 0;
}
} else if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_fp]) {
/* all FP registers are caller save */
return 1;
}
}
return 0;
}
const arch_isa_if_t TEMPLATE_isa_if = {
TEMPLATE_init,
TEMPLATE_lower_for_target,
......@@ -373,6 +417,7 @@ const arch_isa_if_t TEMPLATE_isa_if = {
TEMPLATE_after_ra,
TEMPLATE_finish_irg,
TEMPLATE_emit_routine,
TEMPLATE_register_saved_by,
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_TEMPLATE)
......
......@@ -55,55 +55,53 @@ $arch = "amd64";
#
# register types:
$normal = 0; # no special type
$caller_save = 1; # caller save (register must be saved by the caller of a function)
$callee_save = 2; # callee save (register must be saved by the called function)
$ignore = 4; # ignore (do not assign this register)
$arbitrary = 8; # emitter can choose an arbitrary register of this class
$virtual = 16; # the register is a virtual one
$state = 32; # register represents a state
$ignore = 1; # ignore (do not assign this register)
$arbitrary = 2; # emitter can choose an arbitrary register of this class
$virtual = 4; # the register is a virtual one
$state = 8; # register represents a state
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
%reg_classes = (
gp => [
{ name => "rax", type => $caller_save },
{ name => "rcx", type => $caller_save },
{ name => "rdx", type => $caller_save },
{ name => "rsi", type => $caller_save },
{ name => "rdi", type => $caller_save },
{ name => "rbx", type => $callee_save },
{ name => "rbp", type => $callee_save },
{ name => "rsp", type => 4 }, # stackpointer?
{ name => "r8", type => $caller_save },
{ name => "r9", type => $caller_save },
{ name => "r10", type => $caller_save },
{ name => "r11", type => $caller_save },
{ name => "r12", type => $callee_save },
{ name => "r13", type => $callee_save },
{ name => "r14", type => $callee_save },
{ name => "r15", type => $callee_save },
{ name => "rax" },
{ name => "rcx" },
{ name => "rdx" },
{ name => "rsi" },
{ name => "rdi" },
{ name => "rbx" },
{ name => "rbp" },
{ name => "rsp", type => $ignore }, # stackpointer?
{ name => "r8" },
{ name => "r9" },
{ name => "r10" },
{ name => "r11" },
{ name => "r12" },
{ name => "r13" },
{ name => "r14" },
{ name => "r15" },
# { name => "gp_NOREG", type => $ignore }, # we need a dummy register for NoReg nodes
{ mode => "mode_Lu" }
],
# fp => [
# { name => "xmm0", type => $caller_save },
# { name => "xmm1", type => $caller_save },
# { name => "xmm2", type => $caller_save },
# { name => "xmm3", type => $caller_save },
# { name => "xmm4", type => $caller_save },
# { name => "xmm5", type => $caller_save },
# { name => "xmm6", type => $caller_save },
# { name => "xmm7", type => $caller_save },
# { name => "xmm8", type => $caller_save },
# { name => "xmm9", type => $caller_save },
# { name => "xmm10", type => $caller_save },
# { name => "xmm11", type => $caller_save },
# { name => "xmm12", type => $caller_save },
# { name => "xmm13", type => $caller_save },
# { name => "xmm14", type => $caller_save },
# { name => "xmm15", type => $caller_save },
# { name => "xmm0" },
# { name => "xmm1" },
# { name => "xmm2" },
# { name => "xmm3" },
# { name => "xmm4" },
# { name => "xmm5" },
# { name => "xmm6" },
# { name => "xmm7" },
# { name => "xmm8" },
# { name => "xmm9" },
# { name => "xmm10" },
# { name => "xmm11" },
# { name => "xmm12" },
# { name => "xmm13" },
# { name => "xmm14" },
# { name => "xmm15" },
# { mode => "mode_D" }
# ]
flags => [
{ name => "eflags", type => 0 },
{ name => "eflags" },
{ mode => "mode_Iu", flags => "manual_ra" }
],
);
......
......@@ -531,6 +531,45 @@ static int amd64_is_valid_clobber(const char *clobber)
return 0;
}
static int amd64_register_saved_by(const arch_register_t *reg, int callee)
{
if (callee) {
/* check for callee saved */
if (reg->reg_class == &amd64_reg_classes[CLASS_amd64_gp]) {
switch (reg->index) {
case REG_GP_RBX:
case REG_GP_RBP:
case REG_GP_R12:
case REG_GP_R13:
case REG_GP_R14:
case REG_GP_R15:
return 1;
default:
return 0;
}
}
} else {
/* check for caller saved */
if (reg->reg_class == &amd64_reg_classes[CLASS_amd64_gp]) {
switch (reg->index) {
case REG_GP_RAX:
case REG_GP_RCX:
case REG_GP_RDX:
case REG_GP_RSI:
case REG_GP_RDI:
case REG_GP_R8:
case REG_GP_R9:
case REG_GP_R10:
case REG_GP_R11:
return 1;
default:
return 0;
}
}
}
return 0;
}
const arch_isa_if_t amd64_isa_if = {
amd64_init,
amd64_lower_for_target,
......@@ -553,6 +592,7 @@ const arch_isa_if_t amd64_isa_if = {
amd64_after_ra,
amd64_finish_irg,
amd64_gen_routine,
amd64_register_saved_by,
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_amd64)
......
......@@ -625,6 +625,7 @@ const arch_isa_if_t arm_isa_if = {
arm_after_ra,
arm_finish_irg,
arm_gen_routine,
NULL, /* register_saved_by */
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
......
......@@ -536,7 +536,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
* checking */
continue;
}
if (destroy_all_regs || (reg->type & arch_register_type_caller_save)) {
if (destroy_all_regs || arch_register_is_caller_save(arch_env, reg)) {
if (!(reg->type & arch_register_type_ignore)) {
ARR_APP1(const arch_register_t*, destroyed_regs, reg);
}
......@@ -1274,7 +1274,7 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
/* Add uses of the callee save registers. */
foreach_pmap(env->regs, ent) {
const arch_register_t *reg = (const arch_register_t*)ent->key;
if (reg->type & (arch_register_type_callee_save | arch_register_type_ignore))
if ((reg->type & arch_register_type_ignore) || arch_register_is_callee_save(arch_env, reg))
pmap_insert(reg_map, ent->key, ent->value);
}
......@@ -1787,7 +1787,7 @@ static void modify_irg(ir_graph *irg)
const arch_register_class_t *cls = &arch_env->register_classes[i];
for (j = 0; j < cls->n_regs; ++j) {
const arch_register_t *reg = &cls->regs[j];
if (reg->type & (arch_register_type_callee_save | arch_register_type_state)) {
if ((reg->type & arch_register_type_state) || arch_register_is_callee_save(arch_env, reg)) {
pmap_insert(env->regs, (void *) reg, NULL);
}
}
......
......@@ -58,24 +58,18 @@ ENUM_BITSET(arch_register_class_flags_t)
typedef enum arch_register_type_t {
arch_register_type_none = 0,
/** The register must be saved by the caller upon a function call. It thus
* can be overwritten in the called function. */
arch_register_type_caller_save = 1U << 0,
/** The register must be saved by the caller upon a function call. It thus
* can be overwritten in the called function. */
arch_register_type_callee_save = 1U << 1,
/** Do not consider this register when allocating. */
arch_register_type_ignore = 1U << 2,
arch_register_type_ignore = 1U << 0,
/** The emitter can choose an arbitrary register. The register fulfills any
* register constraints as long as the register class matches */
arch_register_type_joker = 1U << 3,
arch_register_type_joker = 1U << 1,
/** This is just a virtual register. Virtual registers fulfill any register
* constraints as long as the register class matches. It is a allowed to
* have multiple definitions for the same virtual register at a point */
arch_register_type_virtual = 1U << 4,
arch_register_type_virtual = 1U << 2,
/** The register represents a state that should be handled by bestate
* code */
arch_register_type_state = 1U << 5,
arch_register_type_state = 1U << 3,
} arch_register_type_t;
ENUM_BITSET(arch_register_type_t)
......@@ -588,6 +582,11 @@ struct arch_isa_if_t {
* The code generator must also be de-allocated here.
*/
void (*emit)(ir_graph *irg);
/**
* Checks if the given register is callee/caller saved.
*/
int (*register_saved_by)(const arch_register_t *reg, int callee);
};
#define arch_env_done(env) ((env)->impl->done(env))
......@@ -728,6 +727,30 @@ static inline const arch_register_req_t **arch_get_in_register_reqs(
return info->in_reqs;
}
/**
* Check if the given register is callee save, ie. will be save by the callee.
*/
static inline bool arch_register_is_callee_save(
const arch_env_t *arch_env,
const arch_register_t *reg)
{
if (arch_env->impl->register_saved_by)
return arch_env->impl->register_saved_by(reg, /*callee=*/1);
return false;
}
/**
* Check if the given register is caller save, ie. must be save by the caller.
*/
static inline bool arch_register_is_caller_save(
const arch_env_t *arch_env,
const arch_register_t *reg)
{
if (arch_env->impl->register_saved_by)
return arch_env->impl->register_saved_by(reg, /*callee=*/0);
return false;
}
/**
* Iterate over all values defined by an instruction.
* Only looks at values in a certain register class where the requirements
......
......@@ -2118,6 +2118,46 @@ static const backend_params *ia32_get_libfirm_params(void)
return &p;
}
/**
* Check if the given register is callee or caller save.
*/
static int ia32_register_saved_by(const arch_register_t *reg, int callee)
{
if (callee) {
/* check for callee saved */
if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_gp]) {
switch (reg->index) {
case REG_GP_EBX:
case REG_GP_ESI:
case REG_GP_EDI:
case REG_GP_EBP:
return 1;
default:
return 0;
}
}
} else {
/* check for caller saved */
if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_gp]) {
switch (reg->index) {
case REG_GP_EDX:
case REG_GP_ECX:
case REG_GP_EAX:
return 1;
default:
return 0;
}
} else if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_xmm]) {
/* all XMM registers are caller save */
return reg->index != REG_XMM_NOREG;
} else if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]) {
/* all VFP registers are caller save */
return reg->index != REG_VFP_NOREG;
}
}
return 0;
}
static const lc_opt_enum_int_items_t gas_items[] = {
{ "elf", OBJECT_FILE_FORMAT_ELF },
{ "mingw", OBJECT_FILE_FORMAT_COFF },
......@@ -2175,6 +2215,7 @@ const arch_isa_if_t ia32_isa_if = {
ia32_after_ra, /* after register allocation hook */
ia32_finish, /* called before codegen */
ia32_emit, /* emit && done */
ia32_register_saved_by,
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_ia32)
......
......@@ -6,22 +6,20 @@ $arch = "ia32";
# register types:
$normal = 0; # no special type
$caller_save = 1; # caller save (register must be saved by the caller of a function)
$callee_save = 2; # callee save (register must be saved by the called function)
$ignore = 4; # ignore (do not assign this register)
$arbitrary = 8; # emitter can choose an arbitrary register of this class
$virtual = 16; # the register is a virtual one
$state = 32; # register represents a state
$ignore = 1; # ignore (do not assign this register)
$arbitrary = 2; # emitter can choose an arbitrary register of this class
$virtual = 4; # the register is a virtual one
$state = 8; # register represents a state
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
%reg_classes = (
gp => [
{ name => "edx", type => $caller_save },
{ name => "ecx", type => $caller_save },
{ name => "eax", type => $caller_save },
{ name => "ebx", type => $callee_save },
{ name => "esi", type => $callee_save },
{ name => "edi", type => $callee_save },
{ name => "ebp", type => $callee_save },
{ name => "edx" },
{ name => "ecx" },
{ name => "eax" },
{ name => "ebx" },
{ name => "esi" },
{ name => "edi" },
{ name => "ebp" },
{ name => "esp", type => $ignore },
{ name => "gp_NOREG", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for NoReg nodes
{ mode => "mode_Iu" }
......@@ -38,26 +36,26 @@ $state = 32; # register represents a state
{ mode => "mode_E", flags => "manual_ra" }
],
xmm => [
{ name => "xmm0", type => $caller_save },
{ name => "xmm1", type => $caller_save },
{ name => "xmm2", type => $caller_save },
{ name => "xmm3", type => $caller_save },
{ name => "xmm4", type => $caller_save },
{ name => "xmm5", type => $caller_save },
{ name => "xmm6", type => $caller_save },
{ name => "xmm7", type => $caller_save },
{ name => "xmm0" },
{ name => "xmm1" },
{ name => "xmm2" },
{ name => "xmm3" },
{ name => "xmm4" },
{ name => "xmm5" },
{ name => "xmm6" },
{ name => "xmm7" },
{ name => "xmm_NOREG", type => $ignore | $virtual }, # we need a dummy register for NoReg nodes
{ mode => "mode_E" }
],
vfp => [
{ name => "vf0", type => $caller_save },
{ name => "vf1", type => $caller_save },
{ name => "vf2", type => $caller_save },
{ name => "vf3", type => $caller_save },
{ name => "vf4", type => $caller_save },
{ name => "vf5", type => $caller_save },
{ name => "vf6", type => $caller_save },
{ name => "vf7", type => $caller_save },
{ name => "vf0" },
{ name => "vf1" },
{ name => "vf2" },
{ name => "vf3" },
{ name => "vf4" },
{ name => "vf5" },
{ name => "vf6" },
{ name => "vf7" },
{ name => "vfp_NOREG", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for NoReg nodes
{ mode => "mode_E" }
],
......
......@@ -61,26 +61,18 @@ sub translate_reg_type {
my @types;
if ($t & 1) {
push(@types, "arch_register_type_caller_save");
}
if ($t & 2) {
push(@types, "arch_register_type_callee_save");
}
if ($t & 4) {
push(@types, "arch_register_type_ignore");
}
if ($t & 8) {
if ($t & 2) {
push(@types, "arch_register_type_joker");
}
if ($t & 16) {
if ($t & 4) {
push(@types, "arch_register_type_virtual");
}
if ($t & 32) {
if ($t & 8) {
push(@types, "arch_register_type_state");
}
......
......@@ -655,6 +655,7 @@ const arch_isa_if_t sparc_isa_if = {
sparc_after_ra,
sparc_finish,
sparc_emit_routine,
NULL, /* register_saved_by */
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_sparc);
......
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