Removed the callee/caller saved flag from register specification.
authorMichael Beck <mm.beck@gmx.net>
Wed, 8 Jun 2011 17:39:39 +0000 (19:39 +0200)
committerMichael Beck <mm.beck@gmx.net>
Wed, 8 Jun 2011 17:41:34 +0000 (19:41 +0200)
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.

ir/be/TEMPLATE/TEMPLATE_spec.pl
ir/be/TEMPLATE/bearch_TEMPLATE.c
ir/be/amd64/amd64_spec.pl
ir/be/amd64/bearch_amd64.c
ir/be/arm/bearch_arm.c
ir/be/beabi.c
ir/be/bearch.h
ir/be/ia32/bearch_ia32.c
ir/be/ia32/ia32_spec.pl
ir/be/scripts/generate_regalloc_if.pl
ir/be/sparc/bearch_sparc.c

index 678c10c..63ed205 100644 (file)
@@ -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 }
        ]
 );
index 527a8a3..afa533f 100644 (file)
@@ -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)
index 8091083..6a90fed 100644 (file)
@@ -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" }
        ],
 );
index 4972ded..71b68fb 100644 (file)
@@ -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)
index acdf135..dd7f71f 100644 (file)
@@ -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)
index 5ec10b4..97b7cec 100644 (file)
@@ -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);
                        }
                }
index 6a68866..a46ff53 100644 (file)
@@ -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
index ad87374..036f775 100644 (file)
@@ -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)
index 667cf9e..ae6b2b9 100644 (file)
@@ -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" }
        ],
index c754c58..284ca6b 100755 (executable)
@@ -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");
                }
 
index ca32527..42b2da0 100644 (file)
@@ -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);