OSDN Git Service

* system.h (STRIP_NAME_ENCODING): Poison it.
[pf3gnuchains/gcc-fork.git] / gcc / config / v850 / v850.c
index 86c7144..e65dae5 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for NEC V850 series
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    Contributed by Jeff Law (law@cygnus.com).
 
@@ -29,7 +29,6 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
@@ -40,21 +39,29 @@ Boston, MA 02111-1307, USA.  */
 #include "cpplib.h"
 #include "c-lex.h"
 #include "ggc.h"
+#include "integrate.h"
 #include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
 
 #ifndef streq
 #define streq(a,b) (strcmp (a, b) == 0)
 #endif
 
 /* Function prototypes for stupid compilers:  */
-static void const_double_split
-  PARAMS ((rtx, HOST_WIDE_INT *, HOST_WIDE_INT *));
-static int  const_costs_int        PARAMS ((HOST_WIDE_INT, int));
-static void substitute_ep_register PARAMS ((rtx, rtx, int, int, rtx *, rtx *));
-static int  ep_memory_offset       PARAMS ((enum machine_mode, int));
-static void v850_set_data_area     PARAMS ((tree, v850_data_area));
-static void v850_save_machine_status    PARAMS ((struct function *));
-static void v850_restore_machine_status PARAMS ((struct function *));
+static void const_double_split       PARAMS ((rtx, HOST_WIDE_INT *, HOST_WIDE_INT *));
+static int  const_costs_int          PARAMS ((HOST_WIDE_INT, int));
+static void substitute_ep_register   PARAMS ((rtx, rtx, int, int, rtx *, rtx *));
+static int  ep_memory_offset         PARAMS ((enum machine_mode, int));
+static void v850_set_data_area       PARAMS ((tree, v850_data_area));
+const struct attribute_spec v850_attribute_table[];
+static tree v850_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree v850_handle_data_area_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static void v850_insert_attributes   PARAMS ((tree, tree *));
+static void v850_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));
+static void v850_encode_data_area    PARAMS ((tree));
+static void v850_encode_section_info PARAMS ((tree, int));
+static const char *v850_strip_name_encoding PARAMS ((const char *));
 
 /* True if the current function has anonymous arguments.  */
 int current_function_anonymous_args;
@@ -82,7 +89,26 @@ static int v850_interrupt_cache_p = FALSE;
 
 /* Whether current function is an interrupt handler.  */
 static int v850_interrupt_p = FALSE;
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
+
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
 
+#undef  TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION  v850_select_section
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
+#undef TARGET_STRIP_NAME_ENCODING
+#define TARGET_STRIP_NAME_ENCODING v850_strip_name_encoding
+
+struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Sometimes certain combinations of command options do not make
    sense on a particular target machine.  You can define a macro
@@ -105,14 +131,14 @@ override_options ()
       if (small_memory[i].value)
        {
          if (!ISDIGIT (*small_memory[i].value))
-           error ("%s=%s is not numeric.",
+           error ("%s=%s is not numeric",
                   small_memory[i].name,
                   small_memory[i].value);
          else
            {
              small_memory[i].max = atoi (small_memory[i].value);
              if (small_memory[i].max > small_memory[i].physical_max)
-               error ("%s=%s is too large.",
+               error ("%s=%s is too large",
                   small_memory[i].name,
                   small_memory[i].value);
            }
@@ -478,7 +504,7 @@ print_operand (file, x, code)
          fprintf (file, reg_names[REGNO (x) + 1]);
          break;
        case MEM:
-         x = XEXP (adj_offsettable_operand (x, 4), 0);
+         x = XEXP (adjust_address (x, SImode, 4), 0);
          print_operand_address (file, x);
          if (GET_CODE (x) == CONST_INT)
            fprintf (file, "[r0]");
@@ -542,7 +568,7 @@ print_operand (file, x, code)
          fputs (reg_names[REGNO (x)], file);
          break;
        case SUBREG:
-         fputs (reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)], file);
+         fputs (reg_names[subreg_regno (x)], file);
          break;
        case CONST_INT:
        case SYMBOL_REF:
@@ -824,7 +850,7 @@ output_move_double (operands)
       if (GET_CODE (inside) == REG)
        ptrreg = REGNO (inside);
       else if (GET_CODE (inside) == SUBREG)
-       ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside);
+       ptrreg = subreg_regno (inside);
       else if (GET_CODE (inside) == PLUS)
        ptrreg = REGNO (XEXP (inside, 0));
       else if (GET_CODE (inside) == LO_SUM)
@@ -1036,7 +1062,7 @@ not_power_of_two_operand (op, mode)
   else if (mode == HImode)
     mask = 0xffff;
   else if (mode == SImode)
-    mask = 0xffffffffU;
+    mask = 0xffffffff;
   else
     return 0;
 
@@ -1153,7 +1179,7 @@ Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, end
    as a C statement to act on the code starting at INSN.
 
    On the 850, we use it to implement the -mep mode to copy heavily used
-   pointers to ep to use the implicit addressing */
+   pointers to ep to use the implicit addressing */
 
 void v850_reorg (start_insn)
      rtx start_insn;
@@ -1173,7 +1199,7 @@ void v850_reorg (start_insn)
   rtx insn;
   rtx pattern;
 
-  /* If not ep mode, just return now */
+  /* If not ep mode, just return now */
   if (!TARGET_EP)
     return;
 
@@ -1235,12 +1261,15 @@ void v850_reorg (start_insn)
              int unsignedp = FALSE;
 
              /* We might have (SUBREG (MEM)) here, so just get rid of the
-                subregs to make this code simpler.  It is safe to call
-                alter_subreg any time after reload.  */
-             if (GET_CODE (dest) == SUBREG)
-               dest = alter_subreg (dest);
-             if (GET_CODE (src) == SUBREG)
-               src = alter_subreg (src);
+                subregs to make this code simpler.  */
+             if (GET_CODE (dest) == SUBREG
+                 && (GET_CODE (SUBREG_REG (dest)) == MEM
+                     || GET_CODE (SUBREG_REG (dest)) == REG))
+               alter_subreg (&dest);
+             if (GET_CODE (src) == SUBREG
+                 && (GET_CODE (SUBREG_REG (src)) == MEM
+                     || GET_CODE (SUBREG_REG (src)) == REG))
+               alter_subreg (&src);
 
              if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
                mem = NULL_RTX;
@@ -1378,7 +1407,7 @@ compute_register_save_size (p_reg_saved)
   long reg_saved = 0;
 
   /* Count the return pointer if we need to save it.  */
-  if (profile_flag && !call_p)
+  if (current_function_profile && !call_p)
     regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
  
   /* Count space for the register saves.  */
@@ -1425,14 +1454,11 @@ compute_register_save_size (p_reg_saved)
         need to cover the possibility that such a helper function will
         be used, despite the fact that there might be gaps in the list of
         registers that need to be saved.  To detect this we note that the
-        helper functions always push at least register r29 if the link
-        register is not used, and at least registers r27 - r31 if the
-        link register is used (and provided that the function is not an
-        interrupt handler).  */
+        helper functions always push at least register r29 (provided
+        that the function is not an interrupt handler).  */
         
       if (TARGET_PROLOG_FUNCTION
-         && (i == 2 || i >= 20)
-         && regs_ever_live[LINK_POINTER_REGNUM] ? (i < 28) : (i < 30))
+          && (i == 2 || ((i >= 20) && (i < 30))))
        {
          if (i == 2)
            {
@@ -1606,7 +1632,7 @@ expand_prologue ()
              offset -= 4;
            }
 
-         code = recog (save_all, NULL_RTX, NULL_PTR);
+         code = recog (save_all, NULL_RTX, NULL);
          if (code >= 0)
            {
              rtx insn = emit_insn (save_all);
@@ -1791,7 +1817,7 @@ expand_epilogue ()
              offset -= 4;
            }
 
-         code = recog (restore_all, NULL_RTX, NULL_PTR);
+         code = recog (restore_all, NULL_RTX, NULL);
          
          if (code >= 0)
            {
@@ -1970,13 +1996,13 @@ v850_data_area
 v850_get_data_area (decl)
      tree decl;
 {
-  if (lookup_attribute ("sda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+  if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
     return DATA_AREA_SDA;
   
-  if (lookup_attribute ("tda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+  if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
     return DATA_AREA_TDA;
   
-  if (lookup_attribute ("zda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+  if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
     return DATA_AREA_ZDA;
 
   return DATA_AREA_NORMAL;
@@ -2000,61 +2026,92 @@ v850_set_data_area (decl, data_area)
       return;
     }
 
-  DECL_MACHINE_ATTRIBUTES (decl) = tree_cons
-    (name, NULL, DECL_MACHINE_ATTRIBUTES (decl));
+  DECL_ATTRIBUTES (decl) = tree_cons
+    (name, NULL, DECL_ATTRIBUTES (decl));
 }
 \f
-/* Return nonzero if ATTR is a valid attribute for DECL.
-   ARGS are the arguments supplied with ATTR.  */
+const struct attribute_spec v850_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "interrupt_handler", 0, 0, true,  false, false, v850_handle_interrupt_attribute },
+  { "interrupt",         0, 0, true,  false, false, v850_handle_interrupt_attribute },
+  { "sda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
+  { "tda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
+  { "zda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
+  { NULL,                0, 0, false, false, false, NULL }
+};
 
-int
-v850_valid_machine_decl_attribute (decl, attr, args)
-     tree decl;
-     tree attr;
-     tree args;
+/* Handle an "interrupt" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+v850_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning ("`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "sda", "tda" or "zda" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+v850_handle_data_area_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
   v850_data_area data_area;
   v850_data_area area;
-  
-  if (args != NULL_TREE)
-    return 0;
-
-  if (is_attribute_p ("interrupt_handler", attr)
-      || is_attribute_p ("interrupt", attr))
-    return TREE_CODE (decl) == FUNCTION_DECL;
+  tree decl = *node;
 
   /* Implement data area attribute.  */
-  if (is_attribute_p ("sda", attr))
+  if (is_attribute_p ("sda", name))
     data_area = DATA_AREA_SDA;
-  else if (is_attribute_p ("tda", attr))
+  else if (is_attribute_p ("tda", name))
     data_area = DATA_AREA_TDA;
-  else if (is_attribute_p ("zda", attr))
+  else if (is_attribute_p ("zda", name))
     data_area = DATA_AREA_ZDA;
   else
-    return 0;
+    abort ();
   
   switch (TREE_CODE (decl))
     {
     case VAR_DECL:
       if (current_function_decl != NULL_TREE)
-       error_with_decl (decl, "\
+       {
+         error_with_decl (decl, "\
 a data area attribute cannot be specified for local variables");
-      
+         *no_add_attrs = true;
+       }
+
       /* Drop through.  */
 
     case FUNCTION_DECL:
       area = v850_get_data_area (decl);
       if (area != DATA_AREA_NORMAL && data_area != area)
-       error_with_decl (decl, "\
+       {
+         error_with_decl (decl, "\
 data area of '%s' conflicts with previous declaration");
-      
-      return 1;
+         *no_add_attrs = true;
+       }
+      break;
       
     default:
       break;
     }
-  
-  return 0;
+
+  return NULL_TREE;
 }
 
 \f
@@ -2074,13 +2131,13 @@ v850_interrupt_function_p (func)
   if (TREE_CODE (func) != FUNCTION_DECL)
     return 0;
 
-  a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
+  a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
   if (a != NULL_TREE)
     ret = 1;
 
   else
     {
-      a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+      a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
       ret = a != NULL_TREE;
     }
 
@@ -2093,7 +2150,7 @@ v850_interrupt_function_p (func)
 }
 
 \f
-void
+static void
 v850_encode_data_area (decl)
      tree decl;
 {
@@ -2154,6 +2211,23 @@ v850_encode_data_area (decl)
   XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 2);
 }
 
+static void
+v850_encode_section_info (decl, first)
+     tree decl;
+     int first;
+{
+  if (first && TREE_CODE (decl) == VAR_DECL
+      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+    v850_encode_data_area (decl);
+}
+
+static const char *
+v850_strip_name_encoding (str)
+     const char *str;
+{
+  return str + (ENCODED_NAME_P (str) || *str == '*');
+}
+
 /* Return true if the given RTX is a register which can be restored
    by a function epilogue.  */
 int
@@ -2247,7 +2321,7 @@ construct_restore_jr (op)
   
   if (count <= 2)
     {
-      error ("Bogus JR construction: %d\n", count);
+      error ("bogus JR construction: %d\n", count);
       return NULL;
     }
 
@@ -2268,7 +2342,7 @@ construct_restore_jr (op)
   /* Make sure that the amount we are popping either 0 or 16 bytes.  */
   if (stack_bytes != 0 && stack_bytes != 16)
     {
-      error ("Bad amount of stack space removal: %d", stack_bytes);
+      error ("bad amount of stack space removal: %d", stack_bytes);
       return NULL;
     }
 
@@ -2446,7 +2520,7 @@ construct_save_jarl (op)
   
   if (count <= 2)
     {
-      error ("Bogus JARL construction: %d\n", count);
+      error ("bogus JARL construction: %d\n", count);
       return NULL;
     }
 
@@ -2470,7 +2544,7 @@ construct_save_jarl (op)
   /* Make sure that the amount we are popping either 0 or 16 bytes.  */
   if (stack_bytes != 0 && stack_bytes != -16)
     {
-      error ("Bad amount of stack space removal: %d", stack_bytes);
+      error ("bad amount of stack space removal: %d", stack_bytes);
       return NULL;
     }
 
@@ -2556,7 +2630,7 @@ void
 v850_output_aligned_bss (file, decl, name, size, align)
      FILE * file;
      tree decl;
-     char * name;
+     const char * name;
      int size;
      int align;
 {
@@ -2596,7 +2670,7 @@ void
 v850_output_common (file, decl, name, size, align)
      FILE * file;
      tree decl;
-     char * name;
+     const char * name;
      int size;
      int align;
 {
@@ -2635,7 +2709,7 @@ void
 v850_output_local (file, decl, name, size, align)
      FILE * file;
      tree decl;
-     char * name;
+     const char * name;
      int size;
      int align;
 {
@@ -2648,9 +2722,10 @@ v850_output_local (file, decl, name, size, align)
 
 /* Add data area to the given declaration if a ghs data area pragma is
    currently in effect (#pragma ghs startXXX/endXXX).  */
-void
-v850_set_default_decl_attr (decl)
+static void
+v850_insert_attributes (decl, attr_ptr)
      tree decl;
+     tree *attr_ptr ATTRIBUTE_UNUSED;
 {
   if (data_area_stack
       && data_area_stack->data_area
@@ -2768,7 +2843,7 @@ v850_va_arg (valist, type)
     }
 
   addr = save_expr (valist);
-  incr = fold (build (PLUS_EXPR, ptr_type_node, valist,
+  incr = fold (build (PLUS_EXPR, ptr_type_node, addr,
                      build_int_2 (rsize, 0)));
 
   incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
@@ -2781,40 +2856,12 @@ v850_va_arg (valist, type)
     {
       addr_rtx = force_reg (Pmode, addr_rtx);
       addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
-      MEM_ALIAS_SET (addr_rtx) = get_varargs_alias_set ();
+      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
     }
 
   return addr_rtx;
 }
 \f
-/* Functions to save and restore machine-specific function data.  */
-
-static rtx ra_rtx;
-
-struct machine_function
-{
-  /* Records __builtin_return address.  */
-  struct rtx_def * ra_rtx;
-};
-
-static void
-v850_save_machine_status (p)
-     struct function * p;
-{
-  p->machine =
-    (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
-  p->machine->ra_rtx = ra_rtx;
-}
-
-static void
-v850_restore_machine_status (p)
-     struct function * p;
-{
-  ra_rtx = p->machine->ra_rtx;
-  free (p->machine);
-  p->machine = NULL;
-}
-
 /* Return an RTX indicating where the return address to the
    calling function can be found.  */
 
@@ -2825,35 +2872,62 @@ v850_return_addr (count)
   if (count != 0)
     return const0_rtx;
 
-  if (ra_rtx == NULL)
+  return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
+}
+\f
+static void
+v850_select_section (exp, reloc, align)
+     tree exp;
+     int reloc;
+     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+  if (TREE_CODE (exp) == VAR_DECL)
     {
-      rtx init;
-      
-      /* No rtx yet.  Invent one, and initialize it for r31 (lp) in 
-       the prologue.  */
-      ra_rtx = gen_reg_rtx (Pmode);
-      
-      init = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
-
-      init = gen_rtx_SET (VOIDmode, ra_rtx, init);
-
-      /* Emit the insn to the prologue with the other argument copies.  */
-      push_topmost_sequence ();
-      emit_insn_after (init, get_insns ());
-      pop_topmost_sequence ();
-    }
+      int is_const;
+      if (!TREE_READONLY (exp)
+         || TREE_SIDE_EFFECTS (exp)
+         || !DECL_INITIAL (exp)
+         || (DECL_INITIAL (exp) != error_mark_node
+             && !TREE_CONSTANT (DECL_INITIAL (exp))))
+        is_const = FALSE;
+      else
+        is_const = TRUE;
 
-  debug_rtx (ra_rtx);
-  return ra_rtx;
-}
+      switch (v850_get_data_area (exp))
+        {
+        case DATA_AREA_ZDA:
+         if (is_const)
+           rozdata_section ();
+         else
+           zdata_section ();
+         break;
 
-/* Do anything needed before RTL is emitted for each function.  */
+        case DATA_AREA_TDA:
+         tdata_section ();
+         break;
 
-void
-v850_init_expanders ()
-{
-  ra_rtx = NULL;
+        case DATA_AREA_SDA:
+         if (is_const)
+           rosdata_section ();
+         else
+           sdata_section ();
+         break;
 
-  save_machine_status    = v850_save_machine_status;
-  restore_machine_status = v850_restore_machine_status;
+        default:
+          if (is_const)
+           readonly_data_section ();
+         else
+           data_section ();
+         break;
+        }
+    }
+  else if (TREE_CODE (exp) == STRING_CST)
+    {
+      if (! flag_writable_strings)
+       readonly_data_section ();
+      else
+       data_section ();
+    }
+  else
+    readonly_data_section ();
 }