OSDN Git Service

* config/m32c/m32c.h (LIBGCC2_UNITS_PER_WORD): Define if not
[pf3gnuchains/gcc-fork.git] / gcc / config / m32c / m32c.c
index 5b05950..5021831 100644 (file)
@@ -1,5 +1,5 @@
 /* Target Code for R8C/M16C/M32C
-   Copyright (C) 2005, 2006, 2007
+   Copyright (C) 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by Red Hat.
 
@@ -7,7 +7,7 @@
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 2, or (at your
+   by the Free Software Foundation; either version 3, or (at your
    option) any later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -16,9 +16,8 @@
    License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -48,7 +47,7 @@
 #include "target-def.h"
 #include "tm_p.h"
 #include "langhooks.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "df.h"
 
 /* Prototypes */
@@ -65,13 +64,13 @@ static tree interrupt_handler (tree *, tree, tree, int, bool *);
 static tree function_vector_handler (tree *, tree, tree, int, bool *);
 static int interrupt_p (tree node);
 static bool m32c_asm_integer (rtx, unsigned int, int);
-static int m32c_comp_type_attributes (tree, tree);
+static int m32c_comp_type_attributes (const_tree, const_tree);
 static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *);
 static struct machine_function *m32c_init_machine_status (void);
 static void m32c_insert_attributes (tree, tree *);
 static bool m32c_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
-                                   tree, bool);
-static bool m32c_promote_prototypes (tree);
+                                   const_tree, bool);
+static bool m32c_promote_prototypes (const_tree);
 static int m32c_pushm_popm (Push_Pop_Type);
 static bool m32c_strict_argument_naming (CUMULATIVE_ARGS *);
 static rtx m32c_struct_value_rtx (tree, int);
@@ -341,36 +340,36 @@ classes_intersect (int class1, int class2)
 /* Used by m32c_register_move_cost to determine if a move is
    impossibly expensive.  */
 static int
-class_can_hold_mode (int class, enum machine_mode mode)
+class_can_hold_mode (int rclass, enum machine_mode mode)
 {
   /* Cache the results:  0=untested  1=no  2=yes */
   static char results[LIM_REG_CLASSES][MAX_MACHINE_MODE];
-  if (results[class][mode] == 0)
+  if (results[rclass][mode] == 0)
     {
       int r, n, i;
-      results[class][mode] = 1;
+      results[rclass][mode] = 1;
       for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-       if (class_contents[class][0] & (1 << r)
+       if (class_contents[rclass][0] & (1 << r)
            && HARD_REGNO_MODE_OK (r, mode))
          {
            int ok = 1;
            n = HARD_REGNO_NREGS (r, mode);
            for (i = 1; i < n; i++)
-             if (!(class_contents[class][0] & (1 << (r + i))))
+             if (!(class_contents[rclass][0] & (1 << (r + i))))
                ok = 0;
            if (ok)
              {
-               results[class][mode] = 2;
+               results[rclass][mode] = 2;
                break;
              }
          }
     }
 #if DEBUG0
   fprintf (stderr, "class %s can hold %s? %s\n",
-          class_names[class], mode_name[mode],
-          (results[class][mode] == 2) ? "yes" : "no");
+          class_names[rclass], mode_name[mode],
+          (results[rclass][mode] == 2) ? "yes" : "no");
 #endif
-  return results[class][mode] == 2;
+  return results[rclass][mode] == 2;
 }
 
 /* Run-time Target Specification.  */
@@ -446,7 +445,7 @@ m32c_init_expanders (void)
 #undef TARGET_PROMOTE_FUNCTION_RETURN
 #define TARGET_PROMOTE_FUNCTION_RETURN m32c_promote_function_return
 bool
-m32c_promote_function_return (tree fntype ATTRIBUTE_UNUSED)
+m32c_promote_function_return (const_tree fntype ATTRIBUTE_UNUSED)
 {
   return false;
 }
@@ -524,8 +523,8 @@ m32c_conditional_register_usage (void)
 /* Implements HARD_REGNO_NREGS.  This is complicated by the fact that
    different registers are different sizes from each other, *and* may
    be different sizes in different chip families.  */
-int
-m32c_hard_regno_nregs (int regno, enum machine_mode mode)
+static int
+m32c_hard_regno_nregs_1 (int regno, enum machine_mode mode)
 {
   if (regno == FLG_REGNO && mode == CCmode)
     return 1;
@@ -550,12 +549,19 @@ m32c_hard_regno_nregs (int regno, enum machine_mode mode)
   return 0;
 }
 
+int
+m32c_hard_regno_nregs (int regno, enum machine_mode mode)
+{
+  int rv = m32c_hard_regno_nregs_1 (regno, mode);
+  return rv ? rv : 1;
+}
+
 /* Implements HARD_REGNO_MODE_OK.  The above function does the work
    already; just test its return value.  */
 int
 m32c_hard_regno_ok (int regno, enum machine_mode mode)
 {
-  return m32c_hard_regno_nregs (regno, mode) != 0;
+  return m32c_hard_regno_nregs_1 (regno, mode) != 0;
 }
 
 /* Implements MODES_TIEABLE_P.  In general, modes aren't tieable since
@@ -943,6 +949,11 @@ m32c_const_ok_for_constraint_p (HOST_WIDE_INT value,
       int b = exact_log2 ((value ^ 0xff) & 0xff);
       return (b >= 0 && b <= 7);
     }
+  if (memcmp (str, "ImB", 3) == 0)
+    {
+      int b = exact_log2 ((value ^ 0xffff) & 0xffff);
+      return (b >= 0 && b <= 7);
+    }
   if (memcmp (str, "Ilw", 3) == 0)
     {
       int b = exact_log2 (value);
@@ -1093,7 +1104,8 @@ m32c_return_addr_rtx (int count)
 
   if (TARGET_A24)
     {
-      mode = SImode;
+      /* It's four bytes */
+      mode = PSImode;
       offset = 4;
     }
   else
@@ -1128,7 +1140,10 @@ m32c_eh_return_data_regno (int n)
     case 0:
       return A0_REGNO;
     case 1:
-      return A1_REGNO;
+      if (TARGET_A16)
+       return R3_REGNO;
+      else
+       return R1_REGNO;
     default:
       return INVALID_REGNUM;
     }
@@ -1242,7 +1257,7 @@ need_to_save (int regno)
 {
   if (fixed_regs[regno])
     return 0;
-  if (cfun->calls_eh_return)
+  if (crtl->calls_eh_return)
     return 1;
   if (regno == FP_REGNO)
     return 0;
@@ -1272,11 +1287,11 @@ m32c_pushm_popm (Push_Pop_Type ppt)
   int n_dwarfs = 0;
   int nosave_mask = 0;
 
-  if (cfun->return_rtx
-      && GET_CODE (cfun->return_rtx) == PARALLEL
-      && !(cfun->calls_eh_return || cfun->machine->is_interrupt))
+  if (crtl->return_rtx
+      && GET_CODE (crtl->return_rtx) == PARALLEL
+      && !(crtl->calls_eh_return || cfun->machine->is_interrupt))
     {
-      rtx exp = XVECEXP (cfun->return_rtx, 0, 0);
+      rtx exp = XVECEXP (crtl->return_rtx, 0, 0);
       rtx rv = XEXP (exp, 0);
       int rv_bytes = GET_MODE_SIZE (GET_MODE (rv));
 
@@ -1428,7 +1443,7 @@ m32c_initial_elimination_offset (int from, int to)
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES m32c_promote_prototypes
 static bool
-m32c_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
+m32c_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
 {
   return 0;
 }
@@ -1515,7 +1530,7 @@ m32c_function_arg (CUMULATIVE_ARGS * ca,
 static bool
 m32c_pass_by_reference (CUMULATIVE_ARGS * ca ATTRIBUTE_UNUSED,
                        enum machine_mode mode ATTRIBUTE_UNUSED,
-                       tree type ATTRIBUTE_UNUSED,
+                       const_tree type ATTRIBUTE_UNUSED,
                        bool named ATTRIBUTE_UNUSED)
 {
   return 0;
@@ -1640,10 +1655,10 @@ m32c_libcall_value (enum machine_mode mode)
 /* Implements FUNCTION_VALUE.  Functions and libcalls have the same
    conventions.  */
 rtx
-m32c_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
+m32c_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
 {
   /* return reg or parallel */
-  enum machine_mode mode = TYPE_MODE (valtype);
+  const enum machine_mode mode = TYPE_MODE (valtype);
   return m32c_libcall_value (mode);
 }
 
@@ -2109,7 +2124,8 @@ m32c_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS m32c_rtx_costs
 static bool
-m32c_rtx_costs (rtx x, int code, int outer_code, int *total)
+m32c_rtx_costs (rtx x, int code, int outer_code, int *total,
+               bool speed ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
@@ -2188,18 +2204,38 @@ m32c_rtx_costs (rtx x, int code, int outer_code, int *total)
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST m32c_address_cost
 static int
-m32c_address_cost (rtx addr)
+m32c_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
 {
+  int i;
   /*  fprintf(stderr, "\naddress_cost\n");
       debug_rtx(addr);*/
   switch (GET_CODE (addr))
     {
     case CONST_INT:
-      return COSTS_N_INSNS(1);
+      i = INTVAL (addr);
+      if (i == 0)
+       return COSTS_N_INSNS(1);
+      if (0 < i && i <= 255)
+       return COSTS_N_INSNS(2);
+      if (0 < i && i <= 65535)
+       return COSTS_N_INSNS(3);
+      return COSTS_N_INSNS(4);
     case SYMBOL_REF:
-      return COSTS_N_INSNS(3);
+      return COSTS_N_INSNS(4);
     case REG:
-      return COSTS_N_INSNS(2);
+      return COSTS_N_INSNS(1);
+    case PLUS:
+      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
+       {
+         i = INTVAL (XEXP (addr, 1));
+         if (i == 0)
+           return COSTS_N_INSNS(1);
+         if (0 < i && i <= 255)
+           return COSTS_N_INSNS(2);
+         if (0 < i && i <= 65535)
+           return COSTS_N_INSNS(3);
+       }
+      return COSTS_N_INSNS(4);
     default:
       return 0;
     }
@@ -2665,8 +2701,13 @@ m32c_print_operand_punct_valid_p (int c)
 void
 m32c_print_operand_address (FILE * stream, rtx address)
 {
-  gcc_assert (GET_CODE (address) == MEM);
-  m32c_print_operand (stream, XEXP (address, 0), 0);
+  if (GET_CODE (address) == MEM)
+    address = XEXP (address, 0);
+  else
+    /* cf: gcc.dg/asm-4.c.  */
+    gcc_assert (GET_CODE (address) == REG);
+
+  m32c_print_operand (stream, address, 0);
 }
 
 /* Implements ASM_OUTPUT_REG_PUSH.  Control registers are pushed
@@ -2830,8 +2871,8 @@ static const struct attribute_spec m32c_attribute_table[] = {
 #undef TARGET_COMP_TYPE_ATTRIBUTES
 #define TARGET_COMP_TYPE_ATTRIBUTES m32c_comp_type_attributes
 static int
-m32c_comp_type_attributes (tree type1 ATTRIBUTE_UNUSED,
-                          tree type2 ATTRIBUTE_UNUSED)
+m32c_comp_type_attributes (const_tree type1 ATTRIBUTE_UNUSED,
+                          const_tree type2 ATTRIBUTE_UNUSED)
 {
   /* 0=incompatible 1=compatible 2=warning */
   return 1;
@@ -2991,7 +3032,7 @@ m32c_immd_dbl_mov (rtx * operands,
            && GET_CODE (XEXP (XEXP (XEXP (operands[0], 0), 0), 0)) == SYMBOL_REF
            && MEM_SCALAR_P (operands[0])
            && !MEM_IN_STRUCT_P (operands[0])
-           && !(XINT (XEXP (XEXP (XEXP (operands[0], 0), 0), 1), 0) %4)
+           && !(INTVAL (XEXP (XEXP (XEXP (operands[0], 0), 0), 1)) %4)
            && GET_CODE (XEXP (operands[2], 0)) == CONST
            && GET_CODE (XEXP (XEXP (operands[2], 0), 0)) == PLUS
            && GET_CODE (XEXP (XEXP (XEXP (operands[2], 0), 0), 0)) == SYMBOL_REF
@@ -3005,7 +3046,7 @@ m32c_immd_dbl_mov (rtx * operands,
            &&  GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT
            &&  MEM_SCALAR_P (operands[0])
            &&  !MEM_IN_STRUCT_P (operands[0])
-           &&  !(XINT (XEXP (XEXP (operands[0], 0), 1), 0) %4)
+           &&  !(INTVAL (XEXP (XEXP (operands[0], 0), 1)) %4)
            &&  REGNO (XEXP (XEXP (operands[2], 0), 0)) == FB_REGNO 
            &&  GET_CODE (XEXP (XEXP (operands[2], 0), 1)) == CONST_INT
            &&  MEM_SCALAR_P (operands[2])
@@ -3034,8 +3075,8 @@ m32c_immd_dbl_mov (rtx * operands,
        okflag = 0; 
       break; 
     case 3:
-      offset1 = XINT (XEXP (XEXP (operands[0], 0), 1), 0);
-      offset2 = XINT (XEXP (XEXP (operands[2], 0), 1), 0);
+      offset1 = INTVAL (XEXP (XEXP (operands[0], 0), 1));
+      offset2 = INTVAL (XEXP (XEXP (operands[2], 0), 1));
       offsetsign = offset1 >> ((sizeof (offset1) * 8) -1);
       if (((offset2-offset1) == 2) && offsetsign != 0)
        okflag = 1;
@@ -3051,7 +3092,7 @@ m32c_immd_dbl_mov (rtx * operands,
       HOST_WIDE_INT val;
       operands[4] = gen_rtx_MEM (SImode, XEXP (operands[0], 0));
 
-      val = (XINT (operands[3], 0) << 16) + (XINT (operands[1], 0) & 0xFFFF);
+      val = (INTVAL (operands[3]) << 16) + (INTVAL (operands[1]) & 0xFFFF);
       operands[5] = gen_rtx_CONST_INT (VOIDmode, val);
      
       return true;
@@ -3155,7 +3196,7 @@ m32c_prepare_move (rtx * operands, enum machine_mode mode)
       emit_insn (gen_rtx_SET (Pmode, dest_reg, dest_mod));
       operands[0] = gen_rtx_MEM (mode, dest_reg);
     }
-  if (!no_new_pseudos && MEM_P (operands[0]) && MEM_P (operands[1]))
+  if (can_create_pseudo_p () && MEM_P (operands[0]) && MEM_P (operands[1]))
     operands[1] = copy_to_mode_reg (mode, operands[1]);
   return 0;
 }
@@ -3220,7 +3261,7 @@ m32c_split_move (rtx * operands, enum machine_mode mode, int split_all)
 
   /* Before splitting mem-mem moves, force one operand into a
      register.  */
-  if (!no_new_pseudos && MEM_P (operands[0]) && MEM_P (operands[1]))
+  if (can_create_pseudo_p () && MEM_P (operands[0]) && MEM_P (operands[1]))
     {
 #if DEBUG0
       fprintf (stderr, "force_reg...\n");
@@ -3235,7 +3276,8 @@ m32c_split_move (rtx * operands, enum machine_mode mode, int split_all)
   parts = 2;
 
 #if DEBUG_SPLIT
-  fprintf (stderr, "\nsplit_move %d all=%d\n", no_new_pseudos, split_all);
+  fprintf (stderr, "\nsplit_move %d all=%d\n", !can_create_pseudo_p (),
+          split_all);
   debug_rtx (operands[0]);
   debug_rtx (operands[1]);
 #endif
@@ -3774,7 +3816,7 @@ m32c_expand_insv (rtx *operands)
        op0 = sub;
     }
 
-  if (no_new_pseudos
+  if (!can_create_pseudo_p ()
       || (GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0)))
     src0 = op0;
   else
@@ -3879,20 +3921,20 @@ m32c_leaf_function_p (void)
   struct sequence_stack *seq;
   int rv;
 
-  saved_first = cfun->emit->x_first_insn;
-  saved_last = cfun->emit->x_last_insn;
-  for (seq = cfun->emit->sequence_stack; seq && seq->next; seq = seq->next)
+  saved_first = crtl->emit.x_first_insn;
+  saved_last = crtl->emit.x_last_insn;
+  for (seq = crtl->emit.sequence_stack; seq && seq->next; seq = seq->next)
     ;
   if (seq)
     {
-      cfun->emit->x_first_insn = seq->first;
-      cfun->emit->x_last_insn = seq->last;
+      crtl->emit.x_first_insn = seq->first;
+      crtl->emit.x_last_insn = seq->last;
     }
 
   rv = leaf_function_p ();
 
-  cfun->emit->x_first_insn = saved_first;
-  cfun->emit->x_last_insn = saved_last;
+  crtl->emit.x_first_insn = saved_first;
+  crtl->emit.x_last_insn = saved_last;
   return rv;
 }
 
@@ -3908,7 +3950,7 @@ m32c_function_needs_enter (void)
   rtx fb = gen_rtx_REG (Pmode, FB_REGNO);
 
   insn = get_insns ();
-  for (seq = cfun->emit->sequence_stack;
+  for (seq = crtl->emit.sequence_stack;
        seq;
        insn = seq->first, seq = seq->next);
 
@@ -4048,7 +4090,7 @@ m32c_emit_eh_epilogue (rtx ret_addr)
      (fudged), and return (fudged).  This is actually easier to do in
      assembler, so punt to libgcc.  */
   emit_jump_insn (gen_eh_epilogue (ret_addr, cfun->machine->eh_stack_adjust));
-  /*  emit_insn (gen_rtx_CLOBBER (HImode, gen_rtx_REG (HImode, R0L_REGNO))); */
+  /*  emit_clobber (gen_rtx_REG (HImode, R0L_REGNO)); */
   emit_barrier ();
 }
 
@@ -4267,22 +4309,22 @@ m32c_compare_redundant (rtx cmp, rtx *operands)
 char *
 m32c_output_compare (rtx insn, rtx *operands)
 {
-  static char template[] = ";cmp.b\t%1,%0";
+  static char templ[] = ";cmp.b\t%1,%0";
   /*                             ^ 5  */
 
-  template[5] = " bwll"[GET_MODE_SIZE(GET_MODE(operands[0]))];
+  templ[5] = " bwll"[GET_MODE_SIZE(GET_MODE(operands[0]))];
   if (m32c_compare_redundant (insn, operands))
     {
 #if DEBUG_CMP
       fprintf(stderr, "cbranch: cmp not needed\n");
 #endif
-      return template;
+      return templ;
     }
 
 #if DEBUG_CMP
-  fprintf(stderr, "cbranch: cmp needed: `%s'\n", template);
+  fprintf(stderr, "cbranch: cmp needed: `%s'\n", templ);
 #endif
-  return template + 1;
+  return templ + 1;
 }
 
 #undef TARGET_ENCODE_SECTION_INFO