OSDN Git Service

* system.h (STRIP_NAME_ENCODING): Poison it.
[pf3gnuchains/gcc-fork.git] / gcc / config / v850 / v850.c
index c3de80b..e65dae5 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines for insn-output.c for NEC V850 series
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
    Contributed by Jeff Law (law@cygnus.com).
 
 This file is part of GNU CC.
@@ -19,23 +20,48 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-#include <stdio.h>
-#include <ctype.h>
 #include "config.h"
+#include "system.h"
+#include "tree.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "recog.h"
 #include "expr.h"
-#include "tree.h"
-#include "obstack.h"
+#include "function.h"
+#include "toplev.h"
+#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));
+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;
@@ -49,13 +75,40 @@ struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
   { "zda",     (char *)0,      0,              32768 },
 };
 
+/* Names of the various data areas used on the v850.  */
+tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+
+/* Track the current data area set by the data area pragma (which 
+   can be nested).  Tested by check_default_data_area.  */
+data_area_stack_element * data_area_stack = NULL;
+
 /* True if we don't need to check any more if the current
-   function is an interrupt handler */
+   function is an interrupt handler */
 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
@@ -70,22 +123,22 @@ void
 override_options ()
 {
   int i;
-  extern int atoi ();
+  extern int atoi PARAMS ((const char *));
 
   /* Parse -m{s,t,z}da=nnn switches */
   for (i = 0; i < (int)SMALL_MEMORY_max; i++)
     {
       if (small_memory[i].value)
        {
-         if (!isdigit (*small_memory[i].value))
-           error ("%s=%s is not numeric.",
+         if (!ISDIGIT (*small_memory[i].value))
+           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);
            }
@@ -142,16 +195,16 @@ function_arg (cum, mode, type, named)
   switch (cum->nbytes / UNITS_PER_WORD)
     {
     case 0:
-      result = gen_rtx (REG, mode, 6);
+      result = gen_rtx_REG (mode, 6);
       break;
     case 1:
-      result = gen_rtx (REG, mode, 7);
+      result = gen_rtx_REG (mode, 7);
       break;
     case 2:
-      result = gen_rtx (REG, mode, 8);
+      result = gen_rtx_REG (mode, 8);
       break;
     case 3:
-      result = gen_rtx (REG, mode, 9);
+      result = gen_rtx_REG (mode, 9);
       break;
     default:
       result = 0;
@@ -235,6 +288,9 @@ const_double_split (x, p_high, p_low)
          *p_high = CONST_DOUBLE_HIGH (x);
          *p_low  = CONST_DOUBLE_LOW (x);
          return;
+
+       default:
+         break;
        }
     }
 
@@ -305,75 +361,55 @@ print_operand (file, x, code)
 
   switch (code)
     {
+    case 'c':
+      /* We use 'c' operands with symbols for .vtinherit */
+      if (GET_CODE (x) == SYMBOL_REF)
+        {
+          output_addr_const(file, x);
+          break;
+        }
+      /* fall through */
     case 'b':
     case 'B':
-      switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
-       {
-         case NE:
-           fprintf (file, "bne");
-           break;
-         case EQ:
-           fprintf (file, "be");
-           break;
-         case GE:
-           fprintf (file, "bge");
-           break;
-         case GT:
-           fprintf (file, "bgt");
-           break;
-         case LE:
-           fprintf (file, "ble");
-           break;
-         case LT:
-           fprintf (file, "blt");
-           break;
-         case GEU:
-           fprintf (file, "bnl");
-           break;
-         case GTU:
-           fprintf (file, "bh");
-           break;
-         case LEU:
-           fprintf (file, "bnh");
-           break;
-         case LTU:
-           fprintf (file, "bl");
-           break;
-         default:
-           abort ();
-       }
-      break;
-      switch (GET_CODE (x))
+    case 'C':
+      switch ((code == 'B' || code == 'C')
+             ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
        {
          case NE:
-           fprintf (file, "be");
+           if (code == 'c' || code == 'C')
+             fprintf (file, "nz");
+           else
+             fprintf (file, "ne");
            break;
          case EQ:
-           fprintf (file, "bne");
+           if (code == 'c' || code == 'C')
+             fprintf (file, "z");
+           else
+             fprintf (file, "e");
            break;
          case GE:
-           fprintf (file, "blt");
+           fprintf (file, "ge");
            break;
          case GT:
-           fprintf (file, "bgt");
+           fprintf (file, "gt");
            break;
          case LE:
-           fprintf (file, "ble");
+           fprintf (file, "le");
            break;
          case LT:
-           fprintf (file, "blt");
+           fprintf (file, "lt");
            break;
          case GEU:
-           fprintf (file, "bnl");
+           fprintf (file, "nl");
            break;
          case GTU:
-           fprintf (file, "bh");
+           fprintf (file, "h");
            break;
          case LEU:
-           fprintf (file, "bnh");
+           fprintf (file, "nh");
            break;
          case LTU:
-           fprintf (file, "bl");
+           fprintf (file, "l");
            break;
          default:
            abort ();
@@ -410,7 +446,7 @@ print_operand (file, x, code)
     case 'O':
       if (special_symbolref_operand (x, VOIDmode))
         {
-          char* name;
+          const char *name;
 
          if (GET_CODE (x) == SYMBOL_REF)
            name = XSTR (x, 0);
@@ -426,21 +462,21 @@ print_operand (file, x, code)
           else if (TDA_NAME_P (name))
             fprintf (file, "tdaoff");
           else
-            abort();
+            abort ();
         }
       else
-        abort();
+        abort ();
       break;
     case 'P':
       if (special_symbolref_operand (x, VOIDmode))
         output_addr_const (file, x);
       else
-        abort();
+        abort ();
       break;
     case 'Q':
       if (special_symbolref_operand (x, VOIDmode))
         {
-          char* name;
+          const char *name;
 
          if (GET_CODE (x) == SYMBOL_REF)
            name = XSTR (x, 0);
@@ -456,26 +492,31 @@ print_operand (file, x, code)
           else if (TDA_NAME_P (name))
             fprintf (file, "ep");
           else
-            abort();
+            abort ();
         }
       else
-        abort();
+        abort ();
       break;
     case 'R':          /* 2nd word of a double.  */
       switch (GET_CODE (x))
        {
-         case REG:
-           fprintf (file, reg_names[REGNO (x) + 1]);
-           break;
-         case MEM:
-           print_operand_address (file,
-                                  XEXP (adj_offsettable_operand (x, 4), 0));
-           break;
+       case REG:
+         fprintf (file, reg_names[REGNO (x) + 1]);
+         break;
+       case MEM:
+         x = XEXP (adjust_address (x, SImode, 4), 0);
+         print_operand_address (file, x);
+         if (GET_CODE (x) == CONST_INT)
+           fprintf (file, "[r0]");
+         break;
+         
+       default:
+         break;
        }
       break;
     case 'S':
       {
-        /* if it's a referance to a TDA variable, use sst/sld vs. st/ld */
+        /* if it's a reference to a TDA variable, use sst/sld vs. st/ld */
         if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), FALSE))
           fputs ("s", file);
 
@@ -504,14 +545,21 @@ print_operand (file, x, code)
     case '.':                  /* register r0 */
       fputs (reg_names[0], file);
       break;
+    case 'z':                  /* reg or zero */
+      if (x == const0_rtx)
+       fputs (reg_names[0], file);
+      else if (GET_CODE (x) == REG)
+       fputs (reg_names[REGNO (x)], file);
+      else
+       abort ();
+      break;
     default:
       switch (GET_CODE (x))
        {
        case MEM:
          if (GET_CODE (XEXP (x, 0)) == CONST_INT)
-           output_address (gen_rtx (PLUS, SImode,
-                                    gen_rtx (REG, SImode, 0),
-                                    XEXP (x, 0)));
+           output_address (gen_rtx_PLUS (SImode, gen_rtx (REG, SImode, 0),
+                                         XEXP (x, 0)));
          else
            output_address (XEXP (x, 0));
          break;
@@ -520,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:
@@ -583,9 +631,9 @@ print_operand_address (file, addr)
     case SYMBOL_REF:
       if (ENCODED_NAME_P (XSTR (addr, 0)))
         {
-          char* name = XSTR (addr, 0);
-          char* off_name;
-          char* reg_name;
+          const char *name = XSTR (addr, 0);
+          const char *off_name;
+          const char *reg_name;
 
           if (ZDA_NAME_P (name))
             {
@@ -603,7 +651,7 @@ print_operand_address (file, addr)
               reg_name = "ep";
             }
           else
-            abort();
+            abort ();
 
           fprintf (file, "%s(", off_name);
           output_addr_const (file, addr);
@@ -615,9 +663,9 @@ print_operand_address (file, addr)
     case CONST:
       if (special_symbolref_operand (addr, VOIDmode))
         {
-          char* name = XSTR (XEXP (XEXP (addr, 0), 0), 0);
-          char* off_name;
-          char* reg_name;
+          const char *name = XSTR (XEXP (XEXP (addr, 0), 0), 0);
+          const char *off_name;
+          const char *reg_name;
 
           if (ZDA_NAME_P (name))
             {
@@ -635,7 +683,7 @@ print_operand_address (file, addr)
               reg_name = "ep";
             }
           else
-            abort();
+            abort ();
 
           fprintf (file, "%s(", off_name);
           output_addr_const (file, addr);
@@ -654,7 +702,7 @@ print_operand_address (file, addr)
 /* Return appropriate code to load up a 1, 2, or 4 integer/floating
    point value.  */
 
-char *
+const char *
 output_move_single (operands)
      rtx *operands;
 {
@@ -738,14 +786,15 @@ output_move_single (operands)
        return "%S0st%W0 %.,%0";
     }
 
-  fatal_insn ("output_move_single:", gen_rtx (SET, VOIDmode, dst, src));
+  fatal_insn ("output_move_single:", gen_rtx_SET (VOIDmode, dst, src));
   return "";
 }
 
 \f
-/* Return appropriate code to load up an 8 byte integer or floating point value */
+/* Return appropriate code to load up an 8 byte integer or
+   floating point value */
 
-char *
+const char *
 output_move_double (operands)
     rtx *operands;
 {
@@ -784,7 +833,7 @@ output_move_double (operands)
 
       for (i = 0; i < 2; i++)
        {
-         xop[0] = gen_rtx (REG, SImode, REGNO (dst)+i);
+         xop[0] = gen_rtx_REG (SImode, REGNO (dst)+i);
          xop[1] = GEN_INT (high_low[i]);
          output_asm_insn (output_move_single (xop), xop);
        }
@@ -801,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)
@@ -821,43 +870,57 @@ output_move_double (operands)
 }
 
 \f
-/* Return true if OP is a valid short EP memory reference */
+/* Return maximum offset supported for a short EP memory reference of mode
+   MODE and signedness UNSIGNEDP.  */
 
-int
-ep_memory_operand (op, mode, unsigned_load)
-     rtx op;
+static int
+ep_memory_offset (mode, unsignedp)
      enum machine_mode mode;
-     int unsigned_load;
+     int ATTRIBUTE_UNUSED unsignedp;
 {
-  rtx addr, op0, op1;
-  int max_offset;
-  int mask;
-
-  if (GET_CODE (op) != MEM)
-    return FALSE;
+  int max_offset = 0;
 
-  switch (GET_MODE (op))
+  switch (mode)
     {
-    default:
-      return FALSE;
-
     case QImode:
-         max_offset = (1 << 7);
-      mask = 0;
+      max_offset = (1 << 7);
       break;
 
     case HImode:
-         max_offset = (1 << 8);
-      mask = 1;
+      max_offset = (1 << 8);
       break;
 
     case SImode:
     case SFmode:
       max_offset = (1 << 8);
-      mask = 3;
+      break;
+      
+    default:
       break;
     }
 
+  return max_offset;
+}
+
+/* Return true if OP is a valid short EP memory reference */
+
+int
+ep_memory_operand (op, mode, unsigned_load)
+     rtx op;
+     enum machine_mode mode;
+     int unsigned_load;
+{
+  rtx addr, op0, op1;
+  int max_offset;
+  int mask;
+
+  if (GET_CODE (op) != MEM)
+    return FALSE;
+
+  max_offset = ep_memory_offset (mode, unsigned_load);
+
+  mask = GET_MODE_SIZE (mode) - 1;
+
   addr = XEXP (op, 0);
   if (GET_CODE (addr) == CONST)
     addr = XEXP (addr, 0);
@@ -878,6 +941,7 @@ ep_memory_operand (op, mode, unsigned_load)
       op1 = XEXP (addr, 1);
       if (GET_CODE (op1) == CONST_INT
          && INTVAL (op1) < max_offset
+         && INTVAL (op1) >= 0
          && (INTVAL (op1) & mask) == 0)
        {
          if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM)
@@ -905,23 +969,8 @@ reg_or_0_operand (op, mode)
   else if (GET_CODE (op) == CONST_DOUBLE)
     return CONST_DOUBLE_OK_FOR_G (op);
 
-  else if (GET_CODE (op) == REG)
-    return TRUE;
-
-  else if (GET_CODE (op) == SUBREG)
-    {
-      do {
-       op = SUBREG_REG (op);
-      } while (GET_CODE (op) == SUBREG);
-
-      if (GET_CODE (op) == MEM && !reload_completed)
-       return TRUE;
-
-      else if (GET_CODE (op) == REG)
-       return TRUE;
-    }
-
-  return FALSE;
+  else
+    return register_operand (op, mode);
 }
 
 /* Return true if OP is either a register or a signed five bit integer */
@@ -934,23 +983,8 @@ reg_or_int5_operand (op, mode)
   if (GET_CODE (op) == CONST_INT)
     return CONST_OK_FOR_J (INTVAL (op));
 
-  else if (GET_CODE (op) == REG)
-    return TRUE;
-
-  else if (GET_CODE (op) == SUBREG)
-    {
-      do {
-       op = SUBREG_REG (op);
-      } while (GET_CODE (op) == SUBREG);
-
-      if (GET_CODE (op) == MEM && !reload_completed)
-       return TRUE;
-
-      else if (GET_CODE (op) == REG)
-       return TRUE;
-    }
-
-  return FALSE;
+  else
+    return register_operand (op, mode);
 }
 
 /* Return true if OP is a valid call operand.  */
@@ -958,7 +992,7 @@ reg_or_int5_operand (op, mode)
 int
 call_address_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode ATTRIBUTE_UNUSED mode;
 {
   /* Only registers are valid call operands if TARGET_LONG_CALLS.  */
   if (TARGET_LONG_CALLS)
@@ -969,7 +1003,7 @@ call_address_operand (op, mode)
 int
 special_symbolref_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode ATTRIBUTE_UNUSED mode;
 {
   if (GET_CODE (op) == SYMBOL_REF)
     return ENCODED_NAME_P (XSTR (op, 0));
@@ -993,6 +1027,7 @@ movsi_source_operand (op, mode)
      must be done with HIGH & LO_SUM patterns.  */
   if (CONSTANT_P (op)
       && GET_CODE (op) != HIGH
+      && GET_CODE (op) != CONSTANT_P_RTX
       && !(GET_CODE (op) == CONST_INT
            && (CONST_OK_FOR_J (INTVAL (op))
                || CONST_OK_FOR_K (INTVAL (op))
@@ -1005,7 +1040,7 @@ movsi_source_operand (op, mode)
 int
 power_of_two_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode ATTRIBUTE_UNUSED mode;
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
@@ -1027,7 +1062,7 @@ not_power_of_two_operand (op, mode)
   else if (mode == HImode)
     mask = 0xffff;
   else if (mode == SImode)
-    mask = 0xffffffff; 
+    mask = 0xffffffff;
   else
     return 0;
 
@@ -1052,19 +1087,19 @@ substitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep)
      rtx *p_r1;
      rtx *p_ep;
 {
-  rtx reg = gen_rtx (REG, Pmode, regno);
+  rtx reg = gen_rtx_REG (Pmode, regno);
   rtx insn;
-  int i;
 
   if (!*p_r1)
     {
       regs_ever_live[1] = 1;
-      *p_r1 = gen_rtx (REG, Pmode, 1);
-      *p_ep = gen_rtx (REG, Pmode, 30);
+      *p_r1 = gen_rtx_REG (Pmode, 1);
+      *p_ep = gen_rtx_REG (Pmode, 30);
     }
 
   if (TARGET_DEBUG)
-    fprintf (stderr, "Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
+    fprintf (stderr, "\
+Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
             2 * (uses - 3), uses, reg_names[regno],
             IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
             INSN_UID (first_insn), INSN_UID (last_insn));
@@ -1083,6 +1118,8 @@ substitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep)
          if (pattern)
            {
              rtx *p_mem;
+             /* Memory operands are signed by default.  */
+             int unsignedp = FALSE;
 
              if (GET_CODE (SET_DEST (pattern)) == MEM
                  && GET_CODE (SET_SRC (pattern)) == MEM)
@@ -1101,19 +1138,21 @@ substitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep)
                {
                  rtx addr = XEXP (*p_mem, 0);
 
-                 if (GET_CODE (addr) == REG && REGNO (addr) == regno)
+                 if (GET_CODE (addr) == REG && REGNO (addr) == (unsigned) regno)
                    *p_mem = change_address (*p_mem, VOIDmode, *p_ep);
 
                  else if (GET_CODE (addr) == PLUS
                           && GET_CODE (XEXP (addr, 0)) == REG
-                          && REGNO (XEXP (addr, 0)) == regno
+                          && REGNO (XEXP (addr, 0)) == (unsigned) regno
                           && GET_CODE (XEXP (addr, 1)) == CONST_INT
-                          && ((unsigned)INTVAL (XEXP (addr, 1))) < 256
-                          && (GET_MODE (*p_mem) != QImode
-                              || ((unsigned)INTVAL (XEXP (addr, 1))) < 128))
+                          && ((INTVAL (XEXP (addr, 1)))
+                              < ep_memory_offset (GET_MODE (*p_mem),
+                                                  unsignedp))
+                          && ((INTVAL (XEXP (addr, 1))) >= 0))
                    *p_mem = change_address (*p_mem, VOIDmode,
-                                            gen_rtx (PLUS, Pmode,
-                                                     *p_ep, XEXP (addr, 1)));
+                                            gen_rtx_PLUS (Pmode,
+                                                          *p_ep,
+                                                          XEXP (addr, 1)));
                }
            }
        }
@@ -1127,10 +1166,10 @@ substitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep)
       && SET_SRC (PATTERN (insn)) == *p_r1)
     delete_insn (insn);
   else
-    emit_insn_before (gen_rtx (SET, Pmode, *p_r1, *p_ep), first_insn);
+    emit_insn_before (gen_rtx_SET (Pmode, *p_r1, *p_ep), first_insn);
 
-  emit_insn_before (gen_rtx (SET, Pmode, *p_ep, reg), first_insn);
-  emit_insn_before (gen_rtx (SET, Pmode, *p_ep, *p_r1), last_insn);
+  emit_insn_before (gen_rtx_SET (Pmode, *p_ep, reg), first_insn);
+  emit_insn_before (gen_rtx_SET (Pmode, *p_ep, *p_r1), last_insn);
 }
 
 \f
@@ -1140,16 +1179,18 @@ substitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep)
    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;
 {
-  struct {
+  struct
+  {
     int uses;
     rtx first_insn;
     rtx last_insn;
-  } regs[FIRST_PSEUDO_REGISTER];
+  }
+  regs[FIRST_PSEUDO_REGISTER];
 
   int i;
   int use_ep = FALSE;
@@ -1158,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;
 
@@ -1216,6 +1257,19 @@ void v850_reorg (start_insn)
              rtx src = SET_SRC (pattern);
              rtx dest = SET_DEST (pattern);
              rtx mem;
+             /* Memory operands are signed by default.  */
+             int unsignedp = FALSE;
+
+             /* We might have (SUBREG (MEM)) here, so just get rid of the
+                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;
@@ -1229,7 +1283,7 @@ void v850_reorg (start_insn)
              else
                mem = NULL_RTX;
 
-             if (mem && ep_memory_operand (mem, GET_MODE (mem), FALSE))
+             if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
                use_ep = TRUE;
 
              else if (!use_ep && mem
@@ -1248,9 +1302,9 @@ void v850_reorg (start_insn)
                  else if (GET_CODE (addr) == PLUS
                           && GET_CODE (XEXP (addr, 0)) == REG
                           && GET_CODE (XEXP (addr, 1)) == CONST_INT
-                          && ((unsigned)INTVAL (XEXP (addr, 1))) < 256
-                          && (GET_MODE (mem) != QImode
-                              || ((unsigned)INTVAL (XEXP (addr, 1))) < 128))
+                          && ((INTVAL (XEXP (addr, 1)))
+                              < ep_memory_offset (GET_MODE (mem), unsignedp))
+                          && ((INTVAL (XEXP (addr, 1))) >= 0))
                    {
                      short_p = TRUE;
                      regno = REGNO (XEXP (addr, 0));
@@ -1270,20 +1324,13 @@ void v850_reorg (start_insn)
 
              /* Loading up a register in the basic block zaps any savings
                 for the register */
-             if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
+             if (GET_CODE (dest) == REG)
                {
                  enum machine_mode mode = GET_MODE (dest);
-                 int word = 0;
                  int regno;
                  int endregno;
 
-                 while (GET_CODE (dest) == SUBREG)
-                   {
-                     word = SUBREG_WORD (dest);
-                     dest = SUBREG_REG (dest);
-                   }
-
-                 regno = REGNO (dest) + word;
+                 regno = REGNO (dest);
                  endregno = regno + HARD_REGNO_NREGS (regno, mode);
 
                  if (!use_ep)
@@ -1308,7 +1355,8 @@ void v850_reorg (start_insn)
                        {
                          substitute_ep_register (regs[max_regno].first_insn,
                                                  regs[max_regno].last_insn,
-                                                 max_uses, max_regno, &r1, &ep);
+                                                 max_uses, max_regno, &r1,
+                                                 &ep);
 
                          /* Since we made a substitution, zap all remembered
                             registers.  */
@@ -1355,12 +1403,12 @@ compute_register_save_size (p_reg_saved)
   int size = 0;
   int i;
   int interrupt_handler = v850_interrupt_function_p (current_function_decl);
-  int call_p = regs_ever_live[31];
+  int call_p = regs_ever_live [LINK_POINTER_REGNUM];
   long reg_saved = 0;
 
   /* Count the return pointer if we need to save it.  */
-  if (profile_flag && !call_p)
-    regs_ever_live[31] = call_p = 1;
+  if (current_function_profile && !call_p)
+    regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
  
   /* Count space for the register saves.  */
   if (interrupt_handler)
@@ -1386,22 +1434,67 @@ compute_register_save_size (p_reg_saved)
               These registers are handled specially, so don't list them
               on the list of registers to save in the prologue.  */
          case 1:               /* temp used to hold ep */
-         case 5:               /* gp */
+         case 4:               /* gp */
          case 10:              /* temp used to call interrupt save/restore */
          case EP_REGNUM:       /* ep */
            size += 4;
            break;
          }
     }
-
   else
-    for (i = 0; i <= 31; i++)
-      if (regs_ever_live[i] && ((! call_used_regs[i]) || i == 31))
+    {
+      /* Find the first register that needs to be saved.  */
+      for (i = 0; i <= 31; i++)
+       if (regs_ever_live[i] && ((! call_used_regs[i])
+                                 || i == LINK_POINTER_REGNUM))
+         break;
+
+      /* If it is possible that an out-of-line helper function might be
+        used to generate the prologue for the current function, then we
+        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 (provided
+        that the function is not an interrupt handler).  */
+        
+      if (TARGET_PROLOG_FUNCTION
+          && (i == 2 || ((i >= 20) && (i < 30))))
        {
-         size += 4;
-         reg_saved |= 1L << i;
-       }
+         if (i == 2)
+           {
+             size += 4;
+             reg_saved |= 1L << i;
+
+             i = 20;
+           }
+
+         /* Helper functions save all registers between the starting
+            register and the last register, regardless of whether they
+            are actually used by the function or not.  */
+         for (; i <= 29; i++)
+           {
+             size += 4;
+             reg_saved |= 1L << i;
+           }
 
+         if (regs_ever_live [LINK_POINTER_REGNUM])
+           {
+             size += 4;
+             reg_saved |= 1L << LINK_POINTER_REGNUM;
+           }
+       }
+      else
+       {
+         for (; i <= 31; i++)
+           if (regs_ever_live[i] && ((! call_used_regs[i])
+                                     || i == LINK_POINTER_REGNUM))
+             {
+               size += 4;
+               reg_saved |= 1L << i;
+             }
+       }
+    }
+  
   if (p_reg_saved)
     *p_reg_saved = reg_saved;
 
@@ -1413,8 +1506,6 @@ compute_frame_size (size, p_reg_saved)
      int size;
      long *p_reg_saved;
 {
-  extern int current_function_outgoing_args_size;
-
   return (size
          + compute_register_save_size (p_reg_saved)
          + current_function_outgoing_args_size);
@@ -1431,20 +1522,22 @@ expand_prologue ()
   unsigned int init_stack_alloc = 0;
   rtx save_regs[32];
   rtx save_all;
-  int num_save;
-  int default_stack;
+  unsigned int num_save;
+  unsigned int default_stack;
   int code;
   int interrupt_handler = v850_interrupt_function_p (current_function_decl);
   long reg_saved = 0;
 
   actual_fsize = compute_frame_size (size, &reg_saved);
 
-  /* Save/setup global registers for interrupt functions right now */
+  /* Save/setup global registers for interrupt functions right now */
   if (interrupt_handler)
     {
-      emit_insn (gen_save_interrupt ());
+       emit_insn (gen_save_interrupt ());
+      
       actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
-      if (((1L << 31) & reg_saved) != 0)
+      
+      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
        actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
     }
 
@@ -1452,35 +1545,37 @@ expand_prologue ()
   else if (current_function_anonymous_args)
     {
       if (TARGET_PROLOG_FUNCTION)
-       emit_insn (gen_save_r6_r9 ());
+       {
+         emit_insn (gen_save_r6_r9 ());
+       }
       else
        {
          offset = 0;
          for (i = 6; i < 10; i++)
            {
-             emit_move_insn (gen_rtx (MEM, SImode,
-                                      plus_constant (stack_pointer_rtx,
-                                                     offset)),
-                             gen_rtx (REG, SImode, i));
+             emit_move_insn (gen_rtx_MEM (SImode,
+                                          plus_constant (stack_pointer_rtx,
+                                                         offset)),
+                             gen_rtx_REG (SImode, i));
              offset += 4;
            }
        }
     }
 
-  /* Identify all of the saved registers */
+  /* Identify all of the saved registers */
   num_save = 0;
   default_stack = 0;
   for (i = 1; i < 31; i++)
     {
       if (((1L << i) & reg_saved) != 0)
-       save_regs[num_save++] = gen_rtx (REG, Pmode, i);
+       save_regs[num_save++] = gen_rtx_REG (Pmode, i);
     }
 
   /* If the return pointer is saved, the helper functions also allocate
      16 bytes of stack for arguments to be saved in.  */
-  if (((1L << 31) & reg_saved) != 0)
+  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
     {
-      save_regs[num_save++] = gen_rtx (REG, Pmode, 31);
+      save_regs[num_save++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
       default_stack = 16;
     }
 
@@ -1510,39 +1605,43 @@ expand_prologue ()
         stack space is allocated.  */
       if (save_func_len < save_normal_len)
        {
-         save_all = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num_save + (TARGET_V850 ? 2 : 1)));
-         XVECEXP (save_all, 0, 0) = gen_rtx (SET, VOIDmode,
-                                             stack_pointer_rtx,
-                                             gen_rtx (PLUS, Pmode,
-                                                      stack_pointer_rtx,
-                                                      GEN_INT (-alloc_stack)));
+         save_all = gen_rtx_PARALLEL
+           (VOIDmode,
+            rtvec_alloc (num_save + (TARGET_V850 ? 2 : 1)));
+
+         XVECEXP (save_all, 0, 0)
+           = gen_rtx_SET (VOIDmode,
+                          stack_pointer_rtx,
+                          plus_constant (stack_pointer_rtx, -alloc_stack));
 
          if (TARGET_V850)
            {
              XVECEXP (save_all, 0, num_save+1)
-               = gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, Pmode, 10));
+               = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 10));
            }
 
          offset = - default_stack;
          for (i = 0; i < num_save; i++)
            {
              XVECEXP (save_all, 0, i+1)
-               = gen_rtx (SET, VOIDmode,
-                          gen_rtx (MEM, Pmode,
-                                   plus_constant (stack_pointer_rtx, offset)),
-                                   save_regs[i]);
+               = gen_rtx_SET (VOIDmode,
+                              gen_rtx_MEM (Pmode,
+                                           plus_constant (stack_pointer_rtx,
+                                                          offset)),
+                              save_regs[i]);
              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);
              INSN_CODE (insn) = code;
              actual_fsize -= alloc_stack;
-
+             
              if (TARGET_DEBUG)
-               fprintf (stderr, "Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
+               fprintf (stderr, "\
+Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
                         save_normal_len - save_func_len,
                         save_normal_len, save_func_len,
                         IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
@@ -1552,14 +1651,15 @@ expand_prologue ()
        }
     }
 
-  /* If no prolog save function is available, store the registers the old fashioned
-     way (one by one). */
+  /* If no prolog save function is available, store the registers the old
+     fashioned way (one by one). */
   if (!save_all)
     {
       /* Special case interrupt functions that save all registers for a call.  */
-      if (interrupt_handler && ((1L << 31) & reg_saved) != 0)
-       emit_insn (gen_save_all_interrupt ());
-
+      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+       {
+         emit_insn (gen_save_all_interrupt ());
+       }
       else
        {
          /* If the stack is too big, allocate it in chunks so we can do the
@@ -1579,20 +1679,20 @@ expand_prologue ()
                                   GEN_INT (-init_stack_alloc)));
          
          /* Save the return pointer first.  */
-         if (num_save > 0 && REGNO (save_regs[num_save-1]) == 31)
+         if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)
            {
-             emit_move_insn (gen_rtx (MEM, SImode,
-                                      plus_constant (stack_pointer_rtx,
-                                                     offset)),
+             emit_move_insn (gen_rtx_MEM (SImode,
+                                          plus_constant (stack_pointer_rtx,
+                                                         offset)),
                              save_regs[--num_save]);
              offset -= 4;
            }
          
          for (i = 0; i < num_save; i++)
            {
-             emit_move_insn (gen_rtx (MEM, SImode,
-                                      plus_constant (stack_pointer_rtx,
-                                                     offset)),
+             emit_move_insn (gen_rtx_MEM (SImode,
+                                          plus_constant (stack_pointer_rtx,
+                                                         offset)),
                              save_regs[i]);
              offset -= 4;
            }
@@ -1611,7 +1711,7 @@ expand_prologue ()
                               GEN_INT (-diff)));
       else
        {
-         rtx reg = gen_rtx (REG, Pmode, 12);
+         rtx reg = gen_rtx_REG (Pmode, 12);
          emit_move_insn (reg, GEN_INT (-diff));
          emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
        }
@@ -1634,8 +1734,8 @@ expand_epilogue ()
   unsigned int init_stack_free = 0;
   rtx restore_regs[32];
   rtx restore_all;
-  int num_restore;
-  int default_stack;
+  unsigned int num_restore;
+  unsigned int default_stack;
   int code;
   int interrupt_handler = v850_interrupt_function_p (current_function_decl);
 
@@ -1643,7 +1743,7 @@ expand_epilogue ()
   if (interrupt_handler)
     {
       actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
-      if (((1L << 31) & reg_saved) != 0)
+      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
        actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
     }
 
@@ -1651,27 +1751,30 @@ expand_epilogue ()
   if (frame_pointer_needed)
     emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
 
-  /* Identify all of the saved registers */
+  /* Identify all of the saved registers */
   num_restore = 0;
   default_stack = 0;
   for (i = 1; i < 31; i++)
     {
       if (((1L << i) & reg_saved) != 0)
-       restore_regs[num_restore++] = gen_rtx (REG, Pmode, i);
+       restore_regs[num_restore++] = gen_rtx_REG (Pmode, i);
     }
 
   /* If the return pointer is saved, the helper functions also allocate
      16 bytes of stack for arguments to be saved in.  */
-  if (((1L << 31) & reg_saved) != 0)
+  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
     {
-      restore_regs[num_restore++] = gen_rtx (REG, Pmode, 31);
+      restore_regs[num_restore++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
       default_stack = 16;
     }
 
   /* See if we have an insn that restores the particular registers we
      want to.  */
   restore_all = NULL_RTX;
-  if (TARGET_PROLOG_FUNCTION && num_restore > 0 && actual_fsize >= default_stack
+  
+  if (TARGET_PROLOG_FUNCTION
+      && num_restore > 0
+      && actual_fsize >= default_stack
       && !interrupt_handler)
     {
       int alloc_stack = (4 * num_restore) + default_stack;
@@ -1682,7 +1785,7 @@ expand_epilogue ()
       if (unalloc_stack)
        restore_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
 
-      /* see if we would have used ep to restore the registers */
+      /* See if we would have used ep to restore the registers.  */
       if (TARGET_EP && num_restore > 3 && (unsigned)actual_fsize < 255)
        restore_normal_len = (3 * 2) + (2 * num_restore);
       else
@@ -1693,27 +1796,29 @@ expand_epilogue ()
       /* Don't bother checking if we don't actually save any space.  */
       if (restore_func_len < restore_normal_len)
        {
-         restore_all = gen_rtx (PARALLEL, VOIDmode,
-                                rtvec_alloc (num_restore + 2));
-         XVECEXP (restore_all, 0, 0) = gen_rtx (RETURN, VOIDmode);
+         restore_all = gen_rtx_PARALLEL (VOIDmode,
+                                         rtvec_alloc (num_restore + 2));
+         XVECEXP (restore_all, 0, 0) = gen_rtx_RETURN (VOIDmode);
          XVECEXP (restore_all, 0, 1)
-           = gen_rtx (SET, VOIDmode, stack_pointer_rtx,
-                      gen_rtx (PLUS, Pmode,
-                               stack_pointer_rtx,
-                               GEN_INT (alloc_stack)));
+           = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                           gen_rtx_PLUS (Pmode,
+                                         stack_pointer_rtx,
+                                         GEN_INT (alloc_stack)));
 
          offset = alloc_stack - 4;
          for (i = 0; i < num_restore; i++)
            {
              XVECEXP (restore_all, 0, i+2)
-               = gen_rtx (SET, VOIDmode,
-                          restore_regs[i],
-                          gen_rtx (MEM, Pmode,
-                                   plus_constant (stack_pointer_rtx, offset)));
+               = gen_rtx_SET (VOIDmode,
+                              restore_regs[i],
+                              gen_rtx_MEM (Pmode,
+                                           plus_constant (stack_pointer_rtx,
+                                                          offset)));
              offset -= 4;
            }
 
-         code = recog (restore_all, NULL_RTX, NULL_PTR);
+         code = recog (restore_all, NULL_RTX, NULL);
+         
          if (code >= 0)
            {
              rtx insn;
@@ -1727,7 +1832,7 @@ expand_epilogue ()
                                           GEN_INT (actual_fsize)));
                  else
                    {
-                     rtx reg = gen_rtx (REG, Pmode, 12);
+                     rtx reg = gen_rtx_REG (Pmode, 12);
                      emit_move_insn (reg, GEN_INT (actual_fsize));
                      emit_insn (gen_addsi3 (stack_pointer_rtx,
                                             stack_pointer_rtx,
@@ -1739,7 +1844,8 @@ expand_epilogue ()
              INSN_CODE (insn) = code;
 
              if (TARGET_DEBUG)
-               fprintf (stderr, "Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
+               fprintf (stderr, "\
+Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
                         restore_normal_len - restore_func_len,
                         restore_normal_len, restore_func_len,
                         IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
@@ -1750,7 +1856,7 @@ expand_epilogue ()
     }
 
   /* If no epilog save function is available, restore the registers the
-     old fashioned way (one by one). */
+     old fashioned way (one by one).  */
   if (!restore_all)
     {
       /* If the stack is large, we need to cut it down in 2 pieces.  */
@@ -1759,18 +1865,20 @@ expand_epilogue ()
       else
        init_stack_free = actual_fsize;
 
-      /* Deallocate the rest of the stack if it is > 32K or if extra stack
-        was allocated for an interrupt handler that makes a call.  */
-      if (actual_fsize > init_stack_free || (interrupt_handler && actual_fsize))
+      /* Deallocate the rest of the stack if it is > 32K.  */
+      if (actual_fsize > init_stack_free)
        {
-         int diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);
+         int diff;
+
+         diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);
+
          if (CONST_OK_FOR_K (diff))
            emit_insn (gen_addsi3 (stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   GEN_INT (diff)));
          else
            {
-             rtx reg = gen_rtx (REG, Pmode, 12);
+             rtx reg = gen_rtx_REG (Pmode, 12);
              emit_move_insn (reg, GEN_INT (diff));
              emit_insn (gen_addsi3 (stack_pointer_rtx,
                                     stack_pointer_rtx,
@@ -1780,30 +1888,34 @@ expand_epilogue ()
 
       /* Special case interrupt functions that save all registers
         for a call.  */
-      if (interrupt_handler && ((1L << 31) & reg_saved) != 0)
-       emit_insn (gen_restore_all_interrupt ());
+      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+       {
+         emit_insn (gen_restore_all_interrupt ());
+       }
       else
        {
-         /* Restore registers from the beginning of the stack frame */
+         /* Restore registers from the beginning of the stack frame */
          offset = init_stack_free - 4;
 
          /* Restore the return pointer first.  */
-         if (num_restore > 0 && REGNO (restore_regs[num_restore-1]) == 31)
+         if (num_restore > 0
+             && REGNO (restore_regs [num_restore - 1]) == LINK_POINTER_REGNUM)
            {
              emit_move_insn (restore_regs[--num_restore],
-                             gen_rtx (MEM, SImode,
-                                      plus_constant (stack_pointer_rtx,
-                                                     offset)));
+                             gen_rtx_MEM (SImode,
+                                          plus_constant (stack_pointer_rtx,
+                                                         offset)));
              offset -= 4;
            }
 
          for (i = 0; i < num_restore; i++)
            {
              emit_move_insn (restore_regs[i],
-                             gen_rtx (MEM, SImode,
-                                      plus_constant (stack_pointer_rtx,
-                                                     offset)));
+                             gen_rtx_MEM (SImode,
+                                          plus_constant (stack_pointer_rtx,
+                                                         offset)));
 
+             emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));
              offset -= 4;
            }
 
@@ -1845,24 +1957,24 @@ notice_update_cc (body, insn)
     case CC_NONE_0HIT:
       /* Insn does not change CC, but the 0'th operand has been changed.  */
       if (cc_status.value1 != 0
-         && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
+         && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
        cc_status.value1 = 0;
       break;
 
     case CC_SET_ZN:
-      /* Insn sets the Z,N flags of CC to recog_operand[0].
+      /* Insn sets the Z,N flags of CC to recog_data.operand[0].
         V,C is in an unusable state.  */
       CC_STATUS_INIT;
       cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
-      cc_status.value1 = recog_operand[0];
+      cc_status.value1 = recog_data.operand[0];
       break;
 
     case CC_SET_ZNV:
-      /* Insn sets the Z,N,V flags of CC to recog_operand[0].
+      /* Insn sets the Z,N,V flags of CC to recog_data.operand[0].
         C is in an unusable state.  */
       CC_STATUS_INIT;
       cc_status.flags |= CC_NO_CARRY;
-      cc_status.value1 = recog_operand[0];
+      cc_status.value1 = recog_data.operand[0];
       break;
 
     case CC_COMPARE:
@@ -1877,32 +1989,129 @@ notice_update_cc (body, insn)
       break;
     }
 }
-
 \f
-/* Return nonzero if ATTR is a valid attribute for DECL.
-   ATTRIBUTES are any existing attributes and ARGS are the arguments
-   supplied with ATTR.
+/* Retrieve the data area that has been chosen for the given decl.  */
+
+v850_data_area
+v850_get_data_area (decl)
+     tree decl;
+{
+  if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+    return DATA_AREA_SDA;
+  
+  if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+    return DATA_AREA_TDA;
+  
+  if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+    return DATA_AREA_ZDA;
 
-   Supported attributes:
+  return DATA_AREA_NORMAL;
+}
 
-   interrupt_handler or interrupt: output a prologue and epilogue suitable
-   for an interrupt handler.  */
+/* Store the indicated data area in the decl's attributes.  */
 
-int
-v850_valid_machine_decl_attribute (decl, attributes, attr, args)
+static void
+v850_set_data_area (decl, data_area)
      tree decl;
-     tree attributes;
-     tree attr;
-     tree args;
+     v850_data_area data_area;
 {
-  if (args != NULL_TREE)
-    return 0;
+  tree name;
+  
+  switch (data_area)
+    {
+    case DATA_AREA_SDA: name = get_identifier ("sda"); break;
+    case DATA_AREA_TDA: name = get_identifier ("tda"); break;
+    case DATA_AREA_ZDA: name = get_identifier ("zda"); break;
+    default:
+      return;
+    }
+
+  DECL_ATTRIBUTES (decl) = tree_cons
+    (name, NULL, DECL_ATTRIBUTES (decl));
+}
+\f
+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 }
+};
+
+/* 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;
+  tree decl = *node;
+
+  /* Implement data area attribute.  */
+  if (is_attribute_p ("sda", name))
+    data_area = DATA_AREA_SDA;
+  else if (is_attribute_p ("tda", name))
+    data_area = DATA_AREA_TDA;
+  else if (is_attribute_p ("zda", name))
+    data_area = DATA_AREA_ZDA;
+  else
+    abort ();
+  
+  switch (TREE_CODE (decl))
+    {
+    case VAR_DECL:
+      if (current_function_decl != NULL_TREE)
+       {
+         error_with_decl (decl, "\
+a data area attribute cannot be specified for local variables");
+         *no_add_attrs = true;
+       }
+
+      /* Drop through.  */
 
-  if (is_attribute_p ("interrupt_handler", attr)
-      || is_attribute_p ("interrupt", attr))
-    return TREE_CODE (decl) == FUNCTION_DECL;
+    case FUNCTION_DECL:
+      area = v850_get_data_area (decl);
+      if (area != DATA_AREA_NORMAL && data_area != area)
+       {
+         error_with_decl (decl, "\
+data area of '%s' conflicts with previous declaration");
+         *no_add_attrs = true;
+       }
+      break;
+      
+    default:
+      break;
+    }
 
-  return 0;
+  return NULL_TREE;
 }
 
 \f
@@ -1922,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;
     }
 
@@ -1941,18 +2150,82 @@ v850_interrupt_function_p (func)
 }
 
 \f
-extern struct obstack *saveable_obstack;
-
+static void
 v850_encode_data_area (decl)
      tree decl;
 {
-  char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-  int len = strlen (str);
-  char *newstr;
+  const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  int    len = strlen (str);
+  char * newstr;
+
+  /* Map explict sections into the appropriate attribute */
+  if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
+    {
+      if (DECL_SECTION_NAME (decl))
+       {
+         const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+         
+         if (streq (name, ".zdata") || streq (name, ".zbss"))
+           v850_set_data_area (decl, DATA_AREA_ZDA);
+
+         else if (streq (name, ".sdata") || streq (name, ".sbss"))
+           v850_set_data_area (decl, DATA_AREA_SDA);
+
+         else if (streq (name, ".tdata"))
+           v850_set_data_area (decl, DATA_AREA_TDA);
+       }
+
+      /* If no attribute, support -m{zda,sda,tda}=n */
+      else
+       {
+         int size = int_size_in_bytes (TREE_TYPE (decl));
+         if (size <= 0)
+           ;
+
+         else if (size <= small_memory [(int) SMALL_MEMORY_TDA].max)
+           v850_set_data_area (decl, DATA_AREA_TDA);
+
+         else if (size <= small_memory [(int) SMALL_MEMORY_SDA].max)
+           v850_set_data_area (decl, DATA_AREA_SDA);
+
+         else if (size <= small_memory [(int) SMALL_MEMORY_ZDA].max)
+           v850_set_data_area (decl, DATA_AREA_ZDA);
+       }
+      
+      if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
+       return;
+    }
+
+  newstr = alloca (len + 2);
+
+  strcpy (newstr + 1, str);
+
+  switch (v850_get_data_area (decl))
+    {
+    case DATA_AREA_ZDA: *newstr = ZDA_NAME_FLAG_CHAR; break;
+    case DATA_AREA_TDA: *newstr = TDA_NAME_FLAG_CHAR; break;
+    case DATA_AREA_SDA: *newstr = SDA_NAME_FLAG_CHAR; break;
+    default: abort ();
+    }
+
+  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);
+}
 
-  /* In the Cygnus sources we actually do something; this is just
-     here to make merges easier.  */
-  return;
+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
@@ -1960,7 +2233,7 @@ v850_encode_data_area (decl)
 int
 register_is_ok_for_epilogue (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode ATTRIBUTE_UNUSED mode;
 {
   /* The save/restore routines can only cope with registers 2, and 20 - 31 */
   return (GET_CODE (op) == REG)
@@ -1973,7 +2246,7 @@ register_is_ok_for_epilogue (op, mode)
 int
 pattern_is_ok_for_epilogue (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode ATTRIBUTE_UNUSED mode;
 {
   int count = XVECLEN (op, 0);
   int i;
@@ -2048,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;
     }
 
@@ -2069,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;
     }
 
@@ -2100,33 +2373,49 @@ construct_restore_jr (op)
     abort ();
 
   /* Discover the last register to pop.  */
-  if (mask & (1 << 31))
+  if (mask & (1 << LINK_POINTER_REGNUM))
     {
       if (stack_bytes != 16)
        abort ();
       
-      last = 31;
+      last = LINK_POINTER_REGNUM;
     }
   else
     {
       if (stack_bytes != 0)
        abort ();
+      
       if ((mask & (1 << 29)) == 0)
        abort ();
       
       last = 29;
     }
 
-  /* Paranoia */
-  for (i = (first == 2 ? 20 : first + 1); i < 29; i++)
-    if ((mask & (1 << i)) == 0)
-      abort ();
-
-  if (first == last)
-    sprintf (buff, "jr __return_%s", reg_names [first]);
+  /* Note, it is possible to have gaps in the register mask.
+     We ignore this here, and generate a JR anyway.  We will
+     be popping more registers than is strictly necessary, but
+     it does save code space.  */
+  
+  if (TARGET_LONG_CALLS)
+    {
+      char name[40];
+      
+      if (first == last)
+       sprintf (name, "__return_%s", reg_names [first]);
+      else
+       sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]);
+      
+      sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6",
+              name, name);
+    }
   else
-    sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
-
+    {
+      if (first == last)
+       sprintf (buff, "jr __return_%s", reg_names [first]);
+      else
+       sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
+    }
+  
   return buff;
 }
 
@@ -2136,7 +2425,7 @@ construct_restore_jr (op)
 int
 pattern_is_ok_for_prologue (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode ATTRIBUTE_UNUSED mode;
 {
   int count = XVECLEN (op, 0);
   int i; 
@@ -2192,8 +2481,8 @@ pattern_is_ok_for_prologue (op, mode)
        return 0;
 
       /* If the register is being pushed somewhere other than the stack
-        space just aquired by the first operand then abandon this quest.
-        Note: the test is <= becuase both values are negative.  */
+        space just acquired by the first operand then abandon this quest.
+        Note: the test is <= because both values are negative.  */
       if (INTVAL (XEXP (plus, 1))
          <= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
        {
@@ -2231,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;
     }
 
@@ -2255,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;
     }
 
@@ -2286,12 +2575,12 @@ construct_save_jarl (op)
     abort ();
 
   /* Discover the last register to push.  */
-  if (mask & (1 << 31))
+  if (mask & (1 << LINK_POINTER_REGNUM))
     {
       if (stack_bytes != -16)
-       abort();
+       abort ();
       
-      last = 31;
+      last = LINK_POINTER_REGNUM;
     }
   else
     {
@@ -2303,17 +2592,342 @@ construct_save_jarl (op)
       last = 29;
     }
 
-  /* Paranoia */
-  for (i = (first == 2 ? 20 : first + 1); i < 29; i++)
-    if ((mask & (1 << i)) == 0)
-      abort ();
-
-  if (first == last)
-    sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
+  /* Note, it is possible to have gaps in the register mask.
+     We ignore this here, and generate a JARL anyway.  We will
+     be pushing more registers than is strictly necessary, but
+     it does save code space.  */
+  
+  if (TARGET_LONG_CALLS)
+    {
+      char name[40];
+      
+      if (first == last)
+       sprintf (name, "__save_%s", reg_names [first]);
+      else
+       sprintf (name, "__save_%s_%s", reg_names [first], reg_names [last]);
+      
+      sprintf (buff, "movhi hi(%s), r0, r11\n\tmovea lo(%s), r11, r11\n\tjarl .+4, r10\n\tadd 4, r10\n\tjmp r11",
+              name, name);
+    }
   else
-    sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
-            reg_names [last]);
+    {
+      if (first == last)
+       sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
+      else
+       sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
+                reg_names [last]);
+    }
 
   return buff;
 }
 
+extern tree last_assemble_variable_decl;
+extern int size_directive_output;
+
+/* A version of asm_output_aligned_bss() that copes with the special
+   data areas of the v850. */
+void
+v850_output_aligned_bss (file, decl, name, size, align)
+     FILE * file;
+     tree decl;
+     const char * name;
+     int size;
+     int align;
+{
+  ASM_GLOBALIZE_LABEL (file, name);
+  
+  switch (v850_get_data_area (decl))
+    {
+    case DATA_AREA_ZDA:
+      zbss_section ();
+      break;
+
+    case DATA_AREA_SDA:
+      sbss_section ();
+      break;
+
+    case DATA_AREA_TDA:
+      tdata_section ();
+      
+    default:
+      bss_section ();
+      break;
+    }
+  
+  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+#ifdef ASM_DECLARE_OBJECT_NAME
+  last_assemble_variable_decl = decl;
+  ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+  /* Standard thing is just output label for the object.  */
+  ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+  ASM_OUTPUT_SKIP (file, size ? size : 1);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_COMMON */
+void
+v850_output_common (file, decl, name, size, align)
+     FILE * file;
+     tree decl;
+     const char * name;
+     int size;
+     int align;
+{
+  if (decl == NULL_TREE)
+    {
+      fprintf (file, "%s", COMMON_ASM_OP);
+    }
+  else
+    {
+      switch (v850_get_data_area (decl))
+       {
+       case DATA_AREA_ZDA:
+         fprintf (file, "%s", ZCOMMON_ASM_OP);
+         break;
+
+       case DATA_AREA_SDA:
+         fprintf (file, "%s", SCOMMON_ASM_OP);
+         break;
+
+       case DATA_AREA_TDA:
+         fprintf (file, "%s", TCOMMON_ASM_OP);
+         break;
+      
+       default:
+         fprintf (file, "%s", COMMON_ASM_OP);
+         break;
+       }
+    }
+  
+  assemble_name (file, name);
+  fprintf (file, ",%u,%u\n", size, align / BITS_PER_UNIT);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_LOCAL */
+void
+v850_output_local (file, decl, name, size, align)
+     FILE * file;
+     tree decl;
+     const char * name;
+     int size;
+     int align;
+{
+  fprintf (file, "%s", LOCAL_ASM_OP);
+  assemble_name (file, name);
+  fprintf (file, "\n");
+  
+  ASM_OUTPUT_ALIGNED_DECL_COMMON (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).  */
+static void
+v850_insert_attributes (decl, attr_ptr)
+     tree decl;
+     tree *attr_ptr ATTRIBUTE_UNUSED;
+{
+  if (data_area_stack
+      && data_area_stack->data_area
+      && current_function_decl == NULL_TREE
+      && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL)
+      && v850_get_data_area (decl) == DATA_AREA_NORMAL)
+    v850_set_data_area (decl, data_area_stack->data_area);
+
+  /* Initialise the default names of the v850 specific sections,
+     if this has not been done before.  */
+  
+  if (GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA] == NULL)
+    {
+      GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA]
+       = build_string (sizeof (".sdata")-1, ".sdata");
+
+      GHS_default_section_names [(int) GHS_SECTION_KIND_ROSDATA]
+       = build_string (sizeof (".rosdata")-1, ".rosdata");
+
+      GHS_default_section_names [(int) GHS_SECTION_KIND_TDATA]
+       = build_string (sizeof (".tdata")-1, ".tdata");
+      
+      GHS_default_section_names [(int) GHS_SECTION_KIND_ZDATA]
+       = build_string (sizeof (".zdata")-1, ".zdata");
+
+      GHS_default_section_names [(int) GHS_SECTION_KIND_ROZDATA]
+       = build_string (sizeof (".rozdata")-1, ".rozdata");
+    }
+  
+  if (current_function_decl == NULL_TREE
+      && (TREE_CODE (decl) == VAR_DECL
+         || TREE_CODE (decl) == CONST_DECL
+         || TREE_CODE (decl) == FUNCTION_DECL)
+      && (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl))
+      && !DECL_SECTION_NAME (decl))
+    {
+      enum GHS_section_kind kind = GHS_SECTION_KIND_DEFAULT;
+      tree chosen_section;
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       kind = GHS_SECTION_KIND_TEXT;
+      else
+       {
+         /* First choose a section kind based on the data area of the decl. */
+         switch (v850_get_data_area (decl))
+           {
+           default:
+             abort ();
+             
+           case DATA_AREA_SDA:
+             kind = ((TREE_READONLY (decl))
+                     ? GHS_SECTION_KIND_ROSDATA
+                     : GHS_SECTION_KIND_SDATA);
+             break;
+             
+           case DATA_AREA_TDA:
+             kind = GHS_SECTION_KIND_TDATA;
+             break;
+             
+           case DATA_AREA_ZDA:
+             kind = ((TREE_READONLY (decl))
+                     ? GHS_SECTION_KIND_ROZDATA
+                     : GHS_SECTION_KIND_ZDATA);
+             break;
+             
+           case DATA_AREA_NORMAL:               /* default data area */
+             if (TREE_READONLY (decl))
+               kind = GHS_SECTION_KIND_RODATA;
+             else if (DECL_INITIAL (decl))
+               kind = GHS_SECTION_KIND_DATA;
+             else
+               kind = GHS_SECTION_KIND_BSS;
+           }
+       }
+
+      /* Now, if the section kind has been explicitly renamed,
+         then attach a section attribute. */
+      chosen_section = GHS_current_section_names [(int) kind];
+
+      /* Otherwise, if this kind of section needs an explicit section
+         attribute, then also attach one. */
+      if (chosen_section == NULL)
+        chosen_section = GHS_default_section_names [(int) kind];
+
+      if (chosen_section)
+       {
+         /* Only set the section name if specified by a pragma, because
+            otherwise it will force those variables to get allocated storage
+            in this module, rather than by the linker.  */
+         DECL_SECTION_NAME (decl) = chosen_section;
+       }
+    }
+}
+\f
+/* Implement `va_arg'.  */
+
+rtx
+v850_va_arg (valist, type)
+     tree valist, type;
+{
+  HOST_WIDE_INT size, rsize;
+  tree addr, incr;
+  rtx addr_rtx;
+  int indirect;
+
+  /* Round up sizeof(type) to a word.  */
+  size = int_size_in_bytes (type);
+  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+  indirect = 0;
+
+  if (size > 8)
+    {
+      size = rsize = UNITS_PER_WORD;
+      indirect = 1;
+    }
+
+  addr = save_expr (valist);
+  incr = fold (build (PLUS_EXPR, ptr_type_node, addr,
+                     build_int_2 (rsize, 0)));
+
+  incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
+  TREE_SIDE_EFFECTS (incr) = 1;
+  expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
+
+  if (indirect)
+    {
+      addr_rtx = force_reg (Pmode, addr_rtx);
+      addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
+      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
+    }
+
+  return addr_rtx;
+}
+\f
+/* Return an RTX indicating where the return address to the
+   calling function can be found.  */
+
+rtx
+v850_return_addr (count)
+     int count;
+{
+  if (count != 0)
+    return const0_rtx;
+
+  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)
+    {
+      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;
+
+      switch (v850_get_data_area (exp))
+        {
+        case DATA_AREA_ZDA:
+         if (is_const)
+           rozdata_section ();
+         else
+           zdata_section ();
+         break;
+
+        case DATA_AREA_TDA:
+         tdata_section ();
+         break;
+
+        case DATA_AREA_SDA:
+         if (is_const)
+           rosdata_section ();
+         else
+           sdata_section ();
+         break;
+
+        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 ();
+}