OSDN Git Service

* alpha.h, arc.h, arm/aout.h, avr.h, cris.h, d30v.h, dsp16xx.h,
[pf3gnuchains/gcc-fork.git] / gcc / config / arc / arc.c
index c5638f1..f1efc05 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines used for code generation on the Argonaut ARC cpu.
-   Copyright (C) 1994, 1995, 1997, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -29,21 +30,24 @@ 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"
 #include "function.h"
 #include "expr.h"
 #include "recog.h"
+#include "toplev.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
 
 /* Which cpu we're compiling for (NULL(=base), ???).  */
-char *arc_cpu_string;
+const char *arc_cpu_string;
 int arc_cpu_type;
 
 /* Name of mangle string to add to symbols to separate code compiled for each
    cpu (or NULL).  */
-char *arc_mangle_cpu;
+const char *arc_mangle_cpu;
 
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
@@ -51,14 +55,14 @@ rtx arc_compare_op0, arc_compare_op1;
 
 /* Name of text, data, and rodata sections, as specified on command line.
    Selected by -m{text,data,rodata} flags.  */
-char *arc_text_string = ARC_DEFAULT_TEXT_SECTION;
-char *arc_data_string = ARC_DEFAULT_DATA_SECTION;
-char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION;
+const char *arc_text_string = ARC_DEFAULT_TEXT_SECTION;
+const char *arc_data_string = ARC_DEFAULT_DATA_SECTION;
+const char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION;
 
 /* Name of text, data, and rodata sections used in varasm.c.  */
-char *arc_text_section;
-char *arc_data_section;
-char *arc_rodata_section;
+const char *arc_text_section;
+const char *arc_data_section;
+const char *arc_rodata_section;
 
 /* Array of valid operand punctuation characters.  */
 char arc_punct_chars[256];
@@ -80,15 +84,42 @@ static int arc_ccfsm_target_label;
    arc_print_operand.  */
 static int last_insn_set_cc_p;
 static int current_insn_set_cc_p;
-static void record_cc_ref ();
-
-void arc_init_reg_tables ();
-
+static void record_cc_ref PARAMS ((rtx));
+static void arc_init_reg_tables PARAMS ((void));
+static int get_arc_condition_code PARAMS ((rtx));
+const struct attribute_spec arc_attribute_table[];
+static tree arc_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static bool arc_assemble_integer PARAMS ((rtx, unsigned int, int));
+static void arc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static void arc_encode_section_info PARAMS ((tree, int));
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER arc_assemble_integer
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE arc_attribute_table
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO arc_encode_section_info
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 /* Called by OVERRIDE_OPTIONS to initialize various things.  */
 
 void
 arc_init (void)
 {
+  char *tmp;
+  
   if (arc_cpu_string == 0
       || !strcmp (arc_cpu_string, "base"))
     {
@@ -108,12 +139,12 @@ arc_init (void)
     }
 
   /* Set the pseudo-ops for the various standard sections.  */
-  arc_text_section = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1);
-  sprintf (arc_text_section, ARC_SECTION_FORMAT, arc_text_string);
-  arc_data_section = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1);
-  sprintf (arc_data_section, ARC_SECTION_FORMAT, arc_data_string);
-  arc_rodata_section = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
-  sprintf (arc_rodata_section, ARC_SECTION_FORMAT, arc_rodata_string);
+  arc_text_section = tmp = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+  sprintf (tmp, ARC_SECTION_FORMAT, arc_text_string);
+  arc_data_section = tmp = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+  sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string);
+  arc_rodata_section = tmp = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+  sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string);
 
   arc_init_reg_tables ();
 
@@ -127,7 +158,7 @@ arc_init (void)
 }
 \f
 /* The condition codes of the ARC, and the inverse function.  */
-static char *arc_condition_codes[] =
+static const char *const arc_condition_codes[] =
 {
   "al", 0, "eq", "ne", "p", "n", "c", "nc", "v", "nv",
   "gt", "le", "ge", "lt", "hi", "ls", "pnz", 0
@@ -167,7 +198,7 @@ get_arc_condition_code (comparison)
 enum machine_mode
 arc_select_cc_mode (op, x, y)
      enum rtx_code op;
-     rtx x, y;
+     rtx x, y ATTRIBUTE_UNUSED;
 {
   switch (op)
     {
@@ -187,6 +218,8 @@ arc_select_cc_mode (op, x, y)
        case ASHIFTRT :
        case LSHIFTRT :
          return CCZNCmode;
+       default:
+         break;
        }
     }
   return CCmode;
@@ -221,7 +254,7 @@ enum arc_mode_class {
 
 /* Value is 1 if register/mode pair is acceptable on arc.  */
 
-unsigned int arc_hard_regno_mode_ok[] = {
+const unsigned int arc_hard_regno_mode_ok[] = {
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, D_MODES,
@@ -238,7 +271,7 @@ unsigned int arc_mode_class [NUM_MACHINE_MODES];
 
 enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER];
 
-void
+static void
 arc_init_reg_tables ()
 {
   int i;
@@ -305,46 +338,42 @@ arc_init_reg_tables ()
    interrupt - for interrupt functions
 */
 
-/* Return nonzero if IDENTIFIER is a valid decl attribute.  */
+const struct attribute_spec arc_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "interrupt", 1, 1, true,  false, false, arc_handle_interrupt_attribute },
+  { NULL,        0, 0, false, false, false, NULL }
+};
 
-int
-arc_valid_machine_decl_attribute (type, attributes, identifier, args)
-     tree type;
-     tree attributes;
-     tree identifier;
+/* Handle an "interrupt" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+arc_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+     tree *node ATTRIBUTE_UNUSED;
+     tree name;
      tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  if (identifier == get_identifier ("__interrupt__")
-      && list_length (args) == 1
-      && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
-    {
-      tree value = TREE_VALUE (args);
+  tree value = TREE_VALUE (args);
 
-      if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
-          || !strcmp (TREE_STRING_POINTER (value), "ilink2"))
-       return 1;
+  if (TREE_CODE (value) != STRING_CST)
+    {
+      warning ("argument of `%s' attribute is not a string constant",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (strcmp (TREE_STRING_POINTER (value), "ilink1")
+          && strcmp (TREE_STRING_POINTER (value), "ilink2"))
+    {
+      warning ("argument of `%s' attribute is not \"ilink1\" or \"ilink2\"",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
-  return 0;
-}
-
-/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible,
-   and two if they are nearly compatible (which causes a warning to be
-   generated).  */
 
-int
-arc_comp_type_attributes (type1, type2)
-     tree type1, type2;
-{
-  return 1;
+  return NULL_TREE;
 }
 
-/* Set the default attributes for TYPE.  */
-
-void
-arc_set_default_type_attributes (type)
-     tree type;
-{
-}
 \f
 /* Acceptable arguments to the call insn.  */
 
@@ -374,7 +403,7 @@ call_operand (op, mode)
 int
 symbolic_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   switch (GET_CODE (op))
     {
@@ -393,7 +422,7 @@ symbolic_operand (op, mode)
 int
 symbolic_memory_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == SUBREG)
     op = SUBREG_REG (op);
@@ -409,7 +438,7 @@ symbolic_memory_operand (op, mode)
 int
 short_immediate_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
@@ -422,7 +451,7 @@ short_immediate_operand (op, mode)
 int
 long_immediate_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   switch (GET_CODE (op))
     {
@@ -437,6 +466,8 @@ long_immediate_operand (op, mode)
         represented this way (the multiplication patterns can cause these
         to be generated).  They also occur for SFmode values.  */
       return 1;
+    default:
+      break;
     }
   return 0;
 }
@@ -450,7 +481,7 @@ long_immediate_operand (op, mode)
 int
 long_immediate_loadstore_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) != MEM)
     return 0;
@@ -480,6 +511,8 @@ long_immediate_loadstore_operand (op, mode)
          && !SMALL_INT (INTVAL (XEXP (op, 1))))
        return 1;
       return 0;
+    default:
+      break;
     }
   return 0;
 }
@@ -644,7 +677,7 @@ nonvol_nonimm_operand (op, mode)
 int
 const_sint32_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   /* All allowed constants will fit a CONST_INT.  */
   return (GET_CODE (op) == CONST_INT
@@ -658,7 +691,7 @@ const_sint32_operand (op, mode)
 int
 const_uint32_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
 #if HOST_BITS_PER_WIDE_INT > 32
   /* All allowed constants will fit a CONST_INT.  */
@@ -679,7 +712,7 @@ const_uint32_operand (op, mode)
 int
 proper_comparison_operator (op, mode)
     rtx op;
-    enum machine_mode mode;
+    enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   enum rtx_code code = GET_CODE (op);
 
@@ -759,7 +792,7 @@ void
 arc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
      CUMULATIVE_ARGS *cum;
      enum machine_mode mode;
-     tree type;
+     tree type ATTRIBUTE_UNUSED;
      int *pretend_size;
      int no_rtl;
 {
@@ -769,12 +802,8 @@ arc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
   if (mode == BLKmode)
     abort ();
 
-  /* We must treat `__builtin_va_alist' as an anonymous arg.  */
-  if (current_function_varargs)
-    first_anon_arg = *cum;
-  else
-    first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
-                            / UNITS_PER_WORD);
+  first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
+                          / UNITS_PER_WORD);
 
   if (first_anon_arg < MAX_ARC_PARM_REGS && !no_rtl)
     {
@@ -790,7 +819,8 @@ arc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
                              plus_constant (arg_pointer_rtx,
                                             FIRST_PARM_OFFSET (0)
                                             + align_slop * UNITS_PER_WORD));
-      MEM_ALIAS_SET (regblock) = get_varargs_alias_set ();
+      set_mem_alias_set (regblock, get_varargs_alias_set ());
+      set_mem_align (regblock, BITS_PER_WORD);
       move_block_from_reg (first_reg_offset, regblock,
                           MAX_ARC_PARM_REGS - first_reg_offset,
                           ((MAX_ARC_PARM_REGS - first_reg_offset)
@@ -843,6 +873,8 @@ arc_address_cost (addr)
          }
        break;
       }
+    default:
+      break;
     }
 
   return 4;
@@ -947,7 +979,7 @@ arc_compute_function_type (decl)
   fn_type = ARC_FUNCTION_NORMAL;
 
   /* Now see if this is an interrupt handler.  */
-  for (a = DECL_MACHINE_ATTRIBUTES (current_function_decl);
+  for (a = DECL_ATTRIBUTES (current_function_decl);
        a;
        a = TREE_CHAIN (a))
     {
@@ -1061,10 +1093,10 @@ arc_compute_frame_size (size)
 void
 arc_save_restore (file, base_reg, offset, gmask, op)
      FILE *file;
-     char *base_reg;
+     const char *base_reg;
      unsigned int offset;
      unsigned int gmask;
-     char *op;
+     const char *op;
 {
   int regno;
 
@@ -1082,15 +1114,37 @@ arc_save_restore (file, base_reg, offset, gmask, op)
     }
 }
 \f
+/* Target hook to assemble an integer object.  The ARC version needs to
+   emit a special directive for references to labels and function
+   symbols.  */
+
+static bool
+arc_assemble_integer (x, size, aligned_p)
+     rtx x;
+     unsigned int size;
+     int aligned_p;
+{
+  if (size == UNITS_PER_WORD && aligned_p
+      && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
+         || GET_CODE (x) == LABEL_REF))
+    {
+      fputs ("\t.word\t%st(", asm_out_file);
+      output_addr_const (asm_out_file, x);
+      fputs (")\n", asm_out_file);
+      return true;
+    }
+  return default_assemble_integer (x, size, aligned_p);
+}
+\f
 /* Set up the stack and frame pointer (if desired) for the function.  */
 
-void
+static void
 arc_output_function_prologue (file, size)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
 {
-  char *sp_str = reg_names[STACK_POINTER_REGNUM];
-  char *fp_str = reg_names[FRAME_POINTER_REGNUM];
+  const char *sp_str = reg_names[STACK_POINTER_REGNUM];
+  const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
   unsigned int gmask = current_frame_info.gmask;
   enum arc_function_type fn_type = arc_compute_function_type (current_function_decl);
 
@@ -1160,12 +1214,12 @@ arc_output_function_prologue (file, size)
 }
 \f
 /* Do any necessary cleanup after a function to restore stack, frame,
-   and regs. */
+   and regs.  */
 
-void
+static void
 arc_output_function_epilogue (file, size)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
 {
   rtx epilogue_delay = current_function_epilogue_delay_list;
   int noepilogue = FALSE;
@@ -1197,8 +1251,8 @@ arc_output_function_epilogue (file, size)
       unsigned int frame_size = size - pretend_size;
       int restored, fp_restored_p;
       int can_trust_sp_p = !current_function_calls_alloca;
-      char *sp_str = reg_names[STACK_POINTER_REGNUM];
-      char *fp_str = reg_names[FRAME_POINTER_REGNUM];
+      const char *sp_str = reg_names[STACK_POINTER_REGNUM];
+      const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
 
       /* ??? There are lots of optimizations that can be done here.
         EG: Use fp to restore regs if it's closer.
@@ -1275,7 +1329,7 @@ arc_output_function_epilogue (file, size)
 
       /* Emit the return instruction.  */
       {
-       static int regs[4] = {
+       static const int regs[4] = {
          0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM
        };
        fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]);
@@ -1381,7 +1435,7 @@ arc_finalize_pic ()
 int
 shift_operator (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   switch (GET_CODE (op))
     {
@@ -1408,15 +1462,14 @@ shift_operator (op, mode)
 /* ??? We use the loop register here.  We don't use it elsewhere (yet) and
    using it here will give us a chance to play with it.  */
 
-char *
+const char *
 output_shift (operands)
      rtx *operands;
 {
-  static int loopend_lab;
   rtx shift = operands[3];
   enum machine_mode mode = GET_MODE (shift);
   enum rtx_code code = GET_CODE (shift);
-  char *shift_one;
+  const char *shift_one;
 
   if (mode != SImode)
     abort ();
@@ -1472,6 +1525,8 @@ output_shift (operands)
              /* The ARC doesn't have a rol insn.  Use something else.  */
              output_asm_insn ("asl.f 0,%0\n\tadc %0,0,0", operands);
              break;
+           default:
+             break;
            }
        }
       /* Must loop.  */
@@ -1487,7 +1542,7 @@ output_shift (operands)
          if (optimize)
            {
              if (flag_pic)
-               sprintf ("lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start",
+               sprintf (buf, "lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start",
                         ASM_COMMENT_START);
              else
                sprintf (buf, "mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2",
@@ -1531,7 +1586,7 @@ output_shift (operands)
 
 void
 arc_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp, fnaddr, cxt;
+     rtx tramp ATTRIBUTE_UNUSED, fnaddr ATTRIBUTE_UNUSED, cxt ATTRIBUTE_UNUSED;
 {
 }
 \f
@@ -1601,9 +1656,11 @@ arc_print_operand (file, x, code)
                             arc_condition_codes[arc_ccfsm_current_cc]);
                }
              else
-               /* This insn is executed for either path, so don't
-                  conditionalize it at all.  */
-               ; /* nothing to do */
+               {
+                 /* This insn is executed for either path, so don't
+                    conditionalize it at all.  */
+                 ; /* nothing to do */
+               }
            }
          else
            {
@@ -1648,7 +1705,7 @@ arc_print_operand (file, x, code)
          fputc (']', file);
        }
       else
-       output_operand_lossage ("invalid operand to %R code");
+       output_operand_lossage ("invalid operand to %%R code");
       return;
     case 'S' :
       if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
@@ -1677,10 +1734,10 @@ arc_print_operand (file, x, code)
 
          split_double (x, &first, &second);
          fprintf (file, "0x%08lx",
-                  code == 'L' ? INTVAL (first) : INTVAL (second));
+                  (long)(code == 'L' ? INTVAL (first) : INTVAL (second)));
        }
       else
-       output_operand_lossage ("invalid operand to %H/%L code");
+       output_operand_lossage ("invalid operand to %%H/%%L code");
       return;
     case 'A' :
       {
@@ -1704,7 +1761,7 @@ arc_print_operand (file, x, code)
            fputs (".a", file);
        }
       else
-       output_operand_lossage ("invalid operand to %U code");
+       output_operand_lossage ("invalid operand to %%U code");
       return;
     case 'V' :
       /* Output cache bypass indicator for a load/store insn.  Volatile memory
@@ -1715,7 +1772,7 @@ arc_print_operand (file, x, code)
            fputs (".di", file);
        }
       else
-       output_operand_lossage ("invalid operand to %V code");
+       output_operand_lossage ("invalid operand to %%V code");
       return;
     case 0 :
       /* Do nothing special.  */
@@ -1882,8 +1939,8 @@ record_cc_ref (insn)
 void
 arc_final_prescan_insn (insn, opvec, noperands)
      rtx insn;
-     rtx *opvec;
-     int noperands;
+     rtx *opvec ATTRIBUTE_UNUSED;
+     int noperands ATTRIBUTE_UNUSED;
 {
   /* BODY will hold the body of INSN.  */
   register rtx body = PATTERN (insn);
@@ -1892,7 +1949,7 @@ arc_final_prescan_insn (insn, opvec, noperands)
      an if/then/else), and things need to be reversed.  */
   int reverse = 0;
 
-  /* If we start with a return insn, we only succeed if we find another one. */
+  /* If we start with a return insn, we only succeed if we find another one.  */
   int seeking_return = 0;
   
   /* START_INSN will hold the insn from where we start looking.  This is the
@@ -2051,7 +2108,7 @@ arc_final_prescan_insn (insn, opvec, noperands)
              /* Succeed if the following insn is the target label.
                 Otherwise fail.  
                 If return insns are used then the last insn in a function 
-                will be a barrier. */
+                will be a barrier.  */
              next_must_be_target_label_p = TRUE;
              break;
 
@@ -2070,7 +2127,7 @@ arc_final_prescan_insn (insn, opvec, noperands)
              /* If this is an unconditional branch to the same label, succeed.
                 If it is to another label, do nothing.  If it is conditional,
                 fail.  */
-             /* ??? Probably, the test for the SET and the PC are unnecessary. */
+             /* ??? Probably, the test for the SET and the PC are unnecessary.  */
 
              if (GET_CODE (scanbody) == SET
                  && GET_CODE (SET_DEST (scanbody)) == PC)
@@ -2132,7 +2189,7 @@ arc_final_prescan_insn (insn, opvec, noperands)
              if (!this_insn)
                {
                  /* Oh dear! we ran off the end, give up.  */
-                 insn_extract (insn);
+                 extract_insn_cached (insn);
                  arc_ccfsm_state = 0;
                  arc_ccfsm_target_insn = NULL;
                  return;
@@ -2152,11 +2209,10 @@ arc_final_prescan_insn (insn, opvec, noperands)
            arc_ccfsm_current_cc = ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc);
        }
 
-      /* Restore recog_operand.  Getting the attributes of other insns can
+      /* Restore recog_data.  Getting the attributes of other insns can
         destroy this array, but final.c assumes that it remains intact
-        across this call; since the insn has been recognized already we
-        call insn_extract direct. */
-      insn_extract (insn);
+        across this call.  */
+      extract_insn_cached (insn);
     }
 }
 
@@ -2167,7 +2223,7 @@ arc_final_prescan_insn (insn, opvec, noperands)
 
 void
 arc_ccfsm_at_label (prefix, num)
-     char *prefix;
+     const char *prefix;
      int num;
 {
   if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num
@@ -2205,8 +2261,7 @@ arc_ccfsm_record_branch_deleted ()
 }
 \f
 void
-arc_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p;
+arc_va_start (valist, nextarg)
      tree valist;
      rtx nextarg;
 {
@@ -2215,7 +2270,7 @@ arc_va_start (stdarg_p, valist, nextarg)
       && (current_function_args_info & 1))
     nextarg = plus_constant (nextarg, UNITS_PER_WORD);
 
-  std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+  std_expand_builtin_va_start (valist, nextarg);
 }
 
 rtx
@@ -2290,3 +2345,17 @@ arc_va_arg (valist, type)
 
   return addr_rtx;
 }
+
+/* On the ARC, function addresses are not the same as normal addresses.
+   Branch to absolute address insns take an address that is right-shifted
+   by 2.  We encode the fact that we have a function here, and then emit a
+   special assembler op when outputting the address.  */
+
+static void
+arc_encode_section_info (decl, first)
+     tree decl;
+     int first ATTRIBUTE_UNUSED;
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+}