]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/arm/arm.c
NEXT_INSN and PREV_INSN take a const rtx_insn
[thirdparty/gcc.git] / gcc / config / arm / arm.c
index d5d958ebec51d4930abe2e03f15f33d7f1320bb1..d8bfda3aa98365b3d562566f4db2273e2d737cbe 100644 (file)
@@ -92,7 +92,6 @@ static rtx arm_legitimize_address (rtx, rtx, enum machine_mode);
 static reg_class_t arm_preferred_reload_class (rtx, reg_class_t);
 static rtx thumb_legitimize_address (rtx, rtx, enum machine_mode);
 inline static int thumb1_index_register_rtx_p (rtx, int);
-static bool arm_legitimate_address_p (enum machine_mode, rtx, bool);
 static int thumb_far_jump_used_p (void);
 static bool thumb_force_lr_save (void);
 static unsigned arm_size_return_regs (void);
@@ -109,21 +108,21 @@ static const char *output_multi_immediate (rtx *, const char *, const char *,
 static const char *shift_op (rtx, HOST_WIDE_INT *);
 static struct machine_function *arm_init_machine_status (void);
 static void thumb_exit (FILE *, int);
-static HOST_WIDE_INT get_jump_table_size (rtx);
+static HOST_WIDE_INT get_jump_table_size (rtx_jump_table_data *);
 static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
 static Mnode *add_minipool_forward_ref (Mfix *);
 static Mnode *move_minipool_fix_backward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
 static Mnode *add_minipool_backward_ref (Mfix *);
 static void assign_minipool_offsets (Mfix *);
 static void arm_print_value (FILE *, rtx);
-static void dump_minipool (rtx);
+static void dump_minipool (rtx_insn *);
 static int arm_barrier_cost (rtx);
 static Mfix *create_fix_barrier (Mfix *, HOST_WIDE_INT);
-static void push_minipool_barrier (rtx, HOST_WIDE_INT);
-static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
-                              rtx);
+static void push_minipool_barrier (rtx_insn *, HOST_WIDE_INT);
+static void push_minipool_fix (rtx_insn *, HOST_WIDE_INT, rtx *,
+                              enum machine_mode, rtx);
 static void arm_reorg (void);
-static void note_invalid_constants (rtx, HOST_WIDE_INT, int);
+static void note_invalid_constants (rtx_insn *, HOST_WIDE_INT, int);
 static unsigned long arm_compute_save_reg0_reg12_mask (void);
 static unsigned long arm_compute_save_reg_mask (void);
 static unsigned long arm_isr_value (tree);
@@ -138,8 +137,8 @@ static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
 static void arm_set_default_type_attributes (tree);
-static int arm_adjust_cost (rtx, rtx, rtx, int);
-static int arm_sched_reorder (FILE *, int, rtx *, int *, int);
+static int arm_adjust_cost (rtx_insn *, rtx, rtx_insn *, int);
+static int arm_sched_reorder (FILE *, int, rtx_insn **, int *, int);
 static int optimal_immediate_sequence (enum rtx_code code,
                                       unsigned HOST_WIDE_INT val,
                                       struct four_ints *return_sequence);
@@ -181,7 +180,7 @@ static rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
 static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static tree arm_builtin_decl (unsigned, bool);
 static void emit_constant_insn (rtx cond, rtx pattern);
-static rtx emit_set_insn (rtx, rtx);
+static rtx_insn *emit_set_insn (rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
 static int arm_arg_partial_bytes (cumulative_args_t, enum machine_mode,
                                  tree, bool);
@@ -217,7 +216,7 @@ static bool arm_return_in_msb (const_tree);
 static bool arm_must_pass_in_stack (enum machine_mode, const_tree);
 static bool arm_return_in_memory (const_tree, const_tree);
 #if ARM_UNWIND_INFO
-static void arm_unwind_emit (FILE *, rtx);
+static void arm_unwind_emit (FILE *, rtx_insn *);
 static bool arm_output_ttype (rtx);
 static void arm_asm_emit_except_personality (rtx);
 static void arm_asm_init_sections (void);
@@ -239,7 +238,7 @@ static void arm_expand_builtin_va_start (tree, rtx);
 static tree arm_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 static void arm_option_override (void);
 static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
-static bool arm_cannot_copy_insn_p (rtx);
+static bool arm_cannot_copy_insn_p (rtx_insn *);
 static int arm_issue_rate (void);
 static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static bool arm_output_addr_const_extra (FILE *, rtx);
@@ -685,6 +684,9 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_CONST_NOT_OK_FOR_DEBUG_P
 #define TARGET_CONST_NOT_OK_FOR_DEBUG_P arm_const_not_ok_for_debug_p
 
+#undef TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
+#define TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS true
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Obstack for minipool constant handling.  */
@@ -1174,6 +1176,107 @@ const struct cpu_cost_table cortexa8_extra_costs =
   }
 };
 
+const struct cpu_cost_table cortexa5_extra_costs =
+{
+  /* ALU */
+  {
+    0,                 /* arith.  */
+    0,                 /* logical.  */
+    COSTS_N_INSNS (1), /* shift.  */
+    COSTS_N_INSNS (1), /* shift_reg.  */
+    COSTS_N_INSNS (1), /* arith_shift.  */
+    COSTS_N_INSNS (1), /* arith_shift_reg.  */
+    COSTS_N_INSNS (1), /* log_shift.  */
+    COSTS_N_INSNS (1), /* log_shift_reg.  */
+    COSTS_N_INSNS (1), /* extend.  */
+    COSTS_N_INSNS (1), /* extend_arith.  */
+    COSTS_N_INSNS (1), /* bfi.  */
+    COSTS_N_INSNS (1), /* bfx.  */
+    COSTS_N_INSNS (1), /* clz.  */
+    COSTS_N_INSNS (1), /* rev.  */
+    0,                 /* non_exec.  */
+    true               /* non_exec_costs_exec.  */
+  },
+
+  {
+    /* MULT SImode */
+    {
+      0,                       /* simple.  */
+      COSTS_N_INSNS (1),       /* flag_setting.  */
+      COSTS_N_INSNS (1),       /* extend.  */
+      COSTS_N_INSNS (1),       /* add.  */
+      COSTS_N_INSNS (1),       /* extend_add.  */
+      COSTS_N_INSNS (7)                /* idiv.  */
+    },
+    /* MULT DImode */
+    {
+      0,                       /* simple (N/A).  */
+      0,                       /* flag_setting (N/A).  */
+      COSTS_N_INSNS (1),       /* extend.  */
+      0,                       /* add.  */
+      COSTS_N_INSNS (2),       /* extend_add.  */
+      0                                /* idiv (N/A).  */
+    }
+  },
+  /* LD/ST */
+  {
+    COSTS_N_INSNS (1), /* load.  */
+    COSTS_N_INSNS (1), /* load_sign_extend.  */
+    COSTS_N_INSNS (6), /* ldrd.  */
+    COSTS_N_INSNS (1), /* ldm_1st.  */
+    1,                 /* ldm_regs_per_insn_1st.  */
+    2,                 /* ldm_regs_per_insn_subsequent.  */
+    COSTS_N_INSNS (2), /* loadf.  */
+    COSTS_N_INSNS (4), /* loadd.  */
+    COSTS_N_INSNS (1), /* load_unaligned.  */
+    COSTS_N_INSNS (1), /* store.  */
+    COSTS_N_INSNS (3), /* strd.  */
+    COSTS_N_INSNS (1), /* stm_1st.  */
+    1,                 /* stm_regs_per_insn_1st.  */
+    2,                 /* stm_regs_per_insn_subsequent.  */
+    COSTS_N_INSNS (2), /* storef.  */
+    COSTS_N_INSNS (2), /* stored.  */
+    COSTS_N_INSNS (1)  /* store_unaligned.  */
+  },
+  {
+    /* FP SFmode */
+    {
+      COSTS_N_INSNS (15),      /* div.  */
+      COSTS_N_INSNS (3),       /* mult.  */
+      COSTS_N_INSNS (7),       /* mult_addsub. */
+      COSTS_N_INSNS (7),       /* fma.  */
+      COSTS_N_INSNS (3),       /* addsub.  */
+      COSTS_N_INSNS (3),       /* fpconst.  */
+      COSTS_N_INSNS (3),       /* neg.  */
+      COSTS_N_INSNS (3),       /* compare.  */
+      COSTS_N_INSNS (3),       /* widen.  */
+      COSTS_N_INSNS (3),       /* narrow.  */
+      COSTS_N_INSNS (3),       /* toint.  */
+      COSTS_N_INSNS (3),       /* fromint.  */
+      COSTS_N_INSNS (3)                /* roundint.  */
+    },
+    /* FP DFmode */
+    {
+      COSTS_N_INSNS (30),      /* div.  */
+      COSTS_N_INSNS (6),       /* mult.  */
+      COSTS_N_INSNS (10),      /* mult_addsub.  */
+      COSTS_N_INSNS (7),       /* fma.  */
+      COSTS_N_INSNS (3),       /* addsub.  */
+      COSTS_N_INSNS (3),       /* fpconst.  */
+      COSTS_N_INSNS (3),       /* neg.  */
+      COSTS_N_INSNS (3),       /* compare.  */
+      COSTS_N_INSNS (3),       /* widen.  */
+      COSTS_N_INSNS (3),       /* narrow.  */
+      COSTS_N_INSNS (3),       /* toint.  */
+      COSTS_N_INSNS (3),       /* fromint.  */
+      COSTS_N_INSNS (3)                /* roundint.  */
+    }
+  },
+  /* Vector */
+  {
+    COSTS_N_INSNS (1)  /* alu.  */
+  }
+};
 
 
 const struct cpu_cost_table cortexa7_extra_costs =
@@ -1795,7 +1898,7 @@ const struct tune_params arm_cortex_a57_tune =
 const struct tune_params arm_cortex_a5_tune =
 {
   arm_9e_rtx_costs,
-  NULL,
+  &cortexa5_extra_costs,
   NULL,                                                /* Sched adj cost.  */
   1,                                           /* Constant limit.  */
   1,                                           /* Max cond insns.  */
@@ -1972,7 +2075,7 @@ arm_constant_limit (bool size_p)
 
 /* Emit an insn that's a simple single-set.  Both the operands must be known
    to be valid.  */
-inline static rtx
+inline static rtx_insn *
 emit_set_insn (rtx x, rtx y)
 {
   return emit_insn (gen_rtx_SET (VOIDmode, x, y));
@@ -2616,10 +2719,6 @@ arm_option_override (void)
   if (TARGET_APCS_FLOAT)
     warning (0, "passing floating point arguments in fp regs not yet supported");
 
-  if (TARGET_LITTLE_WORDS)
-    warning (OPT_Wdeprecated, "%<mwords-little-endian%> is deprecated and "
-            "will be removed in a future release");
-
   /* Initialize boolean versions of the flags, for use in the arm.md file.  */
   arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
   arm_arch4 = (insn_flags & FL_ARCH4) != 0;
@@ -2890,6 +2989,10 @@ arm_option_override (void)
       /* If optimizing for size, bump the number of instructions that we
          are prepared to conditionally execute (even on a StrongARM).  */
       max_insns_skipped = 6;
+
+      /* For THUMB2, we limit the conditional sequence to one IT block.  */
+      if (TARGET_THUMB2)
+       max_insns_skipped = MAX_INSN_PER_IT_BLOCK;
     }
   else
     max_insns_skipped = current_tune->max_insns_skipped;
@@ -4658,25 +4761,25 @@ libcall_hasher::hash (const value_type *p1)
   return hash_rtx (p1, VOIDmode, NULL, NULL, FALSE);
 }
 
-typedef hash_table <libcall_hasher> libcall_table_type;
+typedef hash_table<libcall_hasher> libcall_table_type;
 
 static void
-add_libcall (libcall_table_type htab, rtx libcall)
+add_libcall (libcall_table_type *htab, rtx libcall)
 {
-  *htab.find_slot (libcall, INSERT) = libcall;
+  *htab->find_slot (libcall, INSERT) = libcall;
 }
 
 static bool
 arm_libcall_uses_aapcs_base (const_rtx libcall)
 {
   static bool init_done = false;
-  static libcall_table_type libcall_htab;
+  static libcall_table_type *libcall_htab = NULL;
 
   if (!init_done)
     {
       init_done = true;
 
-      libcall_htab.create (31);
+      libcall_htab = new libcall_table_type (31);
       add_libcall (libcall_htab,
                   convert_optab_libfunc (sfloat_optab, SFmode, SImode));
       add_libcall (libcall_htab,
@@ -4735,7 +4838,7 @@ arm_libcall_uses_aapcs_base (const_rtx libcall)
                                                        DFmode));
     }
 
-  return libcall && libcall_htab.find (libcall) != NULL;
+  return libcall && libcall_htab->find (libcall) != NULL;
 }
 
 static rtx
@@ -5032,7 +5135,7 @@ arm_get_pcs_model (const_tree type, const_tree decl)
             so we are free to use whatever conventions are
             appropriate.  */
          /* FIXME: remove CONST_CAST_TREE when cgraph is constified.  */
-         struct cgraph_local_info *i = cgraph_local_info (CONST_CAST_TREE(decl));
+         cgraph_local_info *i = cgraph_node::local_info (CONST_CAST_TREE(decl));
          if (i && i->local)
            return ARM_PCS_AAPCS_LOCAL;
        }
@@ -6313,7 +6416,7 @@ require_pic_register (void)
        }
       else
        {
-         rtx seq, insn;
+         rtx_insn *seq, *insn;
 
          if (!cfun->machine->pic_reg)
            cfun->machine->pic_reg = gen_reg_rtx (Pmode);
@@ -11341,7 +11444,7 @@ xscale_sched_adjust_cost (rtx insn, rtx link, rtx dep, int * cost)
             that overlaps with SHIFTED_OPERAND, then we have increase the
             cost of this dependency.  */
          extract_insn (dep);
-         preprocess_constraints ();
+         preprocess_constraints (dep);
          for (opno = 0; opno < recog_data.n_operands; opno++)
            {
              /* We can ignore strict inputs.  */
@@ -11611,8 +11714,9 @@ cortexa7_older_only (rtx insn)
 
   switch (get_attr_type (insn))
     {
-    case TYPE_ALU_REG:
-    case TYPE_ALUS_REG:
+    case TYPE_ALU_DSP_REG:
+    case TYPE_ALU_SREG:
+    case TYPE_ALUS_SREG:
     case TYPE_LOGIC_REG:
     case TYPE_LOGICS_REG:
     case TYPE_ADC_REG:
@@ -11693,8 +11797,8 @@ cortexa7_younger (FILE *file, int verbose, rtx insn)
    instructions.  This heuristic may affect dual issue opportunities
    in the current cycle.  */
 static void
-cortexa7_sched_reorder (FILE *file, int verbose, rtx *ready, int *n_readyp,
-                        int clock)
+cortexa7_sched_reorder (FILE *file, int verbose, rtx_insn **ready,
+                       int *n_readyp, int clock)
 {
   int i;
   int first_older_only = -1, first_younger = -1;
@@ -11711,7 +11815,7 @@ cortexa7_sched_reorder (FILE *file, int verbose, rtx *ready, int *n_readyp,
      older.  */
   for (i = *n_readyp - 1; i >= 0; i--)
     {
-      rtx insn = ready[i];
+      rtx_insn *insn = ready[i];
       if (cortexa7_older_only (insn))
         {
           first_older_only = i;
@@ -11746,7 +11850,7 @@ cortexa7_sched_reorder (FILE *file, int verbose, rtx *ready, int *n_readyp,
     fprintf (file, ";; cortexa7_sched_reorder insn %d before %d\n",
              INSN_UID(ready [first_older_only]),
              INSN_UID(ready [first_younger]));
-  rtx first_older_only_insn = ready [first_older_only];
+  rtx_insn *first_older_only_insn = ready [first_older_only];
   for (i = first_older_only; i < first_younger; i++)
     {
       ready[i] = ready[i+1];
@@ -11758,7 +11862,7 @@ cortexa7_sched_reorder (FILE *file, int verbose, rtx *ready, int *n_readyp,
 
 /* Implement TARGET_SCHED_REORDER. */
 static int
-arm_sched_reorder (FILE *file, int verbose, rtx *ready, int *n_readyp,
+arm_sched_reorder (FILE *file, int verbose, rtx_insn **ready, int *n_readyp,
                    int clock)
 {
   switch (arm_tune)
@@ -11782,7 +11886,7 @@ arm_sched_reorder (FILE *file, int verbose, rtx *ready, int *n_readyp,
    adjust_cost function. Only put bits of code into arm_adjust_cost that
    are common across all cores.  */
 static int
-arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
+arm_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep, int cost)
 {
   rtx i_pat, d_pat;
 
@@ -12792,7 +12896,11 @@ neon_vector_mem_operand (rtx op, int type, bool strict)
       || (type == 0 && GET_CODE (ind) == PRE_DEC))
     return arm_address_register_rtx_p (XEXP (ind, 0), 0);
 
-  /* FIXME: vld1 allows register post-modify.  */
+  /* Allow post-increment by register for VLDn */
+  if (type == 2 && GET_CODE (ind) == POST_MODIFY
+      && GET_CODE (XEXP (ind, 1)) == PLUS
+      && REG_P (XEXP (XEXP (ind, 1), 1)))
+     return true;
 
   /* Match:
      (plus (reg)
@@ -13007,7 +13115,7 @@ arm_note_pic_base (rtx *x, void *date ATTRIBUTE_UNUSED)
 }
 
 static bool
-arm_cannot_copy_insn_p (rtx insn)
+arm_cannot_copy_insn_p (rtx_insn *insn)
 {
   /* The tls call insn cannot be copied, as it is paired with a data
      word.  */
@@ -15983,7 +16091,7 @@ struct minipool_node
 struct minipool_fixup
 {
   Mfix *            next;
-  rtx               insn;
+  rtx_insn *        insn;
   HOST_WIDE_INT     address;
   rtx *             loc;
   enum machine_mode mode;
@@ -16014,7 +16122,7 @@ Mfix *          minipool_barrier;
 #endif
 
 static HOST_WIDE_INT
-get_jump_table_size (rtx insn)
+get_jump_table_size (rtx_jump_table_data *insn)
 {
   /* ADDR_VECs only take room if read-only data does into the text
      section.  */
@@ -16463,7 +16571,7 @@ assign_minipool_offsets (Mfix *barrier)
 
 /* Output the literal table */
 static void
-dump_minipool (rtx scan)
+dump_minipool (rtx_insn *scan)
 {
   Mnode * mp;
   Mnode * nmp;
@@ -16586,23 +16694,23 @@ static Mfix *
 create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
 {
   HOST_WIDE_INT count = 0;
-  rtx barrier;
-  rtx from = fix->insn;
+  rtx_barrier *barrier;
+  rtx_insn *from = fix->insn;
   /* The instruction after which we will insert the jump.  */
-  rtx selected = NULL;
+  rtx_insn *selected = NULL;
   int selected_cost;
   /* The address at which the jump instruction will be placed.  */
   HOST_WIDE_INT selected_address;
   Mfix * new_fix;
   HOST_WIDE_INT max_count = max_address - fix->address;
-  rtx label = gen_label_rtx ();
+  rtx_code_label *label = gen_label_rtx ();
 
   selected_cost = arm_barrier_cost (from);
   selected_address = fix->address;
 
   while (from && count < max_count)
     {
-      rtx tmp;
+      rtx_jump_table_data *tmp;
       int new_cost;
 
       /* This code shouldn't have been called if there was a natural barrier
@@ -16659,7 +16767,7 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
      CALL_ARG_LOCATION note.  */
   if (CALL_P (selected))
     {
-      rtx next = NEXT_INSN (selected);
+      rtx_insn *next = NEXT_INSN (selected);
       if (next && NOTE_P (next)
          && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION)
          selected = next;
@@ -16684,7 +16792,7 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
 /* Record that there is a natural barrier in the insn stream at
    ADDRESS.  */
 static void
-push_minipool_barrier (rtx insn, HOST_WIDE_INT address)
+push_minipool_barrier (rtx_insn *insn, HOST_WIDE_INT address)
 {
   Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
 
@@ -16706,7 +16814,7 @@ push_minipool_barrier (rtx insn, HOST_WIDE_INT address)
    fixing; VALUE is the constant that must be loaded, which is of type
    MODE.  */
 static void
-push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
+push_minipool_fix (rtx_insn *insn, HOST_WIDE_INT address, rtx *loc,
                   enum machine_mode mode, rtx value)
 {
   Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
@@ -16862,7 +16970,7 @@ arm_const_double_by_immediates (rtx val)
    If DO_PUSHES is false we do not actually push any of the fixups
    needed.  */
 static void
-note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
+note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
 {
   int opno;
 
@@ -16876,7 +16984,7 @@ note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
 
   /* Fill in recog_op_alt with information about the constraints of
      this insn.  */
-  preprocess_constraints ();
+  preprocess_constraints (insn);
 
   const operand_alternative *op_alt = which_op_alt ();
   for (opno = 0; opno < recog_data.n_operands; opno++)
@@ -16939,14 +17047,15 @@ thumb1_reorg (void)
     {
       rtx dest, src;
       rtx pat, op0, set = NULL;
-      rtx prev, insn = BB_END (bb);
+      rtx_insn *prev, *insn = BB_END (bb);
       bool insn_clobbered = false;
 
       while (insn != BB_HEAD (bb) && !NONDEBUG_INSN_P (insn))
        insn = PREV_INSN (insn);
 
       /* Find the last cbranchsi4_insn in basic block BB.  */
-      if (INSN_CODE (insn) != CODE_FOR_cbranchsi4_insn)
+      if (insn == BB_HEAD (bb)
+         || INSN_CODE (insn) != CODE_FOR_cbranchsi4_insn)
        continue;
 
       /* Get the register with which we are comparing.  */
@@ -17021,7 +17130,7 @@ thumb2_reorg (void)
          && optimize_bb_for_speed_p (bb))
        continue;
 
-      rtx insn;
+      rtx_insn *insn;
       Convert_Action action = SKIP;
       Convert_Action action_for_partial_flag_setting
        = (current_tune->disparage_partial_flag_setting_t16_encodings
@@ -17215,7 +17324,7 @@ thumb2_reorg (void)
 static void
 arm_reorg (void)
 {
-  rtx insn;
+  rtx_insn *insn;
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
@@ -17246,7 +17355,7 @@ arm_reorg (void)
        push_minipool_barrier (insn, address);
       else if (INSN_P (insn))
        {
-         rtx table;
+         rtx_jump_table_data *table;
 
          note_invalid_constants (insn, address, true);
          address += get_attr_length (insn);
@@ -17610,7 +17719,7 @@ vfp_emit_fstmd (int base_reg, int count)
    the call target.  */
 
 void
-arm_emit_call_insn (rtx pat, rtx addr)
+arm_emit_call_insn (rtx pat, rtx addr, bool sibcall)
 {
   rtx insn;
 
@@ -17621,6 +17730,7 @@ arm_emit_call_insn (rtx pat, rtx addr)
      to the instruction's CALL_INSN_FUNCTION_USAGE.  */
   if (TARGET_VXWORKS_RTP
       && flag_pic
+      && !sibcall
       && GET_CODE (addr) == SYMBOL_REF
       && (SYMBOL_REF_DECL (addr)
          ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
@@ -17629,6 +17739,16 @@ arm_emit_call_insn (rtx pat, rtx addr)
       require_pic_register ();
       use_reg (&CALL_INSN_FUNCTION_USAGE (insn), cfun->machine->pic_reg);
     }
+
+  if (TARGET_AAPCS_BASED)
+    {
+      /* For AAPCS, IP and CC can be clobbered by veneers inserted by the
+        linker.  We need to add an IP clobber to allow setting
+        TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS to true.  A CC clobber
+        is not needed since it's a fixed register.  */
+      rtx *fusage = &CALL_INSN_FUNCTION_USAGE (insn);
+      clobber_reg (fusage, gen_rtx_REG (word_mode, IP_REGNUM));
+    }
 }
 
 /* Output a 'call' insn.  */
@@ -20665,30 +20785,47 @@ arm_get_frame_offsets (void)
        {
          int reg = -1;
 
+         /* Register r3 is caller-saved.  Normally it does not need to be
+            saved on entry by the prologue.  However if we choose to save
+            it for padding then we may confuse the compiler into thinking
+            a prologue sequence is required when in fact it is not.  This
+            will occur when shrink-wrapping if r3 is used as a scratch
+            register and there are no other callee-saved writes.
+
+            This situation can be avoided when other callee-saved registers
+            are available and r3 is not mandatory if we choose a callee-saved
+            register for padding.  */
+         bool prefer_callee_reg_p = false;
+
          /* If it is safe to use r3, then do so.  This sometimes
             generates better code on Thumb-2 by avoiding the need to
             use 32-bit push/pop instructions.  */
           if (! any_sibcall_could_use_r3 ()
              && arm_size_return_regs () <= 12
              && (offsets->saved_regs_mask & (1 << 3)) == 0
-              && (TARGET_THUMB2
+             && (TARGET_THUMB2
                  || !(TARGET_LDRD && current_tune->prefer_ldrd_strd)))
            {
              reg = 3;
+             if (!TARGET_THUMB2)
+               prefer_callee_reg_p = true;
+           }
+         if (reg == -1
+             || prefer_callee_reg_p)
+           {
+             for (i = 4; i <= (TARGET_THUMB1 ? LAST_LO_REGNUM : 11); i++)
+               {
+                 /* Avoid fixed registers; they may be changed at
+                    arbitrary times so it's unsafe to restore them
+                    during the epilogue.  */
+                 if (!fixed_regs[i]
+                     && (offsets->saved_regs_mask & (1 << i)) == 0)
+                   {
+                     reg = i;
+                     break;
+                   }
+               }
            }
-         else
-           for (i = 4; i <= (TARGET_THUMB1 ? LAST_LO_REGNUM : 11); i++)
-             {
-               /* Avoid fixed registers; they may be changed at
-                  arbitrary times so it's unsafe to restore them
-                  during the epilogue.  */
-               if (!fixed_regs[i]
-                   && (offsets->saved_regs_mask & (1 << i)) == 0)
-                 {
-                   reg = i;
-                   break;
-                 }
-             }
 
          if (reg != -1)
            {
@@ -21188,7 +21325,7 @@ arm_expand_prologue (void)
     {
       /* This add can produce multiple insns for a large constant, so we
         need to get tricky.  */
-      rtx last = get_last_insn ();
+      rtx_insn *last = get_last_insn ();
 
       amount = GEN_INT (offsets->saved_args + saved_regs
                        - offsets->outgoing_args);
@@ -21823,6 +21960,7 @@ arm_print_operand (FILE *stream, rtx x, int code)
       {
        rtx addr;
        bool postinc = FALSE;
+       rtx postinc_reg = NULL;
        unsigned align, memsize, align_bits;
 
        gcc_assert (MEM_P (x));
@@ -21832,6 +21970,11 @@ arm_print_operand (FILE *stream, rtx x, int code)
            postinc = 1;
            addr = XEXP (addr, 0);
          }
+       if (GET_CODE (addr) == POST_MODIFY)
+         {
+           postinc_reg = XEXP( XEXP (addr, 1), 1);
+           addr = XEXP (addr, 0);
+         }
        asm_fprintf (stream, "[%r", REGNO (addr));
 
        /* We know the alignment of this access, so we can emit a hint in the
@@ -21857,6 +22000,8 @@ arm_print_operand (FILE *stream, rtx x, int code)
 
        if (postinc)
          fputs("!", stream);
+       if (postinc_reg)
+         asm_fprintf (stream, ", %r", REGNO (postinc_reg));
       }
       return;
 
@@ -22424,9 +22569,9 @@ get_arm_condition_code (rtx comparison)
 /* Tell arm_asm_output_opcode to output IT blocks for conditionally executed
    instructions.  */
 void
-thumb2_final_prescan_insn (rtx insn)
+thumb2_final_prescan_insn (rtx_insn *insn)
 {
-  rtx first_insn = insn;
+  rtx_insn *first_insn = insn;
   rtx body = PATTERN (insn);
   rtx predicate;
   enum arm_cond_code code;
@@ -22508,7 +22653,7 @@ thumb2_final_prescan_insn (rtx insn)
 }
 
 void
-arm_final_prescan_insn (rtx insn)
+arm_final_prescan_insn (rtx_insn *insn)
 {
   /* BODY will hold the body of INSN.  */
   rtx body = PATTERN (insn);
@@ -22523,7 +22668,7 @@ arm_final_prescan_insn (rtx insn)
 
   /* START_INSN will hold the insn from where we start looking.  This is the
      first insn after the following code_label if REVERSE is true.  */
-  rtx start_insn = insn;
+  rtx_insn *start_insn = insn;
 
   /* If in state 4, check if the target branch is reached, in order to
      change back to state 0.  */
@@ -22595,7 +22740,8 @@ arm_final_prescan_insn (rtx insn)
       int fail = FALSE, succeed = FALSE;
       /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
       int then_not_else = TRUE;
-      rtx this_insn = start_insn, label = 0;
+      rtx_insn *this_insn = start_insn;
+      rtx label = 0;
 
       /* Register the insn jumped to.  */
       if (reverse)
@@ -22824,6 +22970,9 @@ arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
            || (TARGET_HARD_FLOAT && TARGET_VFP
                && regno == VFPCC_REGNUM));
 
+  if (regno == CC_REGNUM && GET_MODE_CLASS (mode) != MODE_CC)
+    return false;
+
   if (TARGET_THUMB1)
     /* For the Thumb we only allow values bigger than SImode in
        registers 0 - 6, so that there is always a second low
@@ -22920,6 +23069,9 @@ arm_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
 enum reg_class
 arm_regno_class (int regno)
 {
+  if (regno == PC_REGNUM)
+    return NO_REGS;
+
   if (TARGET_THUMB1)
     {
       if (regno == STACK_POINTER_REGNUM)
@@ -22966,7 +23118,7 @@ arm_regno_class (int regno)
 int
 arm_debugger_arg_offset (int value, rtx addr)
 {
-  rtx insn;
+  rtx_insn *insn;
 
   /* We are only interested if dbxout_parms() failed to compute the offset.  */
   if (value != 0)
@@ -24243,8 +24395,8 @@ static const struct builtin_description bdesc_2arg[] =
   {0, CODE_FOR_##L, "__builtin_arm_"#L, ARM_BUILTIN_##U, \
    UNKNOWN, 0},
 
-  FP_BUILTIN (set_fpscr, GET_FPSCR)
-  FP_BUILTIN (get_fpscr, SET_FPSCR)
+  FP_BUILTIN (get_fpscr, GET_FPSCR)
+  FP_BUILTIN (set_fpscr, SET_FPSCR)
 #undef FP_BUILTIN
 
 #define CRC32_BUILTIN(L, U) \
@@ -24762,7 +24914,7 @@ arm_init_builtins (void)
   if (TARGET_CRC32)
     arm_init_crc32_builtins ();
 
-  if (TARGET_VFP)
+  if (TARGET_VFP && TARGET_HARD_FLOAT)
     {
       tree ftype_set_fpscr
        = build_function_type_list (void_type_node, unsigned_type_node, NULL);
@@ -26000,11 +26152,12 @@ number_of_first_bit_set (unsigned mask)
    to be saved; REAL_REGS is the set of registers to be described as
    saved.  If REAL_REGS is 0, only describe the stack adjustment.  */
 
-static rtx
+static rtx_insn *
 thumb1_emit_multi_reg_push (unsigned long mask, unsigned long real_regs)
 {
   unsigned long regno;
-  rtx par[10], tmp, reg, insn;
+  rtx par[10], tmp, reg;
+  rtx_insn *insn;
   int i, j;
 
   /* Build the parallel of the registers actually being stored.  */
@@ -26400,7 +26553,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
    For Thumb-1, we track the status of the condition codes; this
    information is used in the cbranchsi4_insn pattern.  */
 void
-thumb1_final_prescan_insn (rtx insn)
+thumb1_final_prescan_insn (rtx_insn *insn)
 {
   if (flag_print_asm_name)
     asm_fprintf (asm_out_file, "%@ 0x%04x\n",
@@ -26469,7 +26622,7 @@ thumb_shiftable_const (unsigned HOST_WIDE_INT val)
 static int
 thumb_far_jump_used_p (void)
 {
-  rtx insn;
+  rtx_insn *insn;
   bool far_jump = false;
   unsigned int func_size = 0;
 
@@ -26918,7 +27071,7 @@ thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
 void
 thumb1_expand_prologue (void)
 {
-  rtx insn;
+  rtx_insn *insn;
 
   HOST_WIDE_INT amount;
   arm_stack_offsets *offsets;
@@ -27370,7 +27523,7 @@ arm_expand_epilogue_apcs_frame (bool really_return)
       int saved_size = arm_get_vfp_saved_size ();
       if (saved_size > 0)
         {
-         rtx insn;
+         rtx_insn *insn;
           floats_from_frame += saved_size;
           insn = emit_insn (gen_addsi3 (ip_rtx,
                                        hard_frame_pointer_rtx,
@@ -27409,7 +27562,7 @@ arm_expand_epilogue_apcs_frame (bool really_return)
     {
       /* The frame pointer is guaranteed to be non-double-word aligned, as
          it is set to double-word-aligned old_stack_pointer - 4.  */
-      rtx insn;
+      rtx_insn *insn;
       int lrm_count = (num_regs % 2) ? (num_regs + 2) : (num_regs + 1);
 
       for (i = LAST_IWMMXT_REGNUM; i >= FIRST_IWMMXT_REGNUM; i--)
@@ -27449,7 +27602,7 @@ arm_expand_epilogue_apcs_frame (bool really_return)
   num_regs = bit_count (saved_regs_mask);
   if ((offsets->outgoing_args != (1 + num_regs)) || cfun->calls_alloca)
     {
-      rtx insn;
+      rtx_insn *insn;
       emit_insn (gen_blockage ());
       /* Unwind the stack to just below the saved registers.  */
       insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
@@ -27466,7 +27619,7 @@ arm_expand_epilogue_apcs_frame (bool really_return)
     {
       /* Interrupt handlers will have pushed the
          IP onto the stack, so restore it now.  */
-      rtx insn;
+      rtx_insn *insn;
       rtx addr = gen_rtx_MEM (SImode,
                               gen_rtx_POST_INC (SImode,
                               stack_pointer_rtx));
@@ -27535,7 +27688,7 @@ arm_expand_epilogue (bool really_return)
 
   if (frame_pointer_needed)
     {
-      rtx insn;
+      rtx_insn *insn;
       /* Restore stack pointer if necessary.  */
       if (TARGET_ARM)
         {
@@ -27592,7 +27745,7 @@ arm_expand_epilogue (bool really_return)
       amount = offsets->outgoing_args - offsets->saved_regs;
       if (amount)
         {
-         rtx tmp;
+         rtx_insn *tmp;
           /* Force out any pending memory operations that reference stacked data
              before stack de-allocation occurs.  */
           emit_insn (gen_blockage ());
@@ -27644,7 +27797,7 @@ arm_expand_epilogue (bool really_return)
     for (i = FIRST_IWMMXT_REGNUM; i <= LAST_IWMMXT_REGNUM; i++)
       if (df_regs_ever_live_p (i) && !call_used_regs[i])
         {
-          rtx insn;
+          rtx_insn *insn;
           rtx addr = gen_rtx_MEM (V2SImode,
                                   gen_rtx_POST_INC (SImode,
                                                     stack_pointer_rtx));
@@ -27733,9 +27886,10 @@ arm_expand_epilogue (bool really_return)
     {
       int i, j;
       rtx dwarf = NULL_RTX;
-      rtx tmp = emit_insn (gen_addsi3 (stack_pointer_rtx,
-                          stack_pointer_rtx,
-                          GEN_INT (crtl->args.pretend_args_size)));
+      rtx_insn *tmp =
+       emit_insn (gen_addsi3 (stack_pointer_rtx,
+                              stack_pointer_rtx,
+                              GEN_INT (crtl->args.pretend_args_size)));
 
       RTX_FRAME_RELATED_P (tmp) = 1;
 
@@ -28428,9 +28582,13 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
       fputs (":\n", file);
       if (flag_pic)
        {
-         /* Output ".word .LTHUNKn-7-.LTHUNKPCn".  */
+         /* Output ".word .LTHUNKn-[3,7]-.LTHUNKPCn".  */
          rtx tem = XEXP (DECL_RTL (function), 0);
-         tem = plus_constant (GET_MODE (tem), tem, -7);
+         /* For TARGET_THUMB1_ONLY the thunk is in Thumb mode, so the PC
+            pipeline offset is four rather than eight.  Adjust the offset
+            accordingly.  */
+         tem = plus_constant (GET_MODE (tem), tem,
+                              TARGET_THUMB1_ONLY ? -3 : -7);
          tem = gen_rtx_MINUS (GET_MODE (tem),
                               tem,
                               gen_rtx_SYMBOL_REF (Pmode,
@@ -29195,7 +29353,7 @@ arm_unwind_emit_set (FILE * asm_out_file, rtx p)
 /* Emit unwind directives for the given insn.  */
 
 static void
-arm_unwind_emit (FILE * asm_out_file, rtx insn)
+arm_unwind_emit (FILE * asm_out_file, rtx_insn *insn)
 {
   rtx note, pat;
   bool handled_one = false;
@@ -29581,7 +29739,7 @@ arm_output_iwmmxt_tinsr (rtx *operands)
 const char *
 thumb1_output_casesi (rtx *operands)
 {
-  rtx diff_vec = PATTERN (NEXT_INSN (operands[0]));
+  rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[0])));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
@@ -29604,7 +29762,7 @@ thumb1_output_casesi (rtx *operands)
 const char *
 thumb2_output_casesi (rtx *operands)
 {
-  rtx diff_vec = PATTERN (NEXT_INSN (operands[2]));
+  rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[2])));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
@@ -30287,7 +30445,8 @@ arm_split_compare_and_swap (rtx operands[])
   enum machine_mode mode;
   enum memmodel mod_s, mod_f;
   bool is_weak;
-  rtx label1, label2, x, cond;
+  rtx_code_label *label1, *label2;
+  rtx x, cond;
 
   rval = operands[0];
   mem = operands[1];
@@ -30313,7 +30472,7 @@ arm_split_compare_and_swap (rtx operands[])
   if (!(use_acquire || use_release))
     arm_pre_atomic_barrier (mod_s);
 
-  label1 = NULL_RTX;
+  label1 = NULL;
   if (!is_weak)
     {
       label1 = gen_label_rtx ();
@@ -30363,7 +30522,8 @@ arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
   enum memmodel model = (enum memmodel) INTVAL (model_rtx);
   enum machine_mode mode = GET_MODE (mem);
   enum machine_mode wmode = (mode == DImode ? DImode : SImode);
-  rtx label, x;
+  rtx_code_label *label;
+  rtx x;
 
   bool use_acquire = TARGET_HAVE_LDACQ
                      && !(model == MEMMODEL_RELAXED
@@ -31289,7 +31449,7 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in,
                          ORR (SHIFT (ASHIFT, in_up, scratch1), out_down)));
          if (code == ASHIFTRT)
            {
-             rtx done_label = gen_label_rtx ();
+             rtx_code_label *done_label = gen_label_rtx ();
              emit_jump_insn (BRANCH (LT, done_label));
              emit_insn (SET (out_down, ORR (SHIFT (ASHIFTRT, in_up, scratch2),
                                             out_down)));
@@ -31308,7 +31468,7 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in,
 
          if (code == ASHIFTRT)
            {
-             rtx done_label = gen_label_rtx ();
+             rtx_code_label *done_label = gen_label_rtx ();
              emit_jump_insn (BRANCH (LT, done_label));
              emit_insn (SET (scratch2, SHIFT (ASHIFTRT, in_up, scratch2)));
              emit_insn (SET (out_down, ORR (out_down, scratch2)));
@@ -31454,7 +31614,7 @@ arm_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
   tree new_fenv_var, reload_fenv, restore_fnenv;
   tree update_call, atomic_feraiseexcept, hold_fnclex;
 
-  if (!TARGET_VFP)
+  if (!TARGET_VFP || !TARGET_HARD_FLOAT)
     return;
 
   /* Generate the equivalent of :
@@ -31505,4 +31665,13 @@ arm_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
                            reload_fenv, restore_fnenv), update_call);
 }
 
+/* return TRUE if x is a reference to a value in a constant pool */
+extern bool
+arm_is_constant_pool_ref (rtx x)
+{
+  return (MEM_P (x)
+         && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
+}
+
 #include "gt-arm.h"