]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/arm/arm.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / config / arm / arm.c
index 487095785414531c3e3302932e5d17848b07a8c6..67f1a9c8e2d2d7a0cbbe6bd38e4ac4d259b25df7 100644 (file)
@@ -1,5 +1,5 @@
 /* Output routines for GCC for ARM.
-   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   Copyright (C) 1991-2019 Free Software Foundation, Inc.
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com).
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+#define IN_TARGET_CODE 1
+
 #include "config.h"
+#define INCLUDE_STRING
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
 typedef struct minipool_node    Mnode;
 typedef struct minipool_fixup   Mfix;
 
+/* The last .arch and .fpu assembly strings that we printed.  */
+static std::string arm_last_printed_arch_string;
+static std::string arm_last_printed_fpu_string;
+
 void (*arm_lang_output_object_attributes_hook)(void);
 
 struct four_ints
@@ -281,14 +288,14 @@ static bool arm_builtin_support_vector_misalignment (machine_mode mode,
 static void arm_conditional_register_usage (void);
 static enum flt_eval_method arm_excess_precision (enum excess_precision_type);
 static reg_class_t arm_preferred_rename_class (reg_class_t rclass);
-static unsigned int arm_autovectorize_vector_sizes (void);
+static void arm_autovectorize_vector_sizes (vector_sizes *);
 static int arm_default_branch_cost (bool, bool);
 static int arm_cortex_a5_branch_cost (bool, bool);
 static int arm_cortex_m_branch_cost (bool, bool);
 static int arm_cortex_m7_branch_cost (bool, bool);
 
-static bool arm_vectorize_vec_perm_const_ok (machine_mode vmode,
-                                            const unsigned char *sel);
+static bool arm_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx,
+                                         const vec_perm_indices &);
 
 static bool aarch_macro_fusion_pair_p (rtx_insn*, rtx_insn*);
 
@@ -314,31 +321,33 @@ static unsigned int arm_elf_section_type_flags (tree decl, const char *name,
                                                int reloc);
 static void arm_expand_divmod_libfunc (rtx, machine_mode, rtx, rtx, rtx *, rtx *);
 static opt_scalar_float_mode arm_floatn_mode (int, bool);
+static unsigned int arm_hard_regno_nregs (unsigned int, machine_mode);
 static bool arm_hard_regno_mode_ok (unsigned int, machine_mode);
 static bool arm_modes_tieable_p (machine_mode, machine_mode);
+static HOST_WIDE_INT arm_constant_alignment (const_tree, HOST_WIDE_INT);
 \f
 /* Table of machine attributes.  */
 static const struct attribute_spec arm_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+       affects_type_identity, handler, exclude } */
   /* Function calls made to this symbol must be done indirectly, because
      it may lie outside of the 26 bit addressing range of a normal function
      call.  */
-  { "long_call",    0, 0, false, true,  true,  NULL, false },
+  { "long_call",    0, 0, false, true,  true,  false, NULL, NULL },
   /* Whereas these functions are always known to reside within the 26 bit
      addressing range.  */
-  { "short_call",   0, 0, false, true,  true,  NULL, false },
+  { "short_call",   0, 0, false, true,  true,  false, NULL, NULL },
   /* Specify the procedure call conventions for a function.  */
-  { "pcs",          1, 1, false, true,  true,  arm_handle_pcs_attribute,
-    false },
+  { "pcs",          1, 1, false, true,  true,  false, arm_handle_pcs_attribute,
+    NULL },
   /* Interrupt Service Routines have special prologue and epilogue requirements.  */
-  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute,
-    false },
-  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute,
-    false },
-  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute,
-    false },
+  { "isr",          0, 1, false, false, false, false, arm_handle_isr_attribute,
+    NULL },
+  { "interrupt",    0, 1, false, false, false, false, arm_handle_isr_attribute,
+    NULL },
+  { "naked",        0, 0, true,  false, false, false,
+    arm_handle_fndecl_attribute, NULL },
 #ifdef ARM_PE
   /* ARM/PE has three new attributes:
      interfacearm - ?
@@ -349,22 +358,24 @@ static const struct attribute_spec arm_attribute_table[] =
      them with spaces.  We do NOT support this.  Instead, use __declspec
      multiple times.
   */
-  { "dllimport",    0, 0, true,  false, false, NULL, false },
-  { "dllexport",    0, 0, true,  false, false, NULL, false },
-  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute,
-    false },
+  { "dllimport",    0, 0, true,  false, false, false, NULL, NULL },
+  { "dllexport",    0, 0, true,  false, false, false, NULL, NULL },
+  { "interfacearm", 0, 0, true,  false, false, false,
+    arm_handle_fndecl_attribute, NULL },
 #elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
-  { "dllimport",    0, 0, false, false, false, handle_dll_attribute, false },
-  { "dllexport",    0, 0, false, false, false, handle_dll_attribute, false },
-  { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
-    false },
+  { "dllimport",    0, 0, false, false, false, false, handle_dll_attribute,
+    NULL },
+  { "dllexport",    0, 0, false, false, false, false, handle_dll_attribute,
+    NULL },
+  { "notshared",    0, 0, false, true, false, false,
+    arm_handle_notshared_attribute, NULL },
 #endif
   /* ARMv8-M Security Extensions support.  */
-  { "cmse_nonsecure_entry", 0, 0, true, false, false,
-    arm_handle_cmse_nonsecure_entry, false },
-  { "cmse_nonsecure_call", 0, 0, true, false, false,
-    arm_handle_cmse_nonsecure_call, true },
-  { NULL,           0, 0, false, false, false, NULL, false }
+  { "cmse_nonsecure_entry", 0, 0, true, false, false, false,
+    arm_handle_cmse_nonsecure_entry, NULL },
+  { "cmse_nonsecure_call", 0, 0, true, false, false, true,
+    arm_handle_cmse_nonsecure_call, NULL },
+  { NULL, 0, 0, false, false, false, false, NULL, NULL }
 };
 \f
 /* Initialize the GCC target structure.  */
@@ -730,9 +741,8 @@ static const struct attribute_spec arm_attribute_table[] =
 #define TARGET_PREFERRED_RENAME_CLASS \
   arm_preferred_rename_class
 
-#undef TARGET_VECTORIZE_VEC_PERM_CONST_OK
-#define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
-  arm_vectorize_vec_perm_const_ok
+#undef TARGET_VECTORIZE_VEC_PERM_CONST
+#define TARGET_VECTORIZE_VEC_PERM_CONST arm_vectorize_vec_perm_const
 
 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \
@@ -785,11 +795,19 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_FIXED_CONDITION_CODE_REGS
 #define TARGET_FIXED_CONDITION_CODE_REGS arm_fixed_condition_code_regs
 
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS arm_hard_regno_nregs
 #undef TARGET_HARD_REGNO_MODE_OK
 #define TARGET_HARD_REGNO_MODE_OK arm_hard_regno_mode_ok
 
 #undef TARGET_MODES_TIEABLE_P
 #define TARGET_MODES_TIEABLE_P arm_modes_tieable_p
+
+#undef TARGET_CAN_CHANGE_MODE_CLASS
+#define TARGET_CAN_CHANGE_MODE_CLASS arm_can_change_mode_class
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
 \f
 /* Obstack for minipool constant handling.  */
 static struct obstack minipool_obstack;
@@ -832,20 +850,14 @@ struct arm_build_target arm_active_target;
 /* The following are used in the arm.md file as equivalents to bits
    in the above two flag variables.  */
 
-/* Nonzero if this chip supports the ARM Architecture 3M extensions.  */
-int arm_arch3m = 0;
-
 /* Nonzero if this chip supports the ARM Architecture 4 extensions.  */
 int arm_arch4 = 0;
 
 /* Nonzero if this chip supports the ARM Architecture 4t extensions.  */
 int arm_arch4t = 0;
 
-/* Nonzero if this chip supports the ARM Architecture 5 extensions.  */
-int arm_arch5 = 0;
-
-/* Nonzero if this chip supports the ARM Architecture 5E extensions.  */
-int arm_arch5e = 0;
+/* Nonzero if this chip supports the ARM Architecture 5T extensions.  */
+int arm_arch5t = 0;
 
 /* Nonzero if this chip supports the ARM Architecture 5TE extensions.  */
 int arm_arch5te = 0;
@@ -883,6 +895,12 @@ int arm_arch8_1 = 0;
 /* Nonzero if this chip supports the ARM Architecture 8.2 extensions.  */
 int arm_arch8_2 = 0;
 
+/* Nonzero if this chip supports the ARM Architecture 8.3 extensions.  */
+int arm_arch8_3 = 0;
+
+/* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
+int arm_arch8_4 = 0;
+
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
 int arm_fp16_inst = 0;
@@ -962,6 +980,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip supports the AdvSIMD Dot Product instructions.  */
+int arm_arch_dotprod = 0;
+
 /* Nonzero if chip supports the ARMv8-M security extensions.  */
 int arm_arch_cmse = 0;
 
@@ -1751,9 +1772,32 @@ const struct cpu_cost_table v7m_extra_costs =
   }
 };
 
+const struct addr_mode_cost_table generic_addr_mode_costs =
+{
+  /* int.  */
+  {
+    COSTS_N_INSNS (0), /* AMO_DEFAULT.  */
+    COSTS_N_INSNS (0), /* AMO_NO_WB.  */
+    COSTS_N_INSNS (0)  /* AMO_WB.  */
+  },
+  /* float.  */
+  {
+    COSTS_N_INSNS (0), /* AMO_DEFAULT.  */
+    COSTS_N_INSNS (0), /* AMO_NO_WB.  */
+    COSTS_N_INSNS (0)  /* AMO_WB.  */
+  },
+  /* vector.  */
+  {
+    COSTS_N_INSNS (0), /* AMO_DEFAULT.  */
+    COSTS_N_INSNS (0), /* AMO_NO_WB.  */
+    COSTS_N_INSNS (0)  /* AMO_WB.  */
+  }
+};
+
 const struct tune_params arm_slowmul_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1776,6 +1820,7 @@ const struct tune_params arm_slowmul_tune =
 const struct tune_params arm_fastmul_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1801,6 +1846,7 @@ const struct tune_params arm_fastmul_tune =
 const struct tune_params arm_strongarm_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1823,6 +1869,7 @@ const struct tune_params arm_strongarm_tune =
 const struct tune_params arm_xscale_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   xscale_sched_adjust_cost,
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1845,6 +1892,7 @@ const struct tune_params arm_xscale_tune =
 const struct tune_params arm_9e_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1867,6 +1915,7 @@ const struct tune_params arm_9e_tune =
 const struct tune_params arm_marvell_pj4_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1889,6 +1938,7 @@ const struct tune_params arm_marvell_pj4_tune =
 const struct tune_params arm_v6t2_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1913,6 +1963,7 @@ const struct tune_params arm_v6t2_tune =
 const struct tune_params arm_cortex_tune =
 {
   &generic_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1935,6 +1986,7 @@ const struct tune_params arm_cortex_tune =
 const struct tune_params arm_cortex_a8_tune =
 {
   &cortexa8_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1957,6 +2009,7 @@ const struct tune_params arm_cortex_a8_tune =
 const struct tune_params arm_cortex_a7_tune =
 {
   &cortexa7_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -1979,6 +2032,7 @@ const struct tune_params arm_cortex_a7_tune =
 const struct tune_params arm_cortex_a15_tune =
 {
   &cortexa15_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2001,6 +2055,7 @@ const struct tune_params arm_cortex_a15_tune =
 const struct tune_params arm_cortex_a35_tune =
 {
   &cortexa53_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2023,6 +2078,7 @@ const struct tune_params arm_cortex_a35_tune =
 const struct tune_params arm_cortex_a53_tune =
 {
   &cortexa53_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2045,6 +2101,7 @@ const struct tune_params arm_cortex_a53_tune =
 const struct tune_params arm_cortex_a57_tune =
 {
   &cortexa57_extra_costs,
+  &generic_addr_mode_costs,            /* addressing mode costs */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2067,6 +2124,7 @@ const struct tune_params arm_cortex_a57_tune =
 const struct tune_params arm_exynosm1_tune =
 {
   &exynosm1_extra_costs,
+  &generic_addr_mode_costs,                    /* Addressing mode costs.  */
   NULL,                                                /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2089,6 +2147,7 @@ const struct tune_params arm_exynosm1_tune =
 const struct tune_params arm_xgene1_tune =
 {
   &xgene1_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2114,6 +2173,7 @@ const struct tune_params arm_xgene1_tune =
 const struct tune_params arm_cortex_a5_tune =
 {
   &cortexa5_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_cortex_a5_branch_cost,
   &arm_default_vec_cost,
@@ -2136,6 +2196,7 @@ const struct tune_params arm_cortex_a5_tune =
 const struct tune_params arm_cortex_a9_tune =
 {
   &cortexa9_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   cortex_a9_sched_adjust_cost,
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2158,6 +2219,7 @@ const struct tune_params arm_cortex_a9_tune =
 const struct tune_params arm_cortex_a12_tune =
 {
   &cortexa12_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,                        /* Vectorizer costs.  */
@@ -2180,6 +2242,7 @@ const struct tune_params arm_cortex_a12_tune =
 const struct tune_params arm_cortex_a73_tune =
 {
   &cortexa57_extra_costs,
+  &generic_addr_mode_costs,                    /* Addressing mode costs.  */
   NULL,                                                /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,                       /* Vectorizer costs.  */
@@ -2209,6 +2272,7 @@ const struct tune_params arm_cortex_a73_tune =
 const struct tune_params arm_v7m_tune =
 {
   &v7m_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_cortex_m_branch_cost,
   &arm_default_vec_cost,
@@ -2233,6 +2297,7 @@ const struct tune_params arm_v7m_tune =
 const struct tune_params arm_cortex_m7_tune =
 {
   &v7m_extra_costs,
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_cortex_m7_branch_cost,
   &arm_default_vec_cost,
@@ -2258,6 +2323,7 @@ const struct tune_params arm_cortex_m7_tune =
 const struct tune_params arm_v6m_tune =
 {
   &generic_extra_costs,                        /* Insn extra costs.  */
+  &generic_addr_mode_costs,            /* Addressing mode costs.  */
   NULL,                                        /* Sched adj cost.  */
   arm_default_branch_cost,
   &arm_default_vec_cost,                        /* Vectorizer costs.  */
@@ -2280,6 +2346,7 @@ const struct tune_params arm_v6m_tune =
 const struct tune_params arm_fa726te_tune =
 {
   &generic_extra_costs,                                /* Insn extra costs.  */
+  &generic_addr_mode_costs,                    /* Addressing mode costs.  */
   fa726te_sched_adjust_cost,
   arm_default_branch_cost,
   &arm_default_vec_cost,
@@ -2405,8 +2472,9 @@ arm_set_fixed_conv_libfunc (convert_optab optable, machine_mode to,
   set_conv_libfunc (optable, to, from, buffer);
 }
 
-/* Set up library functions unique to ARM.  */
+static GTY(()) rtx speculation_barrier_libfunc;
 
+/* Set up library functions unique to ARM.  */
 static void
 arm_init_libfuncs (void)
 {
@@ -2692,6 +2760,8 @@ arm_init_libfuncs (void)
 
   if (TARGET_AAPCS_BASED)
     synchronize_libfunc = init_one_libfunc ("__sync_synchronize");
+
+  speculation_barrier_libfunc = init_one_libfunc ("__speculation_barrier");
 }
 
 /* On AAPCS systems, this is the "struct __va_list".  */
@@ -2814,14 +2884,15 @@ arm_option_check_internal (struct gcc_options *opts)
       && write_symbols != NO_DEBUG
       && !TARGET_APCS_FRAME
       && (TARGET_DEFAULT & MASK_APCS_FRAME))
-    warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
+    warning (0, "%<-g%> with %<-mno-apcs-frame%> may not give sensible "
+            "debugging");
 
   /* iWMMXt unsupported under Thumb mode.  */
   if (TARGET_THUMB_P (flags) && TARGET_IWMMXT)
     error ("iWMMXt unsupported under Thumb mode");
 
   if (TARGET_HARD_TP && TARGET_THUMB1_P (flags))
-    error ("can not use -mtp=cp15 with 16-bit Thumb");
+    error ("cannot use %<-mtp=cp15%> with 16-bit Thumb");
 
   if (TARGET_THUMB_P (flags) && TARGET_VXWORKS_RTP && flag_pic)
     {
@@ -2829,17 +2900,22 @@ arm_option_check_internal (struct gcc_options *opts)
       flag_pic = 0;
     }
 
-  /* We only support -mpure-code and -mslow-flash-data on M-profile targets
-     with MOVT.  */
-  if ((target_pure_code || target_slow_flash_data)
-      && (!TARGET_HAVE_MOVT || arm_arch_notm || flag_pic || TARGET_NEON))
+  if (target_pure_code || target_slow_flash_data)
     {
       const char *flag = (target_pure_code ? "-mpure-code" :
                                             "-mslow-flash-data");
-      error ("%s only supports non-pic code on M-profile targets with the "
-            "MOVT instruction", flag);
-    }
 
+      /* We only support -mpure-code and -mslow-flash-data on M-profile targets
+        with MOVT.  */
+      if (!TARGET_HAVE_MOVT || arm_arch_notm || flag_pic || TARGET_NEON)
+       error ("%s only supports non-pic code on M-profile targets with the "
+              "MOVT instruction", flag);
+
+      /* Cannot load addresses: -mslow-flash-data forbids literal pool and
+        -mword-relocations forbids relocation of MOVT/MOVW.  */
+      if (target_word_relocations)
+       error ("%s incompatible with %<-mword-relocations%>", flag);
+    }
 }
 
 /* Recompute the global settings depending on target attribute options.  */
@@ -2873,20 +2949,12 @@ arm_option_params_internal (void)
       targetm.max_anchor_offset = TARGET_MAX_ANCHOR_OFFSET;
     }
 
-  if (optimize_size)
-    {
-      /* If optimizing for size, bump the number of instructions that we
-         are prepared to conditionally execute (even on a StrongARM).  */
-      max_insns_skipped = 6;
+  /* Increase the number of conditional instructions with -Os.  */
+  max_insns_skipped = optimize_size ? 4 : current_tune->max_insns_skipped;
 
-      /* For THUMB2, we limit the conditional sequence to one IT block.  */
-      if (TARGET_THUMB2)
-        max_insns_skipped = arm_restrict_it ? 1 : 4;
-    }
-  else
-    /* When -mrestrict-it is in use tone down the if-conversion.  */
-    max_insns_skipped = (TARGET_THUMB2 && arm_restrict_it)
-      ? 1 : current_tune->max_insns_skipped;
+  /* For THUMB2, we limit the conditional sequence to one IT block.  */
+  if (TARGET_THUMB2)
+    max_insns_skipped = MIN (max_insns_skipped, MAX_INSN_PER_IT_BLOCK);
 }
 
 /* True if -mflip-thumb should next add an attribute for the default
@@ -2899,9 +2967,10 @@ static GTY(()) tree init_optimize;
 static void
 arm_override_options_after_change_1 (struct gcc_options *opts)
 {
-  if (opts->x_align_functions <= 0)
-    opts->x_align_functions = TARGET_THUMB_P (opts->x_target_flags)
-      && opts->x_optimize_size ? 2 : 4;
+  /* -falign-functions without argument: supply one.  */
+  if (opts->x_flag_align_functions && !opts->x_str_align_functions)
+    opts->x_str_align_functions = TARGET_THUMB_P (opts->x_target_flags)
+      && opts->x_optimize_size ? "2" : "4";
 }
 
 /* Implement targetm.override_options_after_change.  */
@@ -2946,7 +3015,8 @@ arm_option_override_internal (struct gcc_options *opts,
   if (TARGET_INTERWORK && !bitmap_bit_p (arm_active_target.isa, isa_bit_thumb))
     {
       /* The default is to enable interworking, so this warning message would
-        be confusing to users who have just compiled with, eg, -march=armv3.  */
+        be confusing to users who have just compiled with
+        eg, -march=armv4.  */
       /* warning (0, "ignoring -minterwork because target CPU does not support THUMB"); */
       opts->x_target_flags &= ~MASK_INTERWORK;
     }
@@ -3032,7 +3102,8 @@ arm_option_override_internal (struct gcc_options *opts,
 
   /* Thumb2 inline assembly code should always use unified syntax.
      This will apply to ARM and Thumb1 eventually.  */
-  opts->x_inline_asm_unified = TARGET_THUMB2_P (opts->x_target_flags);
+  if (TARGET_THUMB2_P (opts->x_target_flags))
+    opts->x_inline_asm_unified = true;
 
 #ifdef SUBTARGET_OVERRIDE_INTERNAL_OPTIONS
   SUBTARGET_OVERRIDE_INTERNAL_OPTIONS;
@@ -3111,7 +3182,8 @@ arm_configure_build_target (struct arm_build_target *target,
          if (!bitmap_empty_p (isa_delta))
            {
              if (warn_compatible)
-               warning (0, "switch -mcpu=%s conflicts with -march=%s switch",
+               warning (0, "switch %<-mcpu=%s%> conflicts "
+                        "with %<-march=%s%> switch",
                         arm_selected_cpu->common.name,
                         arm_selected_arch->common.name);
              /* -march wins for code generation.
@@ -3178,17 +3250,7 @@ arm_configure_build_target (struct arm_build_target *target,
         switches that require certain abilities from the cpu.  */
 
       if (TARGET_INTERWORK || TARGET_THUMB)
-       {
-         bitmap_set_bit (sought_isa, isa_bit_thumb);
-         bitmap_set_bit (sought_isa, isa_bit_mode32);
-
-         /* There are no ARM processors that support both APCS-26 and
-            interworking.  Therefore we forcibly remove MODE26 from
-            from the isa features here (if it was set), so that the
-            search below will always be able to find a compatible
-            processor.  */
-         bitmap_clear_bit (default_isa, isa_bit_mode26);
-       }
+       bitmap_set_bit (sought_isa, isa_bit_thumb);
 
       /* If there are such requirements and the default CPU does not
         satisfy them, we need to run over the complete list of
@@ -3293,6 +3355,7 @@ arm_configure_build_target (struct arm_build_target *target,
   target->tune_flags = tune_data->tune_flags;
   target->tune = tune_data->tune;
   target->tune_core = tune_data->scheduler;
+  arm_option_reconfigure_globals ();
 }
 
 /* Fix up any incompatible options that the user has specified.  */
@@ -3331,8 +3394,9 @@ arm_option_override (void)
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
-  sprintf (arm_arch_name, "__ARM_ARCH_%s__", arm_active_target.arch_pp_name);
-  arm_base_arch = arm_active_target.base_arch;
+  /* Initialize boolean versions of the architectural flags, for use
+     in the arm.md file and for enabling feature flags.  */
+  arm_option_reconfigure_globals ();
 
   arm_tune = arm_active_target.tune_core;
   tune_flags = arm_active_target.tune_flags;
@@ -3342,19 +3406,10 @@ arm_option_override (void)
   if (TARGET_APCS_FRAME)
     flag_shrink_wrap = false;
 
-  /* BPABI targets use linker tricks to allow interworking on cores
-     without thumb support.  */
-  if (TARGET_INTERWORK
-      && !TARGET_BPABI
-      && !bitmap_bit_p (arm_active_target.isa, isa_bit_thumb))
-    {
-      warning (0, "target CPU does not support interworking" );
-      target_flags &= ~MASK_INTERWORK;
-    }
-
   if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
     {
-      warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
+      warning (0, "%<-mapcs-stack-check%> incompatible with "
+              "%<-mno-apcs-frame%>");
       target_flags |= MASK_APCS_FRAME;
     }
 
@@ -3362,48 +3417,11 @@ arm_option_override (void)
     target_flags |= MASK_APCS_FRAME;
 
   if (TARGET_APCS_REENT && flag_pic)
-    error ("-fpic and -mapcs-reent are incompatible");
+    error ("%<-fpic%> and %<-mapcs-reent%> are incompatible");
 
   if (TARGET_APCS_REENT)
     warning (0, "APCS reentrant code not supported.  Ignored");
 
-  /* Initialize boolean versions of the architectural flags, for use
-     in the arm.md file.  */
-  arm_arch3m = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv3m);
-  arm_arch4 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv4);
-  arm_arch4t = arm_arch4 && bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
-  arm_arch5 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv5);
-  arm_arch5e = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv5e);
-  arm_arch5te = arm_arch5e
-    && bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
-  arm_arch6 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv6);
-  arm_arch6k = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv6k);
-  arm_arch_notm = bitmap_bit_p (arm_active_target.isa, isa_bit_notm);
-  arm_arch6m = arm_arch6 && !arm_arch_notm;
-  arm_arch7 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv7);
-  arm_arch7em = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv7em);
-  arm_arch8 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv8);
-  arm_arch8_1 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv8_1);
-  arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv8_2);
-  arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
-  arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
-  arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
-  arm_arch_iwmmxt = bitmap_bit_p (arm_active_target.isa, isa_bit_iwmmxt);
-  arm_arch_iwmmxt2 = bitmap_bit_p (arm_active_target.isa, isa_bit_iwmmxt2);
-  arm_arch_thumb_hwdiv = bitmap_bit_p (arm_active_target.isa, isa_bit_tdiv);
-  arm_arch_arm_hwdiv = bitmap_bit_p (arm_active_target.isa, isa_bit_adiv);
-  arm_arch_crc = bitmap_bit_p (arm_active_target.isa, isa_bit_crc32);
-  arm_arch_cmse = bitmap_bit_p (arm_active_target.isa, isa_bit_cmse);
-  arm_fp16_inst = bitmap_bit_p (arm_active_target.isa, isa_bit_fp16);
-  arm_arch_lpae = bitmap_bit_p (arm_active_target.isa, isa_bit_lpae);
-  if (arm_fp16_inst)
-    {
-      if (arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE)
-       error ("selected fp16 options are incompatible");
-      arm_fp16_format = ARM_FP16_FORMAT_IEEE;
-    }
-
-
   /* Set up some tuning parameters.  */
   arm_ld_sched = (tune_flags & TF_LDSCHED) != 0;
   arm_tune_strongarm = (tune_flags & TF_STRONG) != 0;
@@ -3412,86 +3430,11 @@ arm_option_override (void)
   arm_tune_cortex_a9 = (arm_tune == TARGET_CPU_cortexa9) != 0;
   arm_m_profile_small_mul = (tune_flags & TF_SMALLMUL) != 0;
 
-  /* And finally, set up some quirks.  */
-  arm_arch_no_volatile_ce
-    = bitmap_bit_p (arm_active_target.isa, isa_quirk_no_volatile_ce);
-  arm_arch6kz
-    = arm_arch6k && bitmap_bit_p (arm_active_target.isa, isa_quirk_ARMv6kz);
-
-  /* V5 code we generate is completely interworking capable, so we turn off
-     TARGET_INTERWORK here to avoid many tests later on.  */
-
-  /* XXX However, we must pass the right pre-processor defines to CPP
-     or GLD can get confused.  This is a hack.  */
-  if (TARGET_INTERWORK)
-    arm_cpp_interwork = 1;
-
-  if (arm_arch5)
-    target_flags &= ~MASK_INTERWORK;
-
-  if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
-    error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
-
-  if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
-    error ("iwmmxt abi requires an iwmmxt capable cpu");
-
-  /* If soft-float is specified then don't use FPU.  */
-  if (TARGET_SOFT_FLOAT)
-    arm_fpu_attr = FPU_NONE;
-  else
-    arm_fpu_attr = FPU_VFP;
-
-  if (TARGET_AAPCS_BASED)
-    {
-      if (TARGET_CALLER_INTERWORKING)
-       error ("AAPCS does not support -mcaller-super-interworking");
-      else
-       if (TARGET_CALLEE_INTERWORKING)
-         error ("AAPCS does not support -mcallee-super-interworking");
-    }
-
-  /* __fp16 support currently assumes the core has ldrh.  */
-  if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
-    sorry ("__fp16 and no ldrh");
-
-  if (TARGET_AAPCS_BASED)
-    {
-      if (arm_abi == ARM_ABI_IWMMXT)
-       arm_pcs_default = ARM_PCS_AAPCS_IWMMXT;
-      else if (TARGET_HARD_FLOAT_ABI)
-       {
-         arm_pcs_default = ARM_PCS_AAPCS_VFP;
-         if (!bitmap_bit_p (arm_active_target.isa, isa_bit_VFPv2))
-           error ("-mfloat-abi=hard: selected processor lacks an FPU");
-       }
-      else
-       arm_pcs_default = ARM_PCS_AAPCS;
-    }
-  else
-    {
-      if (arm_float_abi == ARM_FLOAT_ABI_HARD)
-       sorry ("-mfloat-abi=hard and VFP");
-
-      if (arm_abi == ARM_ABI_APCS)
-       arm_pcs_default = ARM_PCS_APCS;
-      else
-       arm_pcs_default = ARM_PCS_ATPCS;
-    }
-
   /* For arm2/3 there is no need to do any scheduling if we are doing
      software floating-point.  */
   if (TARGET_SOFT_FLOAT && (tune_flags & TF_NO_MODE32))
     flag_schedule_insns = flag_schedule_insns_after_reload = 0;
 
-  /* Use the cp15 method if it is available.  */
-  if (target_thread_pointer == TP_AUTO)
-    {
-      if (arm_arch6k && !TARGET_THUMB1)
-       target_thread_pointer = TP_CP15;
-      else
-       target_thread_pointer = TP_SOFT;
-    }
-
   /* Override the default structure alignment for AAPCS ABI.  */
   if (!global_options_set.x_arm_structure_size_boundary)
     {
@@ -3535,7 +3478,7 @@ arm_option_override (void)
   if (flag_pic && TARGET_SINGLE_PIC_BASE)
     {
       if (TARGET_VXWORKS_RTP)
-       warning (0, "RTP PIC is incompatible with -msingle-pic-base");
+       warning (0, "RTP PIC is incompatible with %<-msingle-pic-base%>");
       arm_pic_register = (TARGET_APCS_STACK || TARGET_AAPCS_BASED) ? 9 : 10;
     }
 
@@ -3547,7 +3490,7 @@ arm_option_override (void)
       int pic_register = decode_reg_name (arm_pic_register_string);
 
       if (!flag_pic)
-       warning (0, "-mpic-register= is useless without -fpic");
+       warning (0, "%<-mpic-register=%> is useless without %<-fpic%>");
 
       /* Prevent the user from choosing an obviously stupid PIC register.  */
       else if (pic_register < 0 || call_used_regs[pic_register]
@@ -3561,10 +3504,13 @@ arm_option_override (void)
        arm_pic_register = pic_register;
     }
 
+  if (flag_pic)
+    target_word_relocations = 1;
+
   /* Enable -mfix-cortex-m3-ldrd by default for Cortex-M3 cores.  */
   if (fix_cm3_ldrd == 2)
     {
-      if (bitmap_bit_p (arm_active_target.isa, isa_quirk_cm3_ldrd))
+      if (bitmap_bit_p (arm_active_target.isa, isa_bit_quirk_cm3_ldrd))
        fix_cm3_ldrd = 1;
       else
        fix_cm3_ldrd = 0;
@@ -3575,7 +3521,8 @@ arm_option_override (void)
   if (flag_reorder_blocks_and_partition)
     {
       inform (input_location,
-             "-freorder-blocks-and-partition not supported on this architecture");
+             "%<-freorder-blocks-and-partition%> not supported "
+             "on this architecture");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -3665,9 +3612,6 @@ arm_option_override (void)
   if (target_slow_flash_data || target_pure_code)
     arm_disable_literal_pool = true;
 
-  if (use_cmse && !arm_arch_cmse)
-    error ("target CPU does not support ARMv8-M Security Extensions");
-
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
@@ -3677,6 +3621,7 @@ arm_option_override (void)
   /* Need to remember initial options before they are overriden.  */
   init_optimize = build_optimization_node (&global_options);
 
+  arm_options_perform_arch_sanity_checks ();
   arm_option_override_internal (&global_options, &global_options_set);
   arm_option_check_internal (&global_options);
   arm_option_params_internal ();
@@ -3692,6 +3637,150 @@ arm_option_override (void)
   thumb_flipper = TARGET_THUMB;
 }
 
+
+/* Reconfigure global status flags from the active_target.isa.  */
+void
+arm_option_reconfigure_globals (void)
+{
+  sprintf (arm_arch_name, "__ARM_ARCH_%s__", arm_active_target.arch_pp_name);
+  arm_base_arch = arm_active_target.base_arch;
+
+  /* Initialize boolean versions of the architectural flags, for use
+     in the arm.md file.  */
+  arm_arch4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv4);
+  arm_arch4t = arm_arch4 && bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
+  arm_arch5t =  bitmap_bit_p (arm_active_target.isa, isa_bit_armv5t);
+  arm_arch5te = bitmap_bit_p (arm_active_target.isa, isa_bit_armv5te);
+  arm_arch6 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv6);
+  arm_arch6k = bitmap_bit_p (arm_active_target.isa, isa_bit_armv6k);
+  arm_arch_notm = bitmap_bit_p (arm_active_target.isa, isa_bit_notm);
+  arm_arch6m = arm_arch6 && !arm_arch_notm;
+  arm_arch7 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv7);
+  arm_arch7em = bitmap_bit_p (arm_active_target.isa, isa_bit_armv7em);
+  arm_arch8 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8);
+  arm_arch8_1 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_1);
+  arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
+  arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
+  arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
+  arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
+  arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
+  arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
+  arm_arch_iwmmxt = bitmap_bit_p (arm_active_target.isa, isa_bit_iwmmxt);
+  arm_arch_iwmmxt2 = bitmap_bit_p (arm_active_target.isa, isa_bit_iwmmxt2);
+  arm_arch_thumb_hwdiv = bitmap_bit_p (arm_active_target.isa, isa_bit_tdiv);
+  arm_arch_arm_hwdiv = bitmap_bit_p (arm_active_target.isa, isa_bit_adiv);
+  arm_arch_crc = bitmap_bit_p (arm_active_target.isa, isa_bit_crc32);
+  arm_arch_cmse = bitmap_bit_p (arm_active_target.isa, isa_bit_cmse);
+  arm_fp16_inst = bitmap_bit_p (arm_active_target.isa, isa_bit_fp16);
+  arm_arch_lpae = bitmap_bit_p (arm_active_target.isa, isa_bit_lpae);
+  if (arm_fp16_inst)
+    {
+      if (arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE)
+       error ("selected fp16 options are incompatible");
+      arm_fp16_format = ARM_FP16_FORMAT_IEEE;
+    }
+
+  /* And finally, set up some quirks.  */
+  arm_arch_no_volatile_ce
+    = bitmap_bit_p (arm_active_target.isa, isa_bit_quirk_no_volatile_ce);
+  arm_arch6kz = arm_arch6k && bitmap_bit_p (arm_active_target.isa,
+                                           isa_bit_quirk_armv6kz);
+
+  /* Use the cp15 method if it is available.  */
+  if (target_thread_pointer == TP_AUTO)
+    {
+      if (arm_arch6k && !TARGET_THUMB1)
+       target_thread_pointer = TP_CP15;
+      else
+       target_thread_pointer = TP_SOFT;
+    }
+}
+
+/* Perform some validation between the desired architecture and the rest of the
+   options.  */
+void
+arm_options_perform_arch_sanity_checks (void)
+{
+  /* V5T code we generate is completely interworking capable, so we turn off
+     TARGET_INTERWORK here to avoid many tests later on.  */
+
+  /* XXX However, we must pass the right pre-processor defines to CPP
+     or GLD can get confused.  This is a hack.  */
+  if (TARGET_INTERWORK)
+    arm_cpp_interwork = 1;
+
+  if (arm_arch5t)
+    target_flags &= ~MASK_INTERWORK;
+
+  if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
+    error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
+
+  if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
+    error ("iwmmxt abi requires an iwmmxt capable cpu");
+
+  /* BPABI targets use linker tricks to allow interworking on cores
+     without thumb support.  */
+  if (TARGET_INTERWORK
+      && !TARGET_BPABI
+      && !bitmap_bit_p (arm_active_target.isa, isa_bit_thumb))
+    {
+      warning (0, "target CPU does not support interworking" );
+      target_flags &= ~MASK_INTERWORK;
+    }
+
+  /* If soft-float is specified then don't use FPU.  */
+  if (TARGET_SOFT_FLOAT)
+    arm_fpu_attr = FPU_NONE;
+  else
+    arm_fpu_attr = FPU_VFP;
+
+  if (TARGET_AAPCS_BASED)
+    {
+      if (TARGET_CALLER_INTERWORKING)
+       error ("AAPCS does not support %<-mcaller-super-interworking%>");
+      else
+       if (TARGET_CALLEE_INTERWORKING)
+         error ("AAPCS does not support %<-mcallee-super-interworking%>");
+    }
+
+  /* __fp16 support currently assumes the core has ldrh.  */
+  if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
+    sorry ("__fp16 and no ldrh");
+
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
+  /* We don't clear D16-D31 VFP registers for cmse_nonsecure_call functions
+     and ARMv8-M Baseline and Mainline do not allow such configuration.  */
+  if (use_cmse && LAST_VFP_REGNUM > LAST_LO_VFP_REGNUM)
+    error ("ARMv8-M Security Extensions incompatible with selected FPU");
+
+
+  if (TARGET_AAPCS_BASED)
+    {
+      if (arm_abi == ARM_ABI_IWMMXT)
+       arm_pcs_default = ARM_PCS_AAPCS_IWMMXT;
+      else if (TARGET_HARD_FLOAT_ABI)
+       {
+         arm_pcs_default = ARM_PCS_AAPCS_VFP;
+         if (!bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv2))
+           error ("%<-mfloat-abi=hard%>: selected processor lacks an FPU");
+       }
+      else
+       arm_pcs_default = ARM_PCS_AAPCS;
+    }
+  else
+    {
+      if (arm_float_abi == ARM_FLOAT_ABI_HARD)
+       sorry ("%<-mfloat-abi=hard%> and VFP");
+
+      if (arm_abi == ARM_ABI_APCS)
+       arm_pcs_default = ARM_PCS_APCS;
+      else
+       arm_pcs_default = ARM_PCS_ATPCS;
+    }
+}
+
 static void
 arm_add_gc_roots (void)
 {
@@ -3979,10 +4068,10 @@ use_return_insn (int iscond, rtx sibling)
      the other registers, since that is never slower than executing
      another instruction.
 
-     We test for !arm_arch5 here, because code for any architecture
+     We test for !arm_arch5t here, because code for any architecture
      less than this could potentially be run on one of the buggy
      chips.  */
-  if (stack_adjust == 4 && !arm_arch5 && TARGET_ARM)
+  if (stack_adjust == 4 && !arm_arch5t && TARGET_ARM)
     {
       /* Validate that r3 is a call-clobbered register (always true in
         the default abi) ...  */
@@ -5358,7 +5447,7 @@ arm_function_value(const_tree type, const_tree func,
       if (size % UNITS_PER_WORD != 0)
        {
          size += UNITS_PER_WORD - size % UNITS_PER_WORD;
-         mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+         mode = int_mode_for_size (size * BITS_PER_UNIT, 0).require ();
        }
     }
 
@@ -5877,7 +5966,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
                      - tree_to_uhwi (TYPE_MIN_VALUE (index)));
 
        /* There must be no padding.  */
-       if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+       if (wi::to_wide (TYPE_SIZE (type))
+           != count * GET_MODE_BITSIZE (*modep))
          return -1;
 
        return count;
@@ -5907,7 +5997,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
          }
 
        /* There must be no padding.  */
-       if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+       if (wi::to_wide (TYPE_SIZE (type))
+           != count * GET_MODE_BITSIZE (*modep))
          return -1;
 
        return count;
@@ -5939,7 +6030,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
          }
 
        /* There must be no padding.  */
-       if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+       if (wi::to_wide (TYPE_SIZE (type))
+           != count * GET_MODE_BITSIZE (*modep))
          return -1;
 
        return count;
@@ -6315,7 +6407,7 @@ aapcs_allocate_return_reg (machine_mode mode, const_tree type,
       if (size % UNITS_PER_WORD != 0)
        {
          size += UNITS_PER_WORD - size % UNITS_PER_WORD;
-         mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+         mode = int_mode_for_size (size * BITS_PER_UNIT, 0).require ();
        }
     }
 
@@ -6510,7 +6602,9 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
     }
 }
 
-/* Return 1 if double word alignment is required for argument passing.
+/* Return 2 if double word alignment is required for argument passing,
+   but wasn't required before the fix for PR88469.
+   Return 1 if double word alignment is required for argument passing.
    Return -1 if double word alignment used to be required for argument
    passing before PR77728 ABI fix, but is not required anymore.
    Return 0 if double word alignment is not required and wasn't requried
@@ -6530,7 +6624,8 @@ arm_needs_doubleword_align (machine_mode mode, const_tree type)
     return TYPE_ALIGN (TREE_TYPE (type)) > PARM_BOUNDARY;
 
   int ret = 0;
-  /* Record/aggregate types: Use greatest member alignment of any member.  */ 
+  int ret2 = 0;
+  /* Record/aggregate types: Use greatest member alignment of any member.  */
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (DECL_ALIGN (field) > PARM_BOUNDARY)
       {
@@ -6542,6 +6637,13 @@ arm_needs_doubleword_align (machine_mode mode, const_tree type)
             Make sure we can warn about that with -Wpsabi.  */
          ret = -1;
       }
+    else if (TREE_CODE (field) == FIELD_DECL
+            && DECL_BIT_FIELD_TYPE (field)
+            && TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)) > PARM_BOUNDARY)
+      ret2 = 1;
+
+  if (ret2)
+    return 2;
 
   return ret;
 }
@@ -6607,7 +6709,12 @@ arm_function_arg (cumulative_args_t pcum_v, machine_mode mode,
        inform (input_location, "parameter passing for argument of type "
                "%qT changed in GCC 7.1", type);
       else if (res > 0)
-       pcum->nregs++;
+       {
+         pcum->nregs++;
+         if (res > 1 && warn_psabi)
+           inform (input_location, "parameter passing for argument of type "
+                   "%qT changed in GCC 9.1", type);
+       }
     }
 
   /* Only allow splitting an arg between regs and memory if all preceding
@@ -6634,6 +6741,9 @@ arm_function_arg_boundary (machine_mode mode, const_tree type)
   if (res < 0 && warn_psabi)
     inform (input_location, "parameter passing for argument of type %qT "
            "changed in GCC 7.1", type);
+  if (res > 1 && warn_psabi)
+    inform (input_location, "parameter passing for argument of type "
+           "%qT changed in GCC 9.1", type);
 
   return res > 0 ? DOUBLEWORD_ALIGNMENT : PARM_BOUNDARY;
 }
@@ -6933,8 +7043,8 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   if (!use_cmse)
     {
       *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
-              name);
+      warning (OPT_Wattributes, "%qE attribute ignored without %<-mcmse%> "
+              "option.", name);
       return NULL_TREE;
     }
 
@@ -6985,8 +7095,8 @@ arm_handle_cmse_nonsecure_call (tree *node, tree name,
   if (!use_cmse)
     {
       *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
-              name);
+      warning (OPT_Wattributes, "%qE attribute ignored without %<-mcmse%> "
+              "option.", name);
       return NULL_TREE;
     }
 
@@ -7300,21 +7410,34 @@ legitimate_pic_operand_p (rtx x)
   return 1;
 }
 
-/* Record that the current function needs a PIC register.  Initialize
-   cfun->machine->pic_reg if we have not already done so.  */
+/* Record that the current function needs a PIC register.  If PIC_REG is null,
+   a new pseudo is allocated as PIC register, otherwise PIC_REG is used.  In
+   both case cfun->machine->pic_reg is initialized if we have not already done
+   so.  COMPUTE_NOW decide whether and where to set the PIC register.  If true,
+   PIC register is reloaded in the current position of the instruction stream
+   irregardless of whether it was loaded before.  Otherwise, it is only loaded
+   if not already done so (crtl->uses_pic_offset_table is null).  Note that
+   nonnull PIC_REG is only supported iff COMPUTE_NOW is true and null PIC_REG
+   is only supported iff COMPUTE_NOW is false.  */
 
 static void
-require_pic_register (void)
+require_pic_register (rtx pic_reg, bool compute_now)
 {
+  gcc_assert (compute_now == (pic_reg != NULL_RTX));
+
   /* A lot of the logic here is made obscure by the fact that this
      routine gets called as part of the rtx cost estimation process.
      We don't want those calls to affect any assumptions about the real
      function; and further, we can't call entry_of_function() until we
      start the real expansion process.  */
-  if (!crtl->uses_pic_offset_table)
+  if (!crtl->uses_pic_offset_table || compute_now)
     {
-      gcc_assert (can_create_pseudo_p ());
+      gcc_assert (can_create_pseudo_p ()
+                 || (pic_reg != NULL_RTX
+                     && REG_P (pic_reg)
+                     && GET_MODE (pic_reg) == Pmode));
       if (arm_pic_register != INVALID_REGNUM
+         && !compute_now
          && !(TARGET_THUMB1 && arm_pic_register > LAST_LO_REGNUM))
        {
          if (!cfun->machine->pic_reg)
@@ -7330,8 +7453,10 @@ require_pic_register (void)
        {
          rtx_insn *seq, *insn;
 
+         if (pic_reg == NULL_RTX)
+           pic_reg = gen_reg_rtx (Pmode);
          if (!cfun->machine->pic_reg)
-           cfun->machine->pic_reg = gen_reg_rtx (Pmode);
+           cfun->machine->pic_reg = pic_reg;
 
          /* Play games to avoid marking the function as needing pic
             if we are being called as part of the cost-estimation
@@ -7342,11 +7467,12 @@ require_pic_register (void)
              start_sequence ();
 
              if (TARGET_THUMB1 && arm_pic_register != INVALID_REGNUM
-                 && arm_pic_register > LAST_LO_REGNUM)
+                 && arm_pic_register > LAST_LO_REGNUM
+                 && !compute_now)
                emit_move_insn (cfun->machine->pic_reg,
                                gen_rtx_REG (Pmode, arm_pic_register));
              else
-               arm_load_pic_register (0UL);
+               arm_load_pic_register (0UL, pic_reg);
 
              seq = get_insns ();
              end_sequence ();
@@ -7359,16 +7485,33 @@ require_pic_register (void)
                 we can't yet emit instructions directly in the final
                 insn stream.  Queue the insns on the entry edge, they will
                 be committed after everything else is expanded.  */
-             insert_insn_on_edge (seq,
-                                  single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+             if (currently_expanding_to_rtl)
+               insert_insn_on_edge (seq,
+                                    single_succ_edge
+                                    (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+             else
+               emit_insn (seq);
            }
        }
     }
 }
 
+/* Legitimize PIC load to ORIG into REG.  If REG is NULL, a new pseudo is
+   created to hold the result of the load.  If not NULL, PIC_REG indicates
+   which register to use as PIC register, otherwise it is decided by register
+   allocator.  COMPUTE_NOW forces the PIC register to be loaded at the current
+   location in the instruction stream, irregardless of whether it was loaded
+   previously.  Note that nonnull PIC_REG is only supported iff COMPUTE_NOW is
+   true and null PIC_REG is only supported iff COMPUTE_NOW is false.
+
+   Returns the register REG into which the PIC load is performed.  */
+
 rtx
-legitimize_pic_address (rtx orig, machine_mode mode, rtx reg)
+legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg,
+                       bool compute_now)
 {
+  gcc_assert (compute_now == (pic_reg != NULL_RTX));
+
   if (GET_CODE (orig) == SYMBOL_REF
       || GET_CODE (orig) == LABEL_REF)
     {
@@ -7401,9 +7544,12 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg)
          rtx mem;
 
          /* If this function doesn't have a pic register, create one now.  */
-         require_pic_register ();
+         require_pic_register (pic_reg, compute_now);
+
+         if (pic_reg == NULL_RTX)
+           pic_reg = cfun->machine->pic_reg;
 
-         pat = gen_calculate_pic_address (reg, cfun->machine->pic_reg, orig);
+         pat = gen_calculate_pic_address (reg, pic_reg, orig);
 
          /* Make the MEM as close to a constant as possible.  */
          mem = SET_SRC (pat);
@@ -7452,9 +7598,11 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg)
 
       gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
 
-      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg,
+                                    pic_reg, compute_now);
       offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
-                                      base == reg ? 0 : reg);
+                                      base == reg ? 0 : reg, pic_reg,
+                                      compute_now);
 
       if (CONST_INT_P (offset))
        {
@@ -7554,16 +7702,17 @@ static GTY(()) int pic_labelno;
    low register.  */
 
 void
-arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
+arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED, rtx pic_reg)
 {
-  rtx l1, labelno, pic_tmp, pic_rtx, pic_reg;
+  rtx l1, labelno, pic_tmp, pic_rtx;
 
   if (crtl->uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
     return;
 
   gcc_assert (flag_pic);
 
-  pic_reg = cfun->machine->pic_reg;
+  if (pic_reg == NULL_RTX)
+    pic_reg = cfun->machine->pic_reg;
   if (TARGET_VXWORKS_RTP)
     {
       pic_rtx = gen_rtx_SYMBOL_REF (Pmode, VXWORKS_GOTT_BASE);
@@ -8639,7 +8788,8 @@ arm_legitimize_address (rtx x, rtx orig_x, machine_mode mode)
     {
       /* We need to find and carefully transform any SYMBOL and LABEL
         references; so go back to the original address expression.  */
-      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
+      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX, NULL_RTX,
+                                         false /*compute_now*/);
 
       if (new_x != orig_x)
        x = new_x;
@@ -8707,7 +8857,8 @@ thumb_legitimize_address (rtx x, rtx orig_x, machine_mode mode)
     {
       /* We need to find and carefully transform any SYMBOL and LABEL
         references; so go back to the original address expression.  */
-      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
+      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX, NULL_RTX,
+                                         false /*compute_now*/);
 
       if (new_x != orig_x)
        x = new_x;
@@ -8735,7 +8886,7 @@ arm_tls_referenced_p (rtx x)
             currently implement these if a literal pool is disabled.  */
          if (arm_disable_literal_pool)
            sorry ("accessing thread-local storage is not currently supported "
-                  "with -mpure-code or -mslow-flash-data");
+                  "with %<-mpure-code%> or %<-mslow-flash-data%>");
 
          return true;
        }
@@ -8793,11 +8944,16 @@ static bool
 arm_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
 {
   rtx base, offset;
+  split_const (x, &base, &offset);
 
-  if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
+  if (SYMBOL_REF_P (base))
     {
-      split_const (x, &base, &offset);
-      if (GET_CODE (base) == SYMBOL_REF
+      /* Function symbols cannot have an offset due to the Thumb bit.  */
+      if ((SYMBOL_REF_FLAGS (base) & SYMBOL_FLAG_FUNCTION)
+         && INTVAL (offset) != 0)
+       return true;
+
+      if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P
          && !offset_within_block_p (base, INTVAL (offset)))
        return true;
     }
@@ -9210,10 +9366,89 @@ arm_unspec_cost (rtx x, enum rtx_code /* outer_code */, bool speed_p, int *cost)
                return true;                                            \
              }                                                         \
          }                                                             \
-       while (0);
+       while (0)
+
+/* Helper function for arm_rtx_costs_internal.  Calculates the cost of a MEM,
+   considering the costs of the addressing mode and memory access
+   separately.  */
+static bool
+arm_mem_costs (rtx x, const struct cpu_cost_table *extra_cost,
+              int *cost, bool speed_p)
+{
+  machine_mode mode = GET_MODE (x);
+
+  *cost = COSTS_N_INSNS (1);
+
+  if (flag_pic
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && will_be_in_index_register (XEXP (XEXP (x, 0), 1)))
+    /* This will be split into two instructions.  Add the cost of the
+       additional instruction here.  The cost of the memory access is computed
+       below.  See arm.md:calculate_pic_address.  */
+    *cost += COSTS_N_INSNS (1);
+
+  /* Calculate cost of the addressing mode.  */
+  if (speed_p)
+    {
+      arm_addr_mode_op op_type;
+      switch (GET_CODE (XEXP (x, 0)))
+       {
+       default:
+       case REG:
+         op_type = AMO_DEFAULT;
+         break;
+       case MINUS:
+         /* MINUS does not appear in RTL, but the architecture supports it,
+            so handle this case defensively.  */
+         /* fall through */
+       case PLUS:
+         op_type = AMO_NO_WB;
+         break;
+       case PRE_INC:
+       case PRE_DEC:
+       case POST_INC:
+       case POST_DEC:
+       case PRE_MODIFY:
+       case POST_MODIFY:
+         op_type = AMO_WB;
+         break;
+       }
+
+      if (VECTOR_MODE_P (mode))
+         *cost += current_tune->addr_mode_costs->vector[op_type];
+      else if (FLOAT_MODE_P (mode))
+         *cost += current_tune->addr_mode_costs->fp[op_type];
+      else
+         *cost += current_tune->addr_mode_costs->integer[op_type];
+    }
+
+  /* Calculate cost of memory access.  */
+  if (speed_p)
+    {
+      if (FLOAT_MODE_P (mode))
+       {
+         if (GET_MODE_SIZE (mode) == 8)
+           *cost += extra_cost->ldst.loadd;
+         else
+           *cost += extra_cost->ldst.loadf;
+       }
+      else if (VECTOR_MODE_P (mode))
+       *cost += extra_cost->ldst.loadv;
+      else
+       {
+         /* Integer modes */
+         if (GET_MODE_SIZE (mode) == 8)
+           *cost += extra_cost->ldst.ldrd;
+         else
+           *cost += extra_cost->ldst.load;
+       }
+    }
+
+  return true;
+}
 
 /* RTX costs.  Make an estimate of the cost of executing the operation
-   X, which is contained with an operation with code OUTER_CODE.
+   X, which is contained within an operation with code OUTER_CODE.
    SPEED_P indicates whether the cost desired is the performance cost,
    or the size cost.  The estimate is stored in COST and the return
    value is TRUE if the cost calculation is final, or FALSE if the
@@ -9292,30 +9527,7 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
       return false;
 
     case MEM:
-      /* A memory access costs 1 insn if the mode is small, or the address is
-        a single register, otherwise it costs one insn per word.  */
-      if (REG_P (XEXP (x, 0)))
-       *cost = COSTS_N_INSNS (1);
-      else if (flag_pic
-              && GET_CODE (XEXP (x, 0)) == PLUS
-              && will_be_in_index_register (XEXP (XEXP (x, 0), 1)))
-       /* This will be split into two instructions.
-          See arm.md:calculate_pic_address.  */
-       *cost = COSTS_N_INSNS (2);
-      else
-       *cost = COSTS_N_INSNS (ARM_NUM_REGS (mode));
-
-      /* For speed optimizations, add the costs of the address and
-        accessing memory.  */
-      if (speed_p)
-#ifdef NOT_YET
-       *cost += (extra_cost->ldst.load
-                 + arm_address_cost (XEXP (x, 0), mode,
-                                     ADDR_SPACE_GENERIC, speed_p));
-#else
-        *cost += extra_cost->ldst.load;
-#endif
-      return true;
+      return arm_mem_costs (x, extra_cost, cost, speed_p);
 
     case PARALLEL:
     {
@@ -9418,6 +9630,9 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
                   + rtx_cost (XEXP (x, 0), mode, code, 0, speed_p));
          if (speed_p)
            *cost += 2 * extra_cost->alu.shift;
+         /* Slightly disparage left shift by 1 at so we prefer adddi3.  */
+         if (code == ASHIFT && XEXP (x, 1) == CONST1_RTX (SImode))
+           *cost += 1;
          return true;
        }
       else if (mode == SImode)
@@ -9639,8 +9854,8 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
          /* We check both sides of the MINUS for shifter operands since,
             unlike PLUS, it's not commutative.  */
 
-         HANDLE_NARROW_SHIFT_ARITH (MINUS, 0)
-         HANDLE_NARROW_SHIFT_ARITH (MINUS, 1)
+         HANDLE_NARROW_SHIFT_ARITH (MINUS, 0);
+         HANDLE_NARROW_SHIFT_ARITH (MINUS, 1);
 
          /* Slightly disparage, as we might need to widen the result.  */
          *cost += 1;
@@ -9751,7 +9966,7 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
          rtx shift_op, shift_reg;
          shift_reg = NULL;
 
-         HANDLE_NARROW_SHIFT_ARITH (PLUS, 0)
+         HANDLE_NARROW_SHIFT_ARITH (PLUS, 0);
 
          if (CONST_INT_P (XEXP (x, 1)))
            {
@@ -9866,8 +10081,7 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
 
       if (mode == DImode)
        {
-         if (arm_arch3m
-             && GET_CODE (XEXP (x, 0)) == MULT
+         if (GET_CODE (XEXP (x, 0)) == MULT
              && ((GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
                   && GET_CODE (XEXP (XEXP (x, 0), 1)) == ZERO_EXTEND)
                  || (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
@@ -10065,11 +10279,10 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
 
       if (mode == DImode)
        {
-         if (arm_arch3m
-             && ((GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
-                  && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
-                 || (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
-                     && GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)))
+         if ((GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+               && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
+              || (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+                  && GET_CODE (XEXP (x, 1)) == SIGN_EXTEND))
            {
              if (speed_p)
                *cost += extra_cost->mult[1].extend;
@@ -10930,7 +11143,7 @@ arm_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
                                current_tune->insn_extra_cost,
                                total, speed);
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  if (dump_file && arm_verbose_cost)
     {
       print_rtl_single (dump_file, x);
       fprintf (dump_file, "\n%s cost: %d (%s)\n", speed ? "Hot" : "Cold",
@@ -11241,9 +11454,11 @@ arm_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
         return current_tune->vec_costs->scalar_to_vec_cost;
 
       case unaligned_load:
+      case vector_gather_load:
         return current_tune->vec_costs->vec_unalign_load_cost;
 
       case unaligned_store:
+      case vector_scatter_store:
         return current_tune->vec_costs->vec_unalign_store_cost;
 
       case cond_branch_taken:
@@ -11316,8 +11531,8 @@ cortexa7_older_only (rtx_insn *insn)
     case TYPE_SHIFT_IMM:
     case TYPE_SHIFT_REG:
     case TYPE_LOAD_BYTE:
-    case TYPE_LOAD1:
-    case TYPE_STORE1:
+    case TYPE_LOAD_4:
+    case TYPE_STORE_4:
     case TYPE_FFARITHS:
     case TYPE_FADDS:
     case TYPE_FFARITHD:
@@ -12142,13 +12357,13 @@ neon_vdup_constant (rtx vals)
      load.  */
 
   x = copy_to_mode_reg (inner_mode, x);
-  return gen_rtx_VEC_DUPLICATE (mode, x);
+  return gen_vec_duplicate (mode, x);
 }
 
 /* Generate code to load VALS, which is a PARALLEL containing only
    constants (for vec_init) or CONST_VECTOR, efficiently into a
    register.  Returns an RTX to copy into the register, or NULL_RTX
-   for a PARALLEL that can not be converted into a CONST_VECTOR.  */
+   for a PARALLEL that cannot be converted into a CONST_VECTOR.  */
 
 rtx
 neon_make_constant (rtx vals)
@@ -12190,13 +12405,13 @@ neon_make_constant (rtx vals)
     return target;
   else if (const_vec != NULL_RTX)
     /* Load from constant pool.  On Cortex-A8 this takes two cycles
-       (for either double or quad vectors).  We can not take advantage
+       (for either double or quad vectors).  We cannot take advantage
        of single-cycle VLD1 because we need a PC-relative addressing
        mode.  */
     return const_vec;
   else
     /* A PARALLEL containing something not valid inside CONST_VECTOR.
-       We can not construct an initializer.  */
+       We cannot construct an initializer.  */
     return NULL_RTX;
 }
 
@@ -12237,7 +12452,7 @@ neon_expand_vector_init (rtx target, rtx vals)
   if (all_same && GET_MODE_SIZE (inner_mode) <= 4)
     {
       x = copy_to_mode_reg (inner_mode, XVECEXP (vals, 0, 0));
-      emit_insn (gen_rtx_SET (target, gen_rtx_VEC_DUPLICATE (mode, x)));
+      emit_insn (gen_rtx_SET (target, gen_vec_duplicate (mode, x)));
       return;
     }
 
@@ -12534,6 +12749,43 @@ neon_struct_mem_operand (rtx op)
   return FALSE;
 }
 
+/* Prepares the operands for the VCMLA by lane instruction such that the right
+   register number is selected.  This instruction is special in that it always
+   requires a D register, however there is a choice to be made between Dn[0],
+   Dn[1], D(n+1)[0], and D(n+1)[1] depending on the mode of the registers.
+
+   The VCMLA by lane function always selects two values. For instance given D0
+   and a V2SF, the only valid index is 0 as the values in S0 and S1 will be
+   used by the instruction.  However given V4SF then index 0 and 1 are valid as
+   D0[0] or D1[0] are both valid.
+
+   This function centralizes that information based on OPERANDS, OPERANDS[3]
+   will be changed from a REG into a CONST_INT RTX and OPERANDS[4] will be
+   updated to contain the right index.  */
+
+rtx *
+neon_vcmla_lane_prepare_operands (rtx *operands)
+{
+  int lane = INTVAL (operands[4]);
+  machine_mode constmode = SImode;
+  machine_mode mode = GET_MODE (operands[3]);
+  int regno = REGNO (operands[3]);
+  regno = ((regno - FIRST_VFP_REGNUM) >> 1);
+  if (lane > 0 && lane >= GET_MODE_NUNITS (mode) / 4)
+    {
+      operands[3] = gen_int_mode (regno + 1, constmode);
+      operands[4]
+       = gen_int_mode (lane - GET_MODE_NUNITS (mode) / 4, constmode);
+    }
+  else
+    {
+      operands[3] = gen_int_mode (regno, constmode);
+      operands[4] = gen_int_mode (lane, constmode);
+    }
+  return operands;
+}
+
+
 /* Return true if X is a register that will be eliminated later on.  */
 int
 arm_eliminable_register (rtx x)
@@ -12948,6 +13200,9 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
   if (load && (REGNO (reg) == SP_REGNUM) && (REGNO (addr) != SP_REGNUM))
     return false;
 
+  if (regno == REGNO (addr))
+    addr_reg_in_reglist = true;
+
   for (; i < count; i++)
     {
       elt = XVECEXP (op, 0, i);
@@ -13142,7 +13397,6 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order,
   int unsorted_regs[MAX_LDM_STM_OPS];
   HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS];
   int order[MAX_LDM_STM_OPS];
-  rtx base_reg_rtx = NULL;
   int base_reg = -1;
   int i, ldm_case;
 
@@ -13187,7 +13441,6 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order,
          if (i == 0)
            {
              base_reg = REGNO (reg);
-             base_reg_rtx = reg;
              if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM)
                return 0;
            }
@@ -13246,10 +13499,6 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order,
       *load_offset = unsorted_offsets[order[0]];
     }
 
-  if (TARGET_THUMB1
-      && !peep2_reg_dead_p (nops, base_reg_rtx))
-    return 0;
-
   if (unsorted_offsets[order[0]] == 0)
     ldm_case = 1; /* ldmia */
   else if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
@@ -13625,9 +13874,17 @@ gen_ldm_seq (rtx *operands, int nops, bool sort_regs)
 
   if (TARGET_THUMB1)
     {
-      gcc_assert (peep2_reg_dead_p (nops, base_reg_rtx));
       gcc_assert (ldm_case == 1 || ldm_case == 5);
-      write_back = TRUE;
+
+      /* Thumb-1 ldm uses writeback except if the base is loaded.  */
+      write_back = true;
+      for (i = 0; i < nops; i++)
+       if (base_reg == regs[i])
+         write_back = false;
+
+      /* Ensure the base is dead if it is updated.  */
+      if (write_back && !peep2_reg_dead_p (nops, base_reg_rtx))
+       return false;
     }
 
   if (ldm_case == 5)
@@ -13635,8 +13892,7 @@ gen_ldm_seq (rtx *operands, int nops, bool sort_regs)
       rtx newbase = TARGET_THUMB1 ? base_reg_rtx : gen_rtx_REG (SImode, regs[0]);
       emit_insn (gen_addsi3 (newbase, base_reg_rtx, GEN_INT (offset)));
       offset = 0;
-      if (!TARGET_THUMB1)
-       base_reg_rtx = newbase;
+      base_reg_rtx = newbase;
     }
 
   for (i = 0; i < nops; i++)
@@ -13845,7 +14101,7 @@ arm_block_move_unaligned_straight (rtx dstbase, rtx srcbase,
   HOST_WIDE_INT src_autoinc, dst_autoinc;
   rtx mem, addr;
   
-  gcc_assert (1 <= interleave_factor && interleave_factor <= 4);
+  gcc_assert (interleave_factor >= 1 && interleave_factor <= 4);
   
   /* Use hard registers if we have aligned source or destination so we can use
      load/store multiple with contiguous registers.  */
@@ -15282,12 +15538,23 @@ operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rn, HOST_WIDE_INT offset,
   return true;
 }
 
+/* Return true if a 64-bit access with alignment ALIGN and with a
+   constant offset OFFSET from the base pointer is permitted on this
+   architecture.  */
+static bool
+align_ok_ldrd_strd (HOST_WIDE_INT align, HOST_WIDE_INT offset)
+{
+  return (unaligned_access
+         ? (align >= BITS_PER_WORD && (offset & 3) == 0)
+         : (align >= 2 * BITS_PER_WORD && (offset & 7) == 0));
+}
+
 /* Helper for gen_operands_ldrd_strd.  Returns true iff the memory
    operand MEM's address contains an immediate offset from the base
-   register and has no side effects, in which case it sets BASE and
-   OFFSET accordingly.  */
+   register and has no side effects, in which case it sets BASE,
+   OFFSET and ALIGN accordingly.  */
 static bool
-mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset)
+mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset, HOST_WIDE_INT *align)
 {
   rtx addr;
 
@@ -15306,6 +15573,7 @@ mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset)
   gcc_assert (MEM_P (mem));
 
   *offset = const0_rtx;
+  *align = MEM_ALIGN (mem);
 
   addr = XEXP (mem, 0);
 
@@ -15319,7 +15587,7 @@ mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset)
       *base = addr;
       return true;
     }
-  else if (GET_CODE (addr) == PLUS || GET_CODE (addr) == MINUS)
+  else if (GET_CODE (addr) == PLUS)
     {
       *base = XEXP (addr, 0);
       *offset = XEXP (addr, 1);
@@ -15346,7 +15614,7 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
                         bool const_store, bool commute)
 {
   int nops = 2;
-  HOST_WIDE_INT offsets[2], offset;
+  HOST_WIDE_INT offsets[2], offset, align[2];
   rtx base = NULL_RTX;
   rtx cur_base, cur_offset, tmp;
   int i, gap;
@@ -15358,7 +15626,8 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
      registers, and the corresponding memory offsets.  */
   for (i = 0; i < nops; i++)
     {
-      if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset))
+      if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset,
+                                &align[i]))
         return false;
 
       if (i == 0)
@@ -15472,6 +15741,7 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
       /* Swap the instructions such that lower memory is accessed first.  */
       std::swap (operands[0], operands[1]);
       std::swap (operands[2], operands[3]);
+      std::swap (align[0], align[1]);
       if (const_store)
         std::swap (operands[4], operands[5]);
     }
@@ -15482,7 +15752,10 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
     }
 
   /* Make sure accesses are to consecutive memory locations.  */
-  if (gap != 4)
+  if (gap != GET_MODE_SIZE (SImode))
+    return false;
+
+  if (!align_ok_ldrd_strd (align[0], offset))
     return false;
 
   /* Make sure we generate legal instructions.  */
@@ -15560,6 +15833,55 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
 }
 
 
+/* Return true if parallel execution of the two word-size accesses provided
+   could be satisfied with a single LDRD/STRD instruction.  Two word-size
+   accesses are represented by the OPERANDS array, where OPERANDS[0,1] are
+   register operands and OPERANDS[2,3] are the corresponding memory operands.
+   */
+bool
+valid_operands_ldrd_strd (rtx *operands, bool load)
+{
+  int nops = 2;
+  HOST_WIDE_INT offsets[2], offset, align[2];
+  rtx base = NULL_RTX;
+  rtx cur_base, cur_offset;
+  int i, gap;
+
+  /* Check that the memory references are immediate offsets from the
+     same base register.  Extract the base register, the destination
+     registers, and the corresponding memory offsets.  */
+  for (i = 0; i < nops; i++)
+    {
+      if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset,
+                                &align[i]))
+       return false;
+
+      if (i == 0)
+       base = cur_base;
+      else if (REGNO (base) != REGNO (cur_base))
+       return false;
+
+      offsets[i] = INTVAL (cur_offset);
+      if (GET_CODE (operands[i]) == SUBREG)
+       return false;
+    }
+
+  if (offsets[0] > offsets[1])
+    return false;
+
+  gap = offsets[1] - offsets[0];
+  offset = offsets[0];
+
+  /* Make sure accesses are to consecutive memory locations.  */
+  if (gap != GET_MODE_SIZE (SImode))
+    return false;
+
+  if (!align_ok_ldrd_strd (align[0], offset))
+    return false;
+
+  return operands_ok_ldrd_strd (operands[0], operands[1], base, offset,
+                               false, load);
+}
 
 \f
 /* Print a symbolic form of X to the debug file, F.  */
@@ -15794,7 +16116,7 @@ get_label_padding (rtx label)
 {
   HOST_WIDE_INT align, min_insn_size;
 
-  align = 1 << label_to_alignment (label);
+  align = 1 << label_to_alignment (label).levels[0].log;
   min_insn_size = TARGET_THUMB ? 2 : 4;
   return align > min_insn_size ? align - min_insn_size : 0;
 }
@@ -15867,7 +16189,7 @@ add_minipool_forward_ref (Mfix *fix)
   Mnode *       mp;
 
   /* If the minipool starts before the end of FIX->INSN then this FIX
-     can not be placed into the current pool.  Furthermore, adding the
+     cannot be placed into the current pool.  Furthermore, adding the
      new constant pool entry may cause the pool to start FIX_SIZE bytes
      earlier.  */
   if (minipool_vector_head &&
@@ -16393,16 +16715,6 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
   /* Make sure that we found a place to insert the jump.  */
   gcc_assert (selected);
 
-  /* Make sure we do not split a call and its corresponding
-     CALL_ARG_LOCATION note.  */
-  if (CALL_P (selected))
-    {
-      rtx_insn *next = NEXT_INSN (selected);
-      if (next && NOTE_P (next)
-         && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION)
-         selected = next;
-    }
-
   /* Create a new JUMP_INSN that branches around a barrier.  */
   from = emit_jump_insn_after (gen_jump (label), selected);
   JUMP_LABEL (from) = label;
@@ -16940,6 +17252,128 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Clear registers secret before doing a cmse_nonsecure_call or returning from
+   a cmse_nonsecure_entry function.  TO_CLEAR_BITMAP indicates which registers
+   are to be fully cleared, using the value in register CLEARING_REG if more
+   efficient.  The PADDING_BITS_LEN entries array PADDING_BITS_TO_CLEAR gives
+   the bits that needs to be cleared in caller-saved core registers, with
+   SCRATCH_REG used as a scratch register for that clearing.
+
+   NOTE: one of three following assertions must hold:
+   - SCRATCH_REG is a low register
+   - CLEARING_REG is in the set of registers fully cleared (ie. its bit is set
+     in TO_CLEAR_BITMAP)
+   - CLEARING_REG is a low register.  */
+
+static void
+cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
+                     int padding_bits_len, rtx scratch_reg, rtx clearing_reg)
+{
+  bool saved_clearing = false;
+  rtx saved_clearing_reg = NULL_RTX;
+  int i, regno, clearing_regno, minregno = R0_REGNUM, maxregno = minregno - 1;
+
+  gcc_assert (arm_arch_cmse);
+
+  if (!bitmap_empty_p (to_clear_bitmap))
+    {
+      minregno = bitmap_first_set_bit (to_clear_bitmap);
+      maxregno = bitmap_last_set_bit (to_clear_bitmap);
+    }
+  clearing_regno = REGNO (clearing_reg);
+
+  /* Clear padding bits.  */
+  gcc_assert (padding_bits_len <= NUM_ARG_REGS);
+  for (i = 0, regno = R0_REGNUM; i < padding_bits_len; i++, regno++)
+    {
+      uint64_t mask;
+      rtx rtx16, dest, cleared_reg = gen_rtx_REG (SImode, regno);
+
+      if (padding_bits_to_clear[i] == 0)
+       continue;
+
+      /* If this is a Thumb-1 target and SCRATCH_REG is not a low register, use
+        CLEARING_REG as scratch.  */
+      if (TARGET_THUMB1
+         && REGNO (scratch_reg) > LAST_LO_REGNUM)
+       {
+         /* clearing_reg is not to be cleared, copy its value into scratch_reg
+            such that we can use clearing_reg to clear the unused bits in the
+            arguments.  */
+         if ((clearing_regno > maxregno
+              || !bitmap_bit_p (to_clear_bitmap, clearing_regno))
+             && !saved_clearing)
+           {
+             gcc_assert (clearing_regno <= LAST_LO_REGNUM);
+             emit_move_insn (scratch_reg, clearing_reg);
+             saved_clearing = true;
+             saved_clearing_reg = scratch_reg;
+           }
+         scratch_reg = clearing_reg;
+       }
+
+      /* Fill the lower half of the negated padding_bits_to_clear[i].  */
+      mask = (~padding_bits_to_clear[i]) & 0xFFFF;
+      emit_move_insn (scratch_reg, gen_int_mode (mask, SImode));
+
+      /* Fill the top half of the negated padding_bits_to_clear[i].  */
+      mask = (~padding_bits_to_clear[i]) >> 16;
+      rtx16 = gen_int_mode (16, SImode);
+      dest = gen_rtx_ZERO_EXTRACT (SImode, scratch_reg, rtx16, rtx16);
+      if (mask)
+       emit_insn (gen_rtx_SET (dest, gen_int_mode (mask, SImode)));
+
+      emit_insn (gen_andsi3 (cleared_reg, cleared_reg, scratch_reg));
+    }
+  if (saved_clearing)
+    emit_move_insn (clearing_reg, saved_clearing_reg);
+
+
+  /* Clear full registers.  */
+
+  /* If not marked for clearing, clearing_reg already does not contain
+     any secret.  */
+  if (clearing_regno <= maxregno
+      && bitmap_bit_p (to_clear_bitmap, clearing_regno))
+    {
+      emit_move_insn (clearing_reg, const0_rtx);
+      emit_use (clearing_reg);
+      bitmap_clear_bit (to_clear_bitmap, clearing_regno);
+    }
+
+  for (regno = minregno; regno <= maxregno; regno++)
+    {
+      if (!bitmap_bit_p (to_clear_bitmap, regno))
+       continue;
+
+      if (IS_VFP_REGNUM (regno))
+       {
+         /* If regno is an even vfp register and its successor is also to
+            be cleared, use vmov.  */
+         if (TARGET_VFP_DOUBLE
+             && VFP_REGNO_OK_FOR_DOUBLE (regno)
+             && bitmap_bit_p (to_clear_bitmap, regno + 1))
+           {
+             emit_move_insn (gen_rtx_REG (DFmode, regno),
+                             CONST1_RTX (DFmode));
+             emit_use (gen_rtx_REG (DFmode, regno));
+             regno++;
+           }
+         else
+           {
+             emit_move_insn (gen_rtx_REG (SFmode, regno),
+                             CONST1_RTX (SFmode));
+             emit_use (gen_rtx_REG (SFmode, regno));
+           }
+       }
+      else
+       {
+         emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
+         emit_use (gen_rtx_REG (SImode, regno));
+       }
+    }
+}
+
 /* Clears caller saved registers not used to pass arguments before a
    cmse_nonsecure_call.  Saving, clearing and restoring of callee saved
    registers is done in __gnu_cmse_nonsecure_call libcall.
@@ -16956,18 +17390,18 @@ cmse_nonsecure_call_clear_caller_saved (void)
 
       FOR_BB_INSNS (bb, insn)
        {
-         uint64_t to_clear_mask, float_mask;
+         unsigned address_regnum, regno, maxregno =
+           TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : NUM_ARG_REGS - 1;
+         auto_sbitmap to_clear_bitmap (maxregno + 1);
          rtx_insn *seq;
-         rtx pat, call, unspec, reg, cleared_reg, tmp;
-         unsigned int regno, maxregno;
+         rtx pat, call, unspec, clearing_reg, ip_reg, shift;
          rtx address;
          CUMULATIVE_ARGS args_so_far_v;
          cumulative_args_t args_so_far;
          tree arg_type, fntype;
-         bool using_r4, first_param = true;
+         bool first_param = true;
          function_args_iterator args_iter;
          uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
-         uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
 
          if (!NONDEBUG_INSN_P (insn))
            continue;
@@ -16990,18 +17424,21 @@ cmse_nonsecure_call_clear_caller_saved (void)
            continue;
 
          /* Determine the caller-saved registers we need to clear.  */
-         to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
-         maxregno = NUM_ARG_REGS - 1;
+         bitmap_clear (to_clear_bitmap);
+         bitmap_set_range (to_clear_bitmap, R0_REGNUM, NUM_ARG_REGS);
+
          /* Only look at the caller-saved floating point registers in case of
             -mfloat-abi=hard.  For -mfloat-abi=softfp we will be using the
             lazy store and loads which clear both caller- and callee-saved
             registers.  */
          if (TARGET_HARD_FLOAT_ABI)
            {
-             float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
-             float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
-             to_clear_mask |= float_mask;
-             maxregno = D7_VFP_REGNUM;
+             auto_sbitmap float_bitmap (maxregno + 1);
+
+             bitmap_clear (float_bitmap);
+             bitmap_set_range (float_bitmap, FIRST_VFP_REGNUM,
+                               D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1);
+             bitmap_ior (to_clear_bitmap, to_clear_bitmap, float_bitmap);
            }
 
          /* Make sure the register used to hold the function address is not
@@ -17009,7 +17446,9 @@ cmse_nonsecure_call_clear_caller_saved (void)
          address = RTVEC_ELT (XVEC (unspec, 0), 0);
          gcc_assert (MEM_P (address));
          gcc_assert (REG_P (XEXP (address, 0)));
-         to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+         address_regnum = REGNO (XEXP (address, 0));
+         if (address_regnum < R0_REGNUM + NUM_ARG_REGS)
+           bitmap_clear_bit (to_clear_bitmap, address_regnum);
 
          /* Set basic block of call insn so that df rescan is performed on
             insns inserted here.  */
@@ -17030,6 +17469,7 @@ cmse_nonsecure_call_clear_caller_saved (void)
          FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
            {
              rtx arg_rtx;
+             uint64_t to_clear_args_mask;
              machine_mode arg_mode = TYPE_MODE (arg_type);
 
              if (VOID_TYPE_P (arg_type))
@@ -17042,92 +17482,40 @@ cmse_nonsecure_call_clear_caller_saved (void)
              arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
                                          true);
              gcc_assert (REG_P (arg_rtx));
-             to_clear_mask
-               &= ~compute_not_to_clear_mask (arg_type, arg_rtx,
-                                              REGNO (arg_rtx),
-                                              padding_bits_to_clear_ptr);
-
-             first_param = false;
-           }
-
-         /* Clear padding bits where needed.  */
-         cleared_reg = XEXP (address, 0);
-         reg = gen_rtx_REG (SImode, IP_REGNUM);
-         using_r4 = false;
-         for (regno = R0_REGNUM; regno < NUM_ARG_REGS; regno++)
-           {
-             if (padding_bits_to_clear[regno] == 0)
-               continue;
-
-             /* If this is a Thumb-1 target copy the address of the function
-                we are calling from 'r4' into 'ip' such that we can use r4 to
-                clear the unused bits in the arguments.  */
-             if (TARGET_THUMB1 && !using_r4)
+             to_clear_args_mask
+               = compute_not_to_clear_mask (arg_type, arg_rtx,
+                                            REGNO (arg_rtx),
+                                            &padding_bits_to_clear[0]);
+             if (to_clear_args_mask)
                {
-                 using_r4 =  true;
-                 reg = cleared_reg;
-                 emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
-                                         reg);
-               }
-
-             tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
-             emit_move_insn (reg, tmp);
-             /* Also fill the top half of the negated
-                padding_bits_to_clear.  */
-             if (((~padding_bits_to_clear[regno]) >> 16) > 0)
-               {
-                 tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
-                 emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
-                                                               GEN_INT (16),
-                                                               GEN_INT (16)),
-                                         tmp));
-               }
-
-             emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
-                                    gen_rtx_REG (SImode, regno),
-                                    reg));
-
-           }
-         if (using_r4)
-           emit_move_insn (cleared_reg,
-                           gen_rtx_REG (SImode, IP_REGNUM));
-
-         /* We use right shift and left shift to clear the LSB of the address
-            we jump to instead of using bic, to avoid having to use an extra
-            register on Thumb-1.  */
-         tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
-         emit_insn (gen_rtx_SET (cleared_reg, tmp));
-         tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
-         emit_insn (gen_rtx_SET (cleared_reg, tmp));
-
-         /* Clearing all registers that leak before doing a non-secure
-            call.  */
-         for (regno = R0_REGNUM; regno <= maxregno; regno++)
-           {
-             if (!(to_clear_mask & (1LL << regno)))
-               continue;
-
-             /* If regno is an even vfp register and its successor is also to
-                be cleared, use vmov.  */
-             if (IS_VFP_REGNUM (regno))
-               {
-                 if (TARGET_VFP_DOUBLE
-                     && VFP_REGNO_OK_FOR_DOUBLE (regno)
-                     && to_clear_mask & (1LL << (regno + 1)))
-                   emit_move_insn (gen_rtx_REG (DFmode, regno++),
-                                   CONST0_RTX (DFmode));
-                 else
-                   emit_move_insn (gen_rtx_REG (SFmode, regno),
-                                   CONST0_RTX (SFmode));
+                 for (regno = R0_REGNUM; regno <= maxregno; regno++)
+                   {
+                     if (to_clear_args_mask & (1ULL << regno))
+                       bitmap_clear_bit (to_clear_bitmap, regno);
+                   }
                }
-             else
-               emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+
+             first_param = false;
            }
 
+         /* We use right shift and left shift to clear the LSB of the address
+            we jump to instead of using bic, to avoid having to use an extra
+            register on Thumb-1.  */
+         clearing_reg = XEXP (address, 0);
+         shift = gen_rtx_LSHIFTRT (SImode, clearing_reg, const1_rtx);
+         emit_insn (gen_rtx_SET (clearing_reg, shift));
+         shift = gen_rtx_ASHIFT (SImode, clearing_reg, const1_rtx);
+         emit_insn (gen_rtx_SET (clearing_reg, shift));
+
+         /* Clear caller-saved registers that leak before doing a non-secure
+            call.  */
+         ip_reg = gen_rtx_REG (SImode, IP_REGNUM);
+         cmse_clear_registers (to_clear_bitmap, padding_bits_to_clear,
+                               NUM_ARG_REGS, ip_reg, clearing_reg);
+
          seq = get_insns ();
          end_sequence ();
          emit_insn_before (seq, insn);
-
        }
     }
 }
@@ -17434,7 +17822,11 @@ arm_reorg (void)
 
   if (use_cmse)
     cmse_nonsecure_call_clear_caller_saved ();
-  if (TARGET_THUMB1)
+
+  /* We cannot run the Thumb passes for thunks because there is no CFG.  */
+  if (cfun->is_thunk)
+    ;
+  else if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
     thumb2_reorg ();
@@ -17849,7 +18241,7 @@ arm_emit_call_insn (rtx pat, rtx addr, bool sibcall)
          ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
          : !SYMBOL_REF_LOCAL_P (addr)))
     {
-      require_pic_register ();
+      require_pic_register (NULL_RTX, false /*compute_now*/);
       use_reg (&CALL_INSN_FUNCTION_USAGE (insn), cfun->machine->pic_reg);
     }
 
@@ -17868,7 +18260,7 @@ arm_emit_call_insn (rtx pat, rtx addr, bool sibcall)
 const char *
 output_call (rtx *operands)
 {
-  gcc_assert (!arm_arch5); /* Patterns should call blx <reg> directly.  */
+  gcc_assert (!arm_arch5t); /* Patterns should call blx <reg> directly.  */
 
   /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
   if (REGNO (operands[0]) == LR_REGNUM)
@@ -18254,12 +18646,18 @@ output_move_double (rtx *operands, bool emit, int *count)
       gcc_assert ((REGNO (operands[1]) != IP_REGNUM)
                   || (TARGET_ARM && TARGET_LDRD));
 
+      /* For TARGET_ARM the first source register of an STRD
+        must be even.  This is usually the case for double-word
+        values but user assembly constraints can force an odd
+        starting register.  */
+      bool allow_strd = TARGET_LDRD
+                        && !(TARGET_ARM && (REGNO (operands[1]) & 1) == 1);
       switch (GET_CODE (XEXP (operands[0], 0)))
         {
        case REG:
          if (emit)
            {
-             if (TARGET_LDRD)
+             if (allow_strd)
                output_asm_insn ("strd%?\t%1, [%m0]", operands);
              else
                output_asm_insn ("stm%?\t%m0, %M1", operands);
@@ -18267,7 +18665,7 @@ output_move_double (rtx *operands, bool emit, int *count)
          break;
 
         case PRE_INC:
-         gcc_assert (TARGET_LDRD);
+         gcc_assert (allow_strd);
          if (emit)
            output_asm_insn ("strd%?\t%1, [%m0, #8]!", operands);
          break;
@@ -18275,7 +18673,7 @@ output_move_double (rtx *operands, bool emit, int *count)
         case PRE_DEC:
          if (emit)
            {
-             if (TARGET_LDRD)
+             if (allow_strd)
                output_asm_insn ("strd%?\t%1, [%m0, #-8]!", operands);
              else
                output_asm_insn ("stmdb%?\t%m0!, %M1", operands);
@@ -18285,7 +18683,7 @@ output_move_double (rtx *operands, bool emit, int *count)
         case POST_INC:
          if (emit)
            {
-             if (TARGET_LDRD)
+             if (allow_strd)
                output_asm_insn ("strd%?\t%1, [%m0], #8", operands);
              else
                output_asm_insn ("stm%?\t%m0!, %M1", operands);
@@ -18293,7 +18691,7 @@ output_move_double (rtx *operands, bool emit, int *count)
          break;
 
         case POST_DEC:
-         gcc_assert (TARGET_LDRD);
+         gcc_assert (allow_strd);
          if (emit)
            output_asm_insn ("strd%?\t%1, [%m0], #-8", operands);
          break;
@@ -18304,8 +18702,8 @@ output_move_double (rtx *operands, bool emit, int *count)
          otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
          otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
 
-         /* IWMMXT allows offsets larger than ldrd can handle,
-            fix these up with a pair of ldr.  */
+         /* IWMMXT allows offsets larger than strd can handle,
+            fix these up with a pair of str.  */
          if (!TARGET_THUMB2
              && CONST_INT_P (otherops[2])
              && (INTVAL(otherops[2]) <= -256
@@ -18370,7 +18768,7 @@ output_move_double (rtx *operands, bool emit, int *count)
                  return "";
                }
            }
-         if (TARGET_LDRD
+         if (allow_strd
              && (REG_P (otherops[2])
                  || TARGET_THUMB2
                  || (CONST_INT_P (otherops[2])
@@ -18597,7 +18995,7 @@ output_move_neon (rtx *operands)
 
   gcc_assert (REG_P (reg));
   regno = REGNO (reg);
-  nregs = HARD_REGNO_NREGS (regno, mode) / 2;
+  nregs = REG_NREGS (reg) / 2;
   gcc_assert (VFP_REGNO_OK_FOR_DOUBLE (regno)
              || NEON_REGNO_OK_FOR_QUAD (regno));
   gcc_assert (VALID_NEON_DREG_MODE (mode)
@@ -18730,7 +19128,6 @@ arm_attr_length_move_neon (rtx_insn *insn)
 
   gcc_assert (MEM_P (mem));
 
-  mode = GET_MODE (reg);
   addr = XEXP (mem, 0);
 
   /* Strip off const from addresses like (const (plus (...))).  */
@@ -18739,7 +19136,7 @@ arm_attr_length_move_neon (rtx_insn *insn)
 
   if (GET_CODE (addr) == LABEL_REF || GET_CODE (addr) == PLUS)
     {
-      int insns = HARD_REGNO_NREGS (REGNO (reg), mode) / 2;
+      int insns = REG_NREGS (reg) / 2;
       return insns * 4;
     }
   else
@@ -19164,10 +19561,16 @@ arm_r3_live_at_start_p (void)
 static int
 arm_compute_static_chain_stack_bytes (void)
 {
+  /* Once the value is updated from the init value of -1, do not
+     re-compute.  */
+  if (cfun->machine->static_chain_stack_bytes != -1)
+    return cfun->machine->static_chain_stack_bytes;
+
   /* See the defining assertion in arm_expand_prologue.  */
   if (IS_NESTED (arm_current_func_type ())
       && ((TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
-         || (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+         || ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+              || flag_stack_clash_protection)
              && !df_regs_ever_live_p (LR_REGNUM)))
       && arm_r3_live_at_start_p ()
       && crtl->args.pretend_args_size == 0)
@@ -19383,7 +19786,12 @@ arm_get_vfp_saved_size (void)
 
 /* Generate a function exit sequence.  If REALLY_RETURN is false, then do
    everything bar the final return instruction.  If simple_return is true,
-   then do not output epilogue, because it has already been emitted in RTL.  */
+   then do not output epilogue, because it has already been emitted in RTL.
+
+   Note: do not forget to update length attribute of corresponding insn pattern
+   when changing assembly output (eg. length attribute of
+   thumb2_cmse_entry_return when updating Armv8-M Mainline Security Extensions
+   register clearing sequences).  */
 const char *
 output_return_instruction (rtx operand, bool really_return, bool reverse,
                            bool simple_return)
@@ -19493,7 +19901,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
              stack_adjust = offsets->outgoing_args - offsets->saved_regs;
              gcc_assert (stack_adjust == 0 || stack_adjust == 4);
 
-             if (stack_adjust && arm_arch5 && TARGET_ARM)
+             if (stack_adjust && arm_arch5t && TARGET_ARM)
                  sprintf (instr, "ldmib%s\t%%|sp, {", conditional);
              else
                {
@@ -19568,7 +19976,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
          break;
 
        case ARM_FT_INTERWORKED:
-         gcc_assert (arm_arch5 || arm_arch4t);
+         gcc_assert (arm_arch5t || arm_arch4t);
          sprintf (instr, "bx%s\t%%|lr", conditional);
          break;
 
@@ -19590,7 +19998,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
                          "msr%s\tAPSR_nzcvq, %%|lr", conditional);
 
              output_asm_insn (instr, & operand);
-             if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+             if (TARGET_HARD_FLOAT)
                {
                  /* Clear the cumulative exception-status bits (0-4,7) and the
                     condition code bits (28-31) of the FPSCR.  We need to
@@ -19616,7 +20024,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
              snprintf (instr, sizeof (instr), "bxns\t%%|lr");
            }
          /* Use bx if it's available.  */
-         else if (arm_arch5 || arm_arch4t)
+         else if (arm_arch5t || arm_arch4t)
            sprintf (instr, "bx%s\t%%|lr", conditional);
          else
            sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -19753,8 +20161,8 @@ arm_output_function_prologue (FILE *f)
   if (IS_CMSE_ENTRY (func_type))
     asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
 
-  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
-              crtl->args.size,
+  asm_fprintf (f, "\t%@ args = %wd, pretend = %d, frame = %wd\n",
+              (HOST_WIDE_INT) crtl->args.size,
               crtl->args.pretend_args_size,
               (HOST_WIDE_INT) get_frame_size ());
 
@@ -21465,11 +21873,17 @@ arm_expand_prologue (void)
       emit_insn (gen_movsi (stack_pointer_rtx, r1));
     }
 
+  /* Let's compute the static_chain_stack_bytes required and store it.  Right
+     now the value must be -1 as stored by arm_init_machine_status ().  */
+  cfun->machine->static_chain_stack_bytes
+    = arm_compute_static_chain_stack_bytes ();
+
   /* The static chain register is the same as the IP register.  If it is
      clobbered when creating the frame, we need to save and restore it.  */
   clobber_ip = IS_NESTED (func_type)
               && ((TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
-                  || (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+                  || ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+                       || flag_stack_clash_protection)
                       && !df_regs_ever_live_p (LR_REGNUM)
                       && arm_r3_live_at_start_p ()));
 
@@ -21683,7 +22097,8 @@ arm_expand_prologue (void)
      stack checking.  We use IP as the first scratch register, except for the
      non-APCS nested functions if LR or r3 are available (see clobber_ip).  */
   if (!IS_INTERRUPT (func_type)
-      && flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+      && (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+         || flag_stack_clash_protection))
     {
       unsigned int regno;
 
@@ -21696,13 +22111,13 @@ arm_expand_prologue (void)
 
       if (crtl->is_leaf && !cfun->calls_alloca)
        {
-         if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
-           arm_emit_probe_stack_range (STACK_CHECK_PROTECT,
-                                       size - STACK_CHECK_PROTECT,
+         if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+           arm_emit_probe_stack_range (get_stack_check_protect (),
+                                       size - get_stack_check_protect (),
                                        regno, live_regs_mask);
        }
       else if (size > 0)
-       arm_emit_probe_stack_range (STACK_CHECK_PROTECT, size,
+       arm_emit_probe_stack_range (get_stack_check_protect (), size,
                                    regno, live_regs_mask);
     }
 
@@ -21758,7 +22173,7 @@ arm_expand_prologue (void)
       mask &= THUMB2_WORK_REGS;
       if (!IS_NESTED (func_type))
        mask |= (1 << IP_REGNUM);
-      arm_load_pic_register (mask);
+      arm_load_pic_register (mask, NULL_RTX);
     }
 
   /* If we are profiling, make sure no instructions are scheduled before
@@ -23213,7 +23628,7 @@ arm_final_prescan_insn (rtx_insn *insn)
                 used since they make interworking inefficient (the
                 linker can't transform BL<cond> into BLX).  That's
                 only a problem if the machine has BLX.  */
-             if (arm_arch5)
+             if (arm_arch5t)
                {
                  fail = TRUE;
                  break;
@@ -23357,6 +23772,21 @@ thumb2_asm_output_opcode (FILE * stream)
     }
 }
 
+/* Implement TARGET_HARD_REGNO_NREGS.  On the ARM core regs are
+   UNITS_PER_WORD bytes wide.  */
+static unsigned int
+arm_hard_regno_nregs (unsigned int regno, machine_mode mode)
+{
+  if (TARGET_32BIT
+      && regno > PC_REGNUM
+      && regno != FRAME_POINTER_REGNUM
+      && regno != ARG_POINTER_REGNUM
+      && !IS_VFP_REGNUM (regno))
+    return 1;
+
+  return ARM_NUM_REGS (mode);
+}
+
 /* Implement TARGET_HARD_REGNO_MODE_OK.  */
 static bool
 arm_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
@@ -23721,7 +24151,7 @@ neon_split_vcombine (rtx operands[3])
   unsigned int src1 = REGNO (operands[1]);
   unsigned int src2 = REGNO (operands[2]);
   machine_mode halfmode = GET_MODE (operands[1]);
-  unsigned int halfregs = HARD_REGNO_NREGS (src1, halfmode);
+  unsigned int halfregs = REG_NREGS (operands[1]);
   rtx destlo, desthi;
 
   if (src1 == dest && src2 == dest + halfregs)
@@ -23899,7 +24329,12 @@ thumb_pop (FILE *f, unsigned long mask)
 
 /* Generate code to return from a thumb function.
    If 'reg_containing_return_addr' is -1, then the return address is
-   actually on the stack, at the stack pointer.  */
+   actually on the stack, at the stack pointer.
+
+   Note: do not forget to update length attribute of corresponding insn pattern
+   when changing assembly output (eg. length attribute of epilogue_insns when
+   updating Armv8-M Baseline Security Extensions register clearing
+   sequences).  */
 static void
 thumb_exit (FILE *f, int reg_containing_return_addr)
 {
@@ -24619,6 +25054,7 @@ arm_init_machine_status (void)
 #if ARM_FT_UNKNOWN != 0
   machine->func_type = ARM_FT_UNKNOWN;
 #endif
+  machine->static_chain_stack_bytes = -1;
   return machine;
 }
 
@@ -24968,7 +25404,7 @@ thumb1_expand_prologue (void)
   /* Load the pic register before setting the frame pointer,
      so we can use r7 as a temporary work register.  */
   if (flag_pic && arm_pic_register != INVALID_REGNUM)
-    arm_load_pic_register (live_regs_mask);
+    arm_load_pic_register (live_regs_mask, NULL_RTX);
 
   if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
     emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
@@ -24979,8 +25415,10 @@ thumb1_expand_prologue (void)
     current_function_static_stack_size = size;
 
   /* If we have a frame, then do stack checking.  FIXME: not implemented.  */
-  if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
-    sorry ("-fstack-check=specific for Thumb-1");
+  if ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+       || flag_stack_clash_protection)
+      && size)
+    sorry ("%<-fstack-check=specific%> for Thumb-1");
 
   amount = offsets->outgoing_args - offsets->saved_regs;
   amount -= 4 * thumb1_extra_regs_pushed (offsets, true);
@@ -25055,42 +25493,36 @@ thumb1_expand_prologue (void)
 void
 cmse_nonsecure_entry_clear_before_return (void)
 {
-  uint64_t to_clear_mask[2];
+  int regno, maxregno = TARGET_HARD_FLOAT ? LAST_VFP_REGNUM : IP_REGNUM;
   uint32_t padding_bits_to_clear = 0;
-  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
-  int regno, maxregno = IP_REGNUM;
+  auto_sbitmap to_clear_bitmap (maxregno + 1);
+  rtx r1_reg, result_rtl, clearing_reg = NULL_RTX;
   tree result_type;
-  rtx result_rtl;
 
-  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
-  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+  bitmap_clear (to_clear_bitmap);
+  bitmap_set_range (to_clear_bitmap, R0_REGNUM, NUM_ARG_REGS);
+  bitmap_set_bit (to_clear_bitmap, IP_REGNUM);
 
   /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
-     registers.  We also check that TARGET_HARD_FLOAT and !TARGET_THUMB1 hold
-     to make sure the instructions used to clear them are present.  */
-  if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+     registers.  */
+  if (TARGET_HARD_FLOAT)
     {
-      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
-      maxregno = LAST_VFP_REGNUM;
+      int float_bits = D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1;
 
-      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
-      to_clear_mask[0] |= float_mask;
-
-      float_mask = (1ULL << (maxregno - 63)) - 1;
-      to_clear_mask[1] = float_mask;
+      bitmap_set_range (to_clear_bitmap, FIRST_VFP_REGNUM, float_bits);
 
       /* Make sure we don't clear the two scratch registers used to clear the
         relevant FPSCR bits in output_return_instruction.  */
       emit_use (gen_rtx_REG (SImode, IP_REGNUM));
-      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      bitmap_clear_bit (to_clear_bitmap, IP_REGNUM);
       emit_use (gen_rtx_REG (SImode, 4));
-      to_clear_mask[0] &= ~(1ULL << 4);
+      bitmap_clear_bit (to_clear_bitmap, 4);
     }
 
   /* If the user has defined registers to be caller saved, these are no longer
      restored by the function before returning and must thus be cleared for
      security purposes.  */
-  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+  for (regno = NUM_ARG_REGS; regno <= maxregno; regno++)
     {
       /* We do not touch registers that can be used to pass arguments as per
         the AAPCS, since these should never be made callee-saved by user
@@ -25100,96 +25532,51 @@ cmse_nonsecure_entry_clear_before_return (void)
       if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
        continue;
       if (call_used_regs[regno])
-       to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+       bitmap_set_bit (to_clear_bitmap, regno);
     }
 
   /* Make sure we do not clear the registers used to return the result in.  */
   result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
   if (!VOID_TYPE_P (result_type))
     {
+      uint64_t to_clear_return_mask;
       result_rtl = arm_function_value (result_type, current_function_decl, 0);
 
       /* No need to check that we return in registers, because we don't
         support returning on stack yet.  */
-      to_clear_mask[0]
-       &= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
-                                      padding_bits_to_clear_ptr);
+      gcc_assert (REG_P (result_rtl));
+      to_clear_return_mask
+       = compute_not_to_clear_mask (result_type, result_rtl, 0,
+                                    &padding_bits_to_clear);
+      if (to_clear_return_mask)
+       {
+         gcc_assert ((unsigned) maxregno < sizeof (long long) * __CHAR_BIT__);
+         for (regno = R0_REGNUM; regno <= maxregno; regno++)
+           {
+             if (to_clear_return_mask & (1ULL << regno))
+               bitmap_clear_bit (to_clear_bitmap, regno);
+           }
+       }
     }
 
   if (padding_bits_to_clear != 0)
     {
-      rtx reg_rtx;
-      /* Padding bits to clear is not 0 so we know we are dealing with
-        returning a composite type, which only uses r0.  Let's make sure that
-        r1-r3 is cleared too, we will use r1 as a scratch register.  */
-      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
-
-      reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
-
-      /* Fill the lower half of the negated padding_bits_to_clear.  */
-      emit_move_insn (reg_rtx,
-                     GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
-
-      /* Also fill the top half of the negated padding_bits_to_clear.  */
-      if (((~padding_bits_to_clear) >> 16) > 0)
-       emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
-                                                     GEN_INT (16),
-                                                     GEN_INT (16)),
-                               GEN_INT ((~padding_bits_to_clear) >> 16)));
+      int to_clear_bitmap_size = SBITMAP_SIZE ((sbitmap) to_clear_bitmap);
+      auto_sbitmap to_clear_arg_regs_bitmap (to_clear_bitmap_size);
 
-      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, R0_REGNUM),
-                          gen_rtx_REG (SImode, R0_REGNUM),
-                          reg_rtx));
+      /* Padding_bits_to_clear is not 0 so we know we are dealing with
+        returning a composite type, which only uses r0.  Let's make sure that
+        r1-r3 is cleared too.  */
+      bitmap_clear (to_clear_arg_regs_bitmap);
+      bitmap_set_range (to_clear_arg_regs_bitmap, R1_REGNUM, NUM_ARG_REGS - 1);
+      gcc_assert (bitmap_subset_p (to_clear_arg_regs_bitmap, to_clear_bitmap));
     }
 
-  for (regno = R0_REGNUM; regno <= maxregno; regno++)
-    {
-      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
-       continue;
-
-      if (IS_VFP_REGNUM (regno))
-       {
-         /* If regno is an even vfp register and its successor is also to
-            be cleared, use vmov.  */
-         if (TARGET_VFP_DOUBLE
-             && VFP_REGNO_OK_FOR_DOUBLE (regno)
-             && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
-           {
-             emit_move_insn (gen_rtx_REG (DFmode, regno),
-                             CONST1_RTX (DFmode));
-             emit_use (gen_rtx_REG (DFmode, regno));
-             regno++;
-           }
-         else
-           {
-             emit_move_insn (gen_rtx_REG (SFmode, regno),
-                             CONST1_RTX (SFmode));
-             emit_use (gen_rtx_REG (SFmode, regno));
-           }
-       }
-      else
-       {
-         if (TARGET_THUMB1)
-           {
-             if (regno == R0_REGNUM)
-               emit_move_insn (gen_rtx_REG (SImode, regno),
-                               const0_rtx);
-             else
-               /* R0 has either been cleared before, see code above, or it
-                  holds a return value, either way it is not secret
-                  information.  */
-               emit_move_insn (gen_rtx_REG (SImode, regno),
-                               gen_rtx_REG (SImode, R0_REGNUM));
-             emit_use (gen_rtx_REG (SImode, regno));
-           }
-         else
-           {
-             emit_move_insn (gen_rtx_REG (SImode, regno),
-                             gen_rtx_REG (SImode, LR_REGNUM));
-             emit_use (gen_rtx_REG (SImode, regno));
-           }
-       }
-    }
+  /* Clear full registers that leak before returning.  */
+  clearing_reg = gen_rtx_REG (SImode, TARGET_THUMB1 ? R0_REGNUM : LR_REGNUM);
+  r1_reg = gen_rtx_REG (SImode, R0_REGNUM + 1);
+  cmse_clear_registers (to_clear_bitmap, &padding_bits_to_clear, 1, r1_reg,
+                       clearing_reg);
 }
 
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
@@ -26177,6 +26564,7 @@ arm_print_asm_arch_directives ()
   gcc_assert (arch);
 
   asm_fprintf (asm_out_file, "\t.arch %s\n", arm_active_target.arch_name);
+  arm_last_printed_arch_string = arm_active_target.arch_name;
   if (!arch->common.extensions)
     return;
 
@@ -26224,13 +26612,17 @@ arm_file_start (void)
              asm_fprintf (asm_out_file, "\t.arch_extension idiv\n");
              asm_fprintf (asm_out_file, "\t.arch_extension sec\n");
              asm_fprintf (asm_out_file, "\t.arch_extension mp\n");
+             arm_last_printed_arch_string = "armv7ve";
            }
          else
            arm_print_asm_arch_directives ();
        }
       else if (strncmp (arm_active_target.core_name, "generic", 7) == 0)
-       asm_fprintf (asm_out_file, "\t.arch %s\n",
-                    arm_active_target.core_name + 8);
+       {
+         asm_fprintf (asm_out_file, "\t.arch %s\n",
+                      arm_active_target.core_name + 8);
+         arm_last_printed_arch_string = arm_active_target.core_name + 8;
+       }
       else
        {
          const char* truncated_name
@@ -26508,6 +26900,8 @@ static void
 arm32_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
                       HOST_WIDE_INT vcall_offset, tree function)
 {
+  const bool long_call_p = arm_is_long_call_p (function);
+
   /* On ARM, this_regno is R0 or R1 depending on
      whether the function returns an aggregate or not.
   */
@@ -26545,9 +26939,22 @@ arm32_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
       TREE_USED (function) = 1;
     }
   rtx funexp = XEXP (DECL_RTL (function), 0);
+  if (long_call_p)
+    {
+      emit_move_insn (temp, funexp);
+      funexp = temp;
+    }
   funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
-  rtx_insn * insn = emit_call_insn (gen_sibcall (funexp, const0_rtx, NULL_RTX));
+  rtx_insn *insn = emit_call_insn (gen_sibcall (funexp, const0_rtx, NULL_RTX));
   SIBLING_CALL_P (insn) = 1;
+  emit_barrier ();
+
+  /* Indirect calls require a bit of fixup in PIC mode.  */
+  if (long_call_p)
+    {
+      split_all_insns_noflow ();
+      arm_reorg ();
+    }
 
   insn = get_insns ();
   shorten_branches (insn);
@@ -26672,7 +27079,13 @@ arm_setup_incoming_varargs (cumulative_args_t pcum_v,
            inform (input_location, "parameter passing for argument of "
                    "type %qT changed in GCC 7.1", type);
          else if (res > 0)
-           nregs++;
+           {
+             nregs++;
+             if (res > 1 && warn_psabi)
+               inform (input_location,
+                       "parameter passing for argument of type "
+                       "%qT changed in GCC 9.1", type);
+           }
        }
     }
   else
@@ -26823,7 +27236,7 @@ arm_set_return_address (rtx source, rtx scratch)
 {
   arm_stack_offsets *offsets;
   HOST_WIDE_INT delta;
-  rtx addr;
+  rtx addr, mem;
   unsigned long saved_regs;
 
   offsets = arm_get_frame_offsets ();
@@ -26853,11 +27266,12 @@ arm_set_return_address (rtx source, rtx scratch)
 
          addr = plus_constant (Pmode, addr, delta);
        }
-      /* The store needs to be marked as frame related in order to prevent
-        DSE from deleting it as dead if it is based on fp.  */
-      rtx insn = emit_move_insn (gen_frame_mem (Pmode, addr), source);
-      RTX_FRAME_RELATED_P (insn) = 1;
-      add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
+
+      /* The store needs to be marked to prevent DSE from deleting
+        it as dead if it is based on fp.  */
+      mem = gen_frame_mem (Pmode, addr);
+      MEM_VOLATILE_P (mem) = true;
+      emit_move_insn (mem, source);
     }
 }
 
@@ -26869,7 +27283,7 @@ thumb_set_return_address (rtx source, rtx scratch)
   HOST_WIDE_INT delta;
   HOST_WIDE_INT limit;
   int reg;
-  rtx addr;
+  rtx addr, mem;
   unsigned long mask;
 
   emit_use (source);
@@ -26909,11 +27323,11 @@ thumb_set_return_address (rtx source, rtx scratch)
       else
        addr = plus_constant (Pmode, addr, delta);
 
-      /* The store needs to be marked as frame related in order to prevent
-        DSE from deleting it as dead if it is based on fp.  */
-      rtx insn = emit_move_insn (gen_frame_mem (Pmode, addr), source);
-      RTX_FRAME_RELATED_P (insn) = 1;
-      add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
+      /* The store needs to be marked to prevent DSE from deleting
+        it as dead if it is based on fp.  */
+      mem = gen_frame_mem (Pmode, addr);
+      MEM_VOLATILE_P (mem) = true;
+      emit_move_insn (mem, source);
     }
   else
     emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
@@ -26949,7 +27363,10 @@ static bool
 arm_array_mode_supported_p (machine_mode mode,
                            unsigned HOST_WIDE_INT nelems)
 {
-  if (TARGET_NEON
+  /* We don't want to enable interleaved loads and stores for BYTES_BIG_ENDIAN
+     for now, as the lane-swapping logic needs to be extended in the expanders.
+     See PR target/82518.  */
+  if (TARGET_NEON && !BYTES_BIG_ENDIAN
       && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode))
       && (nelems >= 2 && nelems <= 4))
     return true;
@@ -27859,7 +28276,8 @@ arm_frame_pointer_required (void)
      instruction prior to the stack adjustment and this requires a frame
      pointer if we want to catch the exception using the EABI unwinder.  */
   if (!IS_INTERRUPT (arm_current_func_type ())
-      && flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+      && (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+         || flag_stack_clash_protection)
       && arm_except_unwind_info (&global_options) == UI_TARGET
       && cfun->can_throw_non_call_exceptions)
     {
@@ -27874,7 +28292,7 @@ arm_frame_pointer_required (void)
        {
          /* We don't have the final size of the frame so adjust.  */
          size += 32 * UNITS_PER_WORD;
-         if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
+         if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
            return true;
        }
       else
@@ -27904,10 +28322,14 @@ arm_vector_alignment (const_tree type)
   return align;
 }
 
-static unsigned int
-arm_autovectorize_vector_sizes (void)
+static void
+arm_autovectorize_vector_sizes (vector_sizes *sizes)
 {
-  return TARGET_NEON_VECTORIZE_DOUBLE ? 0 : (16 | 8);
+  if (!TARGET_NEON_VECTORIZE_DOUBLE)
+    {
+      sizes->safe_push (16);
+      sizes->safe_push (8);
+    }
 }
 
 static bool
@@ -28138,6 +28560,26 @@ arm_count_output_move_double_insns (rtx *operands)
   return count;
 }
 
+/* Same as above, but operands are a register/memory pair in SImode.
+   Assumes operands has the base register in position 0 and memory in position
+   2 (which is the order provided by the arm_{ldrd,strd} patterns).  */
+int
+arm_count_ldrdstrd_insns (rtx *operands, bool load)
+{
+  int count;
+  rtx ops[2];
+  int regnum, memnum;
+  if (load)
+    regnum = 0, memnum = 1;
+  else
+    regnum = 1, memnum = 0;
+  ops[regnum] = gen_rtx_REG (DImode, REGNO (operands[0]));
+  ops[memnum] = adjust_address (operands[2], DImode, 0);
+  output_move_double (ops, false, &count);
+  return count;
+}
+
+
 int
 vfp3_const_double_for_fract_bits (rtx operand)
 {
@@ -28298,8 +28740,7 @@ void
 arm_expand_compare_and_swap (rtx operands[])
 {
   rtx bval, bdst, rval, mem, oldval, newval, is_weak, mod_s, mod_f, x;
-  machine_mode mode;
-  rtx (*gen) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx);
+  machine_mode mode, cmp_mode;
 
   bval = operands[0];
   rval = operands[1];
@@ -28347,32 +28788,13 @@ arm_expand_compare_and_swap (rtx operands[])
     }
 
   if (TARGET_THUMB1)
-    {
-      switch (mode)
-       {
-       case E_QImode: gen = gen_atomic_compare_and_swapt1qi_1; break;
-       case E_HImode: gen = gen_atomic_compare_and_swapt1hi_1; break;
-       case E_SImode: gen = gen_atomic_compare_and_swapt1si_1; break;
-       case E_DImode: gen = gen_atomic_compare_and_swapt1di_1; break;
-       default:
-         gcc_unreachable ();
-       }
-    }
+    cmp_mode = E_SImode;
   else
-    {
-      switch (mode)
-       {
-       case E_QImode: gen = gen_atomic_compare_and_swap32qi_1; break;
-       case E_HImode: gen = gen_atomic_compare_and_swap32hi_1; break;
-       case E_SImode: gen = gen_atomic_compare_and_swap32si_1; break;
-       case E_DImode: gen = gen_atomic_compare_and_swap32di_1; break;
-       default:
-         gcc_unreachable ();
-       }
-    }
+    cmp_mode = CC_Zmode;
 
   bdst = TARGET_THUMB1 ? bval : gen_rtx_REG (CC_Zmode, CC_REGNUM);
-  emit_insn (gen (bdst, rval, mem, oldval, newval, is_weak, mod_s, mod_f));
+  emit_insn (gen_atomic_compare_and_swap_1 (cmp_mode, mode, bdst, rval, mem,
+                                        oldval, newval, is_weak, mod_s, mod_f));
 
   if (mode == QImode || mode == HImode)
     emit_move_insn (operands[1], gen_lowpart (mode, rval));
@@ -28404,7 +28826,7 @@ arm_expand_compare_and_swap (rtx operands[])
 void
 arm_split_compare_and_swap (rtx operands[])
 {
-  rtx rval, mem, oldval, newval, neg_bval;
+  rtx rval, mem, oldval, newval, neg_bval, mod_s_rtx;
   machine_mode mode;
   enum memmodel mod_s, mod_f;
   bool is_weak;
@@ -28416,20 +28838,16 @@ arm_split_compare_and_swap (rtx operands[])
   oldval = operands[3];
   newval = operands[4];
   is_weak = (operands[5] != const0_rtx);
-  mod_s = memmodel_from_int (INTVAL (operands[6]));
+  mod_s_rtx = operands[6];
+  mod_s = memmodel_from_int (INTVAL (mod_s_rtx));
   mod_f = memmodel_from_int (INTVAL (operands[7]));
   neg_bval = TARGET_THUMB1 ? operands[0] : operands[8];
   mode = GET_MODE (mem);
 
   bool is_armv8_sync = arm_arch8 && is_mm_sync (mod_s);
 
-  bool use_acquire = TARGET_HAVE_LDACQ
-                     && !(is_mm_relaxed (mod_s) || is_mm_consume (mod_s)
-                         || is_mm_release (mod_s));
-               
-  bool use_release = TARGET_HAVE_LDACQ
-                     && !(is_mm_relaxed (mod_s) || is_mm_consume (mod_s)
-                         || is_mm_acquire (mod_s));
+  bool use_acquire = TARGET_HAVE_LDACQ && aarch_mm_needs_acquire (mod_s_rtx);
+  bool use_release = TARGET_HAVE_LDACQ && aarch_mm_needs_release (mod_s_rtx);
 
   /* For ARMv8, the load-acquire is too weak for __sync memory orders.  Instead,
      a full barrier is emitted after the store-release.  */
@@ -28524,13 +28942,8 @@ arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
 
   bool is_armv8_sync = arm_arch8 && is_mm_sync (model);
 
-  bool use_acquire = TARGET_HAVE_LDACQ
-                     && !(is_mm_relaxed (model) || is_mm_consume (model)
-                         || is_mm_release (model));
-
-  bool use_release = TARGET_HAVE_LDACQ
-                     && !(is_mm_relaxed (model) || is_mm_consume (model)
-                         || is_mm_acquire (model));
+  bool use_acquire = TARGET_HAVE_LDACQ && aarch_mm_needs_acquire (model_rtx);
+  bool use_release = TARGET_HAVE_LDACQ && aarch_mm_needs_release (model_rtx);
 
   /* For ARMv8, a load-acquire is too weak for __sync memory orders.  Instead,
      a full barrier is emitted after the store-release.  */
@@ -28639,9 +29052,8 @@ arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
 struct expand_vec_perm_d
 {
   rtx target, op0, op1;
-  unsigned char perm[MAX_VECT_LEN];
+  vec_perm_indices perm;
   machine_mode vmode;
-  unsigned char nelt;
   bool one_vector_p;
   bool testing_p;
 };
@@ -28691,9 +29103,9 @@ void
 arm_expand_vec_perm (rtx target, rtx op0, rtx op1, rtx sel)
 {
   machine_mode vmode = GET_MODE (target);
-  unsigned int i, nelt = GET_MODE_NUNITS (vmode);
+  unsigned int nelt = GET_MODE_NUNITS (vmode);
   bool one_vector_p = rtx_equal_p (op0, op1);
-  rtx rmask[MAX_VECT_LEN], mask;
+  rtx mask;
 
   /* TODO: ARM's VTBL indexing is little-endian.  In order to handle GCC's
      numbering of elements for big-endian, we must reverse the order.  */
@@ -28702,9 +29114,7 @@ arm_expand_vec_perm (rtx target, rtx op0, rtx op1, rtx sel)
   /* The VTBL instruction does not use a modulo index, so we must take care
      of that ourselves.  */
   mask = GEN_INT (one_vector_p ? nelt - 1 : 2 * nelt - 1);
-  for (i = 0; i < nelt; ++i)
-    rmask[i] = mask;
-  mask = gen_rtx_CONST_VECTOR (vmode, gen_rtvec_v (nelt, rmask));
+  mask = gen_const_vec_duplicate (vmode, mask);
   sel = expand_simple_binop (vmode, AND, sel, mask, NULL, 0, OPTAB_LIB_WIDEN);
 
   arm_expand_vec_perm_1 (target, op0, op1, sel);
@@ -28748,9 +29158,8 @@ neon_pair_endian_lane_map (machine_mode mode, int lane)
 static bool
 arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
 {
-  unsigned int i, odd, mask, nelt = d->nelt;
+  unsigned int i, odd, mask, nelt = d->perm.length ();
   rtx out0, out1, in0, in1;
-  rtx (*gen)(rtx, rtx, rtx, rtx);
   int first_elem;
   int swap_nelt;
 
@@ -28760,7 +29169,7 @@ arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
   /* arm_expand_vec_perm_const_1 () helpfully swaps the operands for the
      big endian pattern on 64 bit vectors, so we correct for that.  */
   swap_nelt = BYTES_BIG_ENDIAN && !d->one_vector_p
-    && GET_MODE_SIZE (d->vmode) == 8 ? d->nelt : 0;
+    && GET_MODE_SIZE (d->vmode) == 8 ? nelt : 0;
 
   first_elem = d->perm[neon_endian_lane_map (d->vmode, 0)] ^ swap_nelt;
 
@@ -28784,22 +29193,6 @@ arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
   if (d->testing_p)
     return true;
 
-  switch (d->vmode)
-    {
-    case E_V16QImode: gen = gen_neon_vuzpv16qi_internal; break;
-    case E_V8QImode:  gen = gen_neon_vuzpv8qi_internal;  break;
-    case E_V8HImode:  gen = gen_neon_vuzpv8hi_internal;  break;
-    case E_V4HImode:  gen = gen_neon_vuzpv4hi_internal;  break;
-    case E_V8HFmode:  gen = gen_neon_vuzpv8hf_internal;  break;
-    case E_V4HFmode:  gen = gen_neon_vuzpv4hf_internal;  break;
-    case E_V4SImode:  gen = gen_neon_vuzpv4si_internal;  break;
-    case E_V2SImode:  gen = gen_neon_vuzpv2si_internal;  break;
-    case E_V2SFmode:  gen = gen_neon_vuzpv2sf_internal;  break;
-    case E_V4SFmode:  gen = gen_neon_vuzpv4sf_internal;  break;
-    default:
-      gcc_unreachable ();
-    }
-
   in0 = d->op0;
   in1 = d->op1;
   if (swap_nelt != 0)
@@ -28810,7 +29203,7 @@ arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
   if (odd)
     std::swap (out0, out1);
 
-  emit_insn (gen (out0, in0, in1, out1));
+  emit_insn (gen_neon_vuzp_internal (d->vmode, out0, in0, in1, out1));
   return true;
 }
 
@@ -28819,9 +29212,8 @@ arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
 static bool
 arm_evpc_neon_vzip (struct expand_vec_perm_d *d)
 {
-  unsigned int i, high, mask, nelt = d->nelt;
+  unsigned int i, high, mask, nelt = d->perm.length ();
   rtx out0, out1, in0, in1;
-  rtx (*gen)(rtx, rtx, rtx, rtx);
   int first_elem;
   bool is_swapped;
 
@@ -28859,22 +29251,6 @@ arm_evpc_neon_vzip (struct expand_vec_perm_d *d)
   if (d->testing_p)
     return true;
 
-  switch (d->vmode)
-    {
-    case E_V16QImode: gen = gen_neon_vzipv16qi_internal; break;
-    case E_V8QImode:  gen = gen_neon_vzipv8qi_internal;  break;
-    case E_V8HImode:  gen = gen_neon_vzipv8hi_internal;  break;
-    case E_V4HImode:  gen = gen_neon_vzipv4hi_internal;  break;
-    case E_V8HFmode:  gen = gen_neon_vzipv8hf_internal;  break;
-    case E_V4HFmode:  gen = gen_neon_vzipv4hf_internal;  break;
-    case E_V4SImode:  gen = gen_neon_vzipv4si_internal;  break;
-    case E_V2SImode:  gen = gen_neon_vzipv2si_internal;  break;
-    case E_V2SFmode:  gen = gen_neon_vzipv2sf_internal;  break;
-    case E_V4SFmode:  gen = gen_neon_vzipv4sf_internal;  break;
-    default:
-      gcc_unreachable ();
-    }
-
   in0 = d->op0;
   in1 = d->op1;
   if (is_swapped)
@@ -28885,17 +29261,16 @@ arm_evpc_neon_vzip (struct expand_vec_perm_d *d)
   if (high)
     std::swap (out0, out1);
 
-  emit_insn (gen (out0, in0, in1, out1));
+  emit_insn (gen_neon_vzip_internal (d->vmode, out0, in0, in1, out1));
   return true;
 }
 
 /* Recognize patterns for the VREV insns.  */
-
 static bool
 arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
 {
-  unsigned int i, j, diff, nelt = d->nelt;
-  rtx (*gen)(rtx, rtx);
+  unsigned int i, j, diff, nelt = d->perm.length ();
+  rtx (*gen) (machine_mode, rtx, rtx);
 
   if (!d->one_vector_p)
     return false;
@@ -28904,23 +29279,29 @@ arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
   switch (diff)
     {
     case 7:
-      switch (d->vmode)
-       {
-       case E_V16QImode: gen = gen_neon_vrev64v16qi; break;
-       case E_V8QImode:  gen = gen_neon_vrev64v8qi;  break;
-       default:
-         return false;
-       }
-      break;
+       switch (d->vmode)
+        {
+         case E_V16QImode:
+         case E_V8QImode:
+          gen = gen_neon_vrev64;
+          break;
+         default:
+          return false;
+        }
+       break;
     case 3:
-      switch (d->vmode)
-       {
-       case E_V16QImode: gen = gen_neon_vrev32v16qi; break;
-       case E_V8QImode:  gen = gen_neon_vrev32v8qi;  break;
-       case E_V8HImode:  gen = gen_neon_vrev64v8hi;  break;
-       case E_V4HImode:  gen = gen_neon_vrev64v4hi;  break;
-       case E_V8HFmode:  gen = gen_neon_vrev64v8hf;  break;
-       case E_V4HFmode:  gen = gen_neon_vrev64v4hf;  break;
+       switch (d->vmode)
+        {
+       case E_V16QImode:
+       case E_V8QImode:
+          gen = gen_neon_vrev32;
+          break;
+       case E_V8HImode:
+       case E_V4HImode:
+       case E_V8HFmode:
+       case E_V4HFmode:
+          gen = gen_neon_vrev64;
+          break;
        default:
          return false;
        }
@@ -28928,15 +29309,21 @@ arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
     case 1:
       switch (d->vmode)
        {
-       case E_V16QImode: gen = gen_neon_vrev16v16qi; break;
-       case E_V8QImode:  gen = gen_neon_vrev16v8qi;  break;
-       case E_V8HImode:  gen = gen_neon_vrev32v8hi;  break;
-       case E_V4HImode:  gen = gen_neon_vrev32v4hi;  break;
-       case E_V4SImode:  gen = gen_neon_vrev64v4si;  break;
-       case E_V2SImode:  gen = gen_neon_vrev64v2si;  break;
-       case E_V4SFmode:  gen = gen_neon_vrev64v4sf;  break;
-       case E_V2SFmode:  gen = gen_neon_vrev64v2sf;  break;
-       default:
+       case E_V16QImode:
+       case E_V8QImode:
+          gen = gen_neon_vrev16;
+          break;
+       case E_V8HImode:
+       case E_V4HImode:
+          gen = gen_neon_vrev32;
+          break;
+       case E_V4SImode:
+       case E_V2SImode:
+       case E_V4SFmode:
+       case E_V2SFmode:
+          gen = gen_neon_vrev64;
+         break;
+        default:
          return false;
        }
       break;
@@ -28961,7 +29348,7 @@ arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
   if (d->testing_p)
     return true;
 
-  emit_insn (gen (d->target, d->op0));
+  emit_insn (gen (d->vmode, d->target, d->op0));
   return true;
 }
 
@@ -28970,9 +29357,8 @@ arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
 static bool
 arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
 {
-  unsigned int i, odd, mask, nelt = d->nelt;
+  unsigned int i, odd, mask, nelt = d->perm.length ();
   rtx out0, out1, in0, in1;
-  rtx (*gen)(rtx, rtx, rtx, rtx);
 
   if (GET_MODE_UNIT_SIZE (d->vmode) >= 8)
     return false;
@@ -28998,22 +29384,6 @@ arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
   if (d->testing_p)
     return true;
 
-  switch (d->vmode)
-    {
-    case E_V16QImode: gen = gen_neon_vtrnv16qi_internal; break;
-    case E_V8QImode:  gen = gen_neon_vtrnv8qi_internal;  break;
-    case E_V8HImode:  gen = gen_neon_vtrnv8hi_internal;  break;
-    case E_V4HImode:  gen = gen_neon_vtrnv4hi_internal;  break;
-    case E_V8HFmode:  gen = gen_neon_vtrnv8hf_internal;  break;
-    case E_V4HFmode:  gen = gen_neon_vtrnv4hf_internal;  break;
-    case E_V4SImode:  gen = gen_neon_vtrnv4si_internal;  break;
-    case E_V2SImode:  gen = gen_neon_vtrnv2si_internal;  break;
-    case E_V2SFmode:  gen = gen_neon_vtrnv2sf_internal;  break;
-    case E_V4SFmode:  gen = gen_neon_vtrnv4sf_internal;  break;
-    default:
-      gcc_unreachable ();
-    }
-
   in0 = d->op0;
   in1 = d->op1;
   if (BYTES_BIG_ENDIAN)
@@ -29027,7 +29397,7 @@ arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
   if (odd)
     std::swap (out0, out1);
 
-  emit_insn (gen (out0, in0, in1, out1));
+  emit_insn (gen_neon_vtrn_internal (d->vmode, out0, in0, in1, out1));
   return true;
 }
 
@@ -29036,8 +29406,7 @@ arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
 static bool
 arm_evpc_neon_vext (struct expand_vec_perm_d *d)
 {
-  unsigned int i, nelt = d->nelt;
-  rtx (*gen) (rtx, rtx, rtx, rtx);
+  unsigned int i, nelt = d->perm.length ();
   rtx offset;
 
   unsigned int location;
@@ -29073,29 +29442,16 @@ arm_evpc_neon_vext (struct expand_vec_perm_d *d)
 
   location = d->perm[0];
 
-  switch (d->vmode)
-    {
-    case E_V16QImode: gen = gen_neon_vextv16qi; break;
-    case E_V8QImode: gen = gen_neon_vextv8qi; break;
-    case E_V4HImode: gen = gen_neon_vextv4hi; break;
-    case E_V8HImode: gen = gen_neon_vextv8hi; break;
-    case E_V2SImode: gen = gen_neon_vextv2si; break;
-    case E_V4SImode: gen = gen_neon_vextv4si; break;
-    case E_V4HFmode: gen = gen_neon_vextv4hf; break;
-    case E_V8HFmode: gen = gen_neon_vextv8hf; break;
-    case E_V2SFmode: gen = gen_neon_vextv2sf; break;
-    case E_V4SFmode: gen = gen_neon_vextv4sf; break;
-    case E_V2DImode: gen = gen_neon_vextv2di; break;
-    default:
-      return false;
-    }
-
   /* Success! */
   if (d->testing_p)
     return true;
 
   offset = GEN_INT (location);
-  emit_insn (gen (d->target, d->op0, d->op1, offset));
+
+  if(d->vmode == E_DImode)
+    return false;
+
+  emit_insn (gen_neon_vext (d->vmode, d->target, d->op0, d->op1, offset));
   return true;
 }
 
@@ -29110,7 +29466,7 @@ arm_evpc_neon_vtbl (struct expand_vec_perm_d *d)
 {
   rtx rperm[MAX_VECT_LEN], sel;
   machine_mode vmode = d->vmode;
-  unsigned int i, nelt = d->nelt;
+  unsigned int i, nelt = d->perm.length ();
 
   /* TODO: ARM's VTBL indexing is little-endian.  In order to handle GCC's
      numbering of elements for big-endian, we must reverse the order.  */
@@ -29147,13 +29503,10 @@ arm_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
   /* The pattern matching functions above are written to look for a small
      number to begin the sequence (0, 1, N/2).  If we begin with an index
      from the second operand, we can swap the operands.  */
-  if (d->perm[0] >= d->nelt)
+  unsigned int nelt = d->perm.length ();
+  if (d->perm[0] >= nelt)
     {
-      unsigned i, nelt = d->nelt;
-
-      for (i = 0; i < nelt; ++i)
-       d->perm[i] = (d->perm[i] + nelt) & (2 * nelt - 1);
-
+      d->perm.rotate_inputs (1);
       std::swap (d->op0, d->op1);
     }
 
@@ -29172,29 +29525,31 @@ arm_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
   return false;
 }
 
-/* Expand a vec_perm_const pattern.  */
+/* Implement TARGET_VECTORIZE_VEC_PERM_CONST.  */
 
-bool
-arm_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
+static bool
+arm_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, rtx op1,
+                             const vec_perm_indices &sel)
 {
   struct expand_vec_perm_d d;
   int i, nelt, which;
 
+  if (!VALID_NEON_DREG_MODE (vmode) && !VALID_NEON_QREG_MODE (vmode))
+    return false;
+
   d.target = target;
   d.op0 = op0;
   d.op1 = op1;
 
-  d.vmode = GET_MODE (target);
+  d.vmode = vmode;
   gcc_assert (VECTOR_MODE_P (d.vmode));
-  d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
-  d.testing_p = false;
+  d.testing_p = !target;
 
+  nelt = GET_MODE_NUNITS (d.vmode);
   for (i = which = 0; i < nelt; ++i)
     {
-      rtx e = XVECEXP (sel, 0, i);
-      int ei = INTVAL (e) & (2 * nelt - 1);
+      int ei = sel[i] & (2 * nelt - 1);
       which |= (ei < nelt ? 1 : 2);
-      d.perm[i] = ei;
     }
 
   switch (which)
@@ -29204,7 +29559,7 @@ arm_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
 
     case 3:
       d.one_vector_p = false;
-      if (!rtx_equal_p (op0, op1))
+      if (d.testing_p || !rtx_equal_p (op0, op1))
        break;
 
       /* The elements of PERM do not suggest that only the first operand
@@ -29213,8 +29568,6 @@ arm_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
         input vector.  */
       /* FALLTHRU */
     case 2:
-      for (i = 0; i < nelt; ++i)
-        d.perm[i] &= nelt - 1;
       d.op0 = op1;
       d.one_vector_p = true;
       break;
@@ -29225,39 +29578,10 @@ arm_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
       break;
     }
 
-  return arm_expand_vec_perm_const_1 (&d);
-}
-
-/* Implement TARGET_VECTORIZE_VEC_PERM_CONST_OK.  */
-
-static bool
-arm_vectorize_vec_perm_const_ok (machine_mode vmode,
-                                const unsigned char *sel)
-{
-  struct expand_vec_perm_d d;
-  unsigned int i, nelt, which;
-  bool ret;
-
-  d.vmode = vmode;
-  d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
-  d.testing_p = true;
-  memcpy (d.perm, sel, nelt);
-
-  /* Categorize the set of elements in the selector.  */
-  for (i = which = 0; i < nelt; ++i)
-    {
-      unsigned char e = d.perm[i];
-      gcc_assert (e < 2 * nelt);
-      which |= (e < nelt ? 1 : 2);
-    }
-
-  /* For all elements from second vector, fold the elements to first.  */
-  if (which == 2)
-    for (i = 0; i < nelt; ++i)
-      d.perm[i] -= nelt;
+  d.perm.new_vector (sel.encoding (), d.one_vector_p ? 1 : 2, nelt);
 
-  /* Check whether the mask can be applied to the vector type.  */
-  d.one_vector_p = (which != 3);
+  if (!d.testing_p)
+    return arm_expand_vec_perm_const_1 (&d);
 
   d.target = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 1);
   d.op1 = d.op0 = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 2);
@@ -29265,7 +29589,7 @@ arm_vectorize_vec_perm_const_ok (machine_mode vmode,
     d.op1 = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 3);
 
   start_sequence ();
-  ret = arm_expand_vec_perm_const_1 (&d);
+  bool ret = arm_expand_vec_perm_const_1 (&d);
   end_sequence ();
 
   return ret;
@@ -29590,6 +29914,9 @@ arm_valid_symbolic_address_p (rtx addr)
   rtx xop0, xop1 = NULL_RTX;
   rtx tmp = addr;
 
+  if (target_word_relocations)
+    return false;
+
   if (GET_CODE (tmp) == SYMBOL_REF || GET_CODE (tmp) == LABEL_REF)
     return true;
 
@@ -29759,10 +30086,9 @@ arm_block_set_unaligned_vect (rtx dstbase,
                              unsigned HOST_WIDE_INT value,
                              unsigned HOST_WIDE_INT align)
 {
-  unsigned int i, j, nelt_v16, nelt_v8, nelt_mode;
+  unsigned int i, nelt_v16, nelt_v8, nelt_mode;
   rtx dst, mem;
-  rtx val_elt, val_vec, reg;
-  rtx rval[MAX_VECT_LEN];
+  rtx val_vec, reg;
   rtx (*gen_func) (rtx, rtx);
   machine_mode mode;
   unsigned HOST_WIDE_INT v = value;
@@ -29790,12 +30116,9 @@ arm_block_set_unaligned_vect (rtx dstbase,
   mem = adjust_automodify_address (dstbase, mode, dst, offset);
 
   v = sext_hwi (v, BITS_PER_WORD);
-  val_elt = GEN_INT (v);
-  for (j = 0; j < nelt_mode; j++)
-    rval[j] = val_elt;
 
   reg = gen_reg_rtx (mode);
-  val_vec = gen_rtx_CONST_VECTOR (mode, gen_rtvec_v (nelt_mode, rval));
+  val_vec = gen_const_vec_duplicate (mode, GEN_INT (v));
   /* Emit instruction loading the constant value.  */
   emit_move_insn (reg, val_vec);
 
@@ -29859,12 +30182,10 @@ arm_block_set_aligned_vect (rtx dstbase,
                            unsigned HOST_WIDE_INT value,
                            unsigned HOST_WIDE_INT align)
 {
-  unsigned int i, j, nelt_v8, nelt_v16, nelt_mode;
+  unsigned int i, nelt_v8, nelt_v16, nelt_mode;
   rtx dst, addr, mem;
-  rtx val_elt, val_vec, reg;
-  rtx rval[MAX_VECT_LEN];
+  rtx val_vec, reg;
   machine_mode mode;
-  unsigned HOST_WIDE_INT v = value;
   unsigned int offset = 0;
 
   gcc_assert ((align & 0x3) == 0);
@@ -29883,13 +30204,8 @@ arm_block_set_aligned_vect (rtx dstbase,
 
   dst = copy_addr_to_reg (XEXP (dstbase, 0));
 
-  v = sext_hwi (v, BITS_PER_WORD);
-  val_elt = GEN_INT (v);
-  for (j = 0; j < nelt_mode; j++)
-    rval[j] = val_elt;
-
   reg = gen_reg_rtx (mode);
-  val_vec = gen_rtx_CONST_VECTOR (mode, gen_rtvec_v (nelt_mode, rval));
+  val_vec = gen_const_vec_duplicate (mode, gen_int_mode (value, QImode));
   /* Emit instruction loading the constant value.  */
   emit_move_insn (reg, val_vec);
 
@@ -30330,6 +30646,8 @@ arm_const_not_ok_for_debug_p (rtx p)
   tree decl_op0 = NULL;
   tree decl_op1 = NULL;
 
+  if (GET_CODE (p) == UNSPEC)
+    return true;
   if (GET_CODE (p) == MINUS)
     {
       if (GET_CODE (XEXP (p, 1)) == SYMBOL_REF)
@@ -30569,7 +30887,7 @@ arm_valid_target_attribute_rec (tree args, struct gcc_options *opts)
          if (! opt_enum_arg_to_value (OPT_mfpu_, q+4,
                                       &fpu_index, CL_TARGET))
            {
-             error ("invalid fpu for attribute(target(\"%s\"))", q);
+             error ("invalid fpu for target attribute or pragma %qs", q);
              return false;
            }
          if (fpu_index == TARGET_FPU_auto)
@@ -30582,9 +30900,29 @@ arm_valid_target_attribute_rec (tree args, struct gcc_options *opts)
            }
          opts->x_arm_fpu_index = (enum fpu_type) fpu_index;
        }
+      else if (!strncmp (q, "arch=", 5))
+       {
+         char* arch = q+5;
+         const arch_option *arm_selected_arch
+            = arm_parse_arch_option_name (all_architectures, "arch", arch);
+
+         if (!arm_selected_arch)
+           {
+             error ("invalid architecture for target attribute or pragma %qs",
+                    q);
+             return false;
+           }
+
+         opts->x_arm_arch_string = xstrndup (arch, strlen (arch));
+       }
+      else if (q[0] == '+')
+       {
+         opts->x_arm_arch_string
+           = xasprintf ("%s%s", opts->x_arm_arch_string, q);
+       }
       else
        {
-         error ("attribute(target(\"%s\")) is unknown", q);
+         error ("unknown target attribute or pragma %qs", q);
          return false;
        }
     }
@@ -30606,7 +30944,10 @@ arm_valid_target_attribute_tree (tree args, struct gcc_options *opts,
   cl_target_option_save (&cl_opts, opts);
   arm_configure_build_target (&arm_active_target, &cl_opts, opts_set, false);
   arm_option_check_internal (opts);
-  /* Do any overrides, such as global options arch=xxx.  */
+  /* Do any overrides, such as global options arch=xxx.
+     We do this since arm_active_target was overridden.  */
+  arm_option_reconfigure_globals ();
+  arm_options_perform_arch_sanity_checks ();
   arm_option_override_internal (opts, opts_set);
 
   return build_target_option_node (opts);
@@ -30637,7 +30978,7 @@ arm_insert_attributes (tree fndecl, tree * attributes)
     return;
 
   if (TREE_CODE (fndecl) != FUNCTION_DECL || DECL_EXTERNAL(fndecl)
-      || DECL_BUILT_IN (fndecl) || DECL_ARTIFICIAL (fndecl))
+      || fndecl_built_in_p (fndecl) || DECL_ARTIFICIAL (fndecl))
    return;
 
   /* Nested definitions must inherit mode.  */
@@ -30733,9 +31074,58 @@ arm_identify_fpu_from_isa (sbitmap isa)
   gcc_unreachable ();
 }
 
+/* Implement ASM_DECLARE_FUNCTION_NAME.  Output the ISA features used
+   by the function fndecl.  */
 void
 arm_declare_function_name (FILE *stream, const char *name, tree decl)
 {
+  tree target_parts = DECL_FUNCTION_SPECIFIC_TARGET (decl);
+
+  struct cl_target_option *targ_options;
+  if (target_parts)
+    targ_options = TREE_TARGET_OPTION (target_parts);
+  else
+    targ_options = TREE_TARGET_OPTION (target_option_current_node);
+  gcc_assert (targ_options);
+
+  /* Only update the assembler .arch string if it is distinct from the last
+     such string we printed. arch_to_print is set conditionally in case
+     targ_options->x_arm_arch_string is NULL which can be the case
+     when cc1 is invoked directly without passing -march option.  */
+  std::string arch_to_print;
+  if (targ_options->x_arm_arch_string)
+    arch_to_print = targ_options->x_arm_arch_string;
+
+  if (arch_to_print != arm_last_printed_arch_string)
+    {
+      std::string arch_name
+       = arch_to_print.substr (0, arch_to_print.find ("+"));
+      asm_fprintf (asm_out_file, "\t.arch %s\n", arch_name.c_str ());
+      const arch_option *arch
+       = arm_parse_arch_option_name (all_architectures, "-march",
+                                     targ_options->x_arm_arch_string);
+      auto_sbitmap opt_bits (isa_num_bits);
+
+      gcc_assert (arch);
+      if (arch->common.extensions)
+       {
+         for (const struct cpu_arch_extension *opt = arch->common.extensions;
+              opt->name != NULL;
+              opt++)
+           {
+             if (!opt->remove)
+               {
+                 arm_initialize_isa (opt_bits, opt->isa_bits);
+                 if (bitmap_subset_p (opt_bits, arm_active_target.isa)
+                     && !bitmap_subset_p (opt_bits, isa_all_fpubits))
+                   asm_fprintf (asm_out_file, "\t.arch_extension %s\n",
+                                opt->name);
+               }
+            }
+       }
+
+      arm_last_printed_arch_string = arch_to_print;
+    }
 
   fprintf (stream, "\t.syntax unified\n");
 
@@ -30753,10 +31143,15 @@ arm_declare_function_name (FILE *stream, const char *name, tree decl)
   else
     fprintf (stream, "\t.arm\n");
 
-  asm_fprintf (asm_out_file, "\t.fpu %s\n",
-              (TARGET_SOFT_FLOAT
-               ? "softvfp"
-               : arm_identify_fpu_from_isa (arm_active_target.isa)));
+  std::string fpu_to_print
+    = TARGET_SOFT_FLOAT
+       ? "softvfp" : arm_identify_fpu_from_isa (arm_active_target.isa);
+
+  if (fpu_to_print != arm_last_printed_arch_string)
+    {
+      asm_fprintf (asm_out_file, "\t.fpu %s\n", fpu_to_print.c_str ());
+      arm_last_printed_fpu_string = fpu_to_print;
+    }
 
   if (TARGET_POKE_FUNCTION_NAME)
     arm_poke_function_name (stream, (const char *) name);
@@ -31162,7 +31557,7 @@ arm_coproc_builtin_available (enum unspecv builtin)
       case VUNSPEC_MRC2:
        /* Only present in ARMv5*, ARMv6 (but not ARMv6-M), ARMv7* and
           ARMv8-{A,M}.  */
-       if (arm_arch5)
+       if (arm_arch5t)
          return true;
        break;
       case VUNSPEC_MCRR:
@@ -31234,6 +31629,55 @@ arm_coproc_ldc_stc_legitimate_address (rtx op)
   return false;
 }
 
+/* Implement TARGET_CAN_CHANGE_MODE_CLASS.
+
+   In VFPv1, VFP registers could only be accessed in the mode they were
+   set, so subregs would be invalid there.  However, we don't support
+   VFPv1 at the moment, and the restriction was lifted in VFPv2.
+
+   In big-endian mode, modes greater than word size (i.e. DFmode) are stored in
+   VFP registers in little-endian order.  We can't describe that accurately to
+   GCC, so avoid taking subregs of such values.
+
+   The only exception is going from a 128-bit to a 64-bit type.  In that
+   case the data layout happens to be consistent for big-endian, so we
+   explicitly allow that case.  */
+
+static bool
+arm_can_change_mode_class (machine_mode from, machine_mode to,
+                          reg_class_t rclass)
+{
+  if (TARGET_BIG_END
+      && !(GET_MODE_SIZE (from) == 16 && GET_MODE_SIZE (to) == 8)
+      && (GET_MODE_SIZE (from) > UNITS_PER_WORD
+         || GET_MODE_SIZE (to) > UNITS_PER_WORD)
+      && reg_classes_intersect_p (VFP_REGS, rclass))
+    return false;
+  return true;
+}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.  Make strings word-aligned so
+   strcpy from constants will be faster.  */
+
+static HOST_WIDE_INT
+arm_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+  unsigned int factor = (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2);
+  if (TREE_CODE (exp) == STRING_CST && !optimize_size)
+    return MAX (align, BITS_PER_WORD * factor);
+  return align;
+}
+
+/* Emit a speculation barrier on target architectures that do not have
+   DSB/ISB directly.  Such systems probably don't need a barrier
+   themselves, but if the code is ever run on a later architecture, it
+   might become a problem.  */
+void
+arm_emit_speculation_barrier_function ()
+{
+  emit_library_call (speculation_barrier_libfunc, LCT_NORMAL, VOIDmode);
+}
+
 #if CHECKING_P
 namespace selftest {
 
@@ -31319,10 +31763,43 @@ arm_test_cpu_arch_data (void)
     }
 }
 
+/* Scan the static data tables generated by parsecpu.awk looking for
+   potential issues with the data.  Here we check for consistency between the
+   fpu bits, in particular we check that ISA_ALL_FPU_INTERNAL does not contain
+   a feature bit that is not defined by any FPU flag.  */
+static void
+arm_test_fpu_data (void)
+{
+  auto_sbitmap isa_all_fpubits (isa_num_bits);
+  auto_sbitmap fpubits (isa_num_bits);
+  auto_sbitmap tmpset (isa_num_bits);
+
+  static const enum isa_feature fpu_bitlist[]
+    = { ISA_ALL_FPU_INTERNAL, isa_nobit };
+  arm_initialize_isa (isa_all_fpubits, fpu_bitlist);
+
+  for (unsigned int i = 0; i < TARGET_FPU_auto; i++)
+  {
+    arm_initialize_isa (fpubits, all_fpus[i].isa_bits);
+    bitmap_and_compl (tmpset, isa_all_fpubits, fpubits);
+    bitmap_clear (isa_all_fpubits);
+    bitmap_copy (isa_all_fpubits, tmpset);
+  }
+
+  if (!bitmap_empty_p (isa_all_fpubits))
+    {
+       fprintf (stderr, "Error: found feature bits in the ALL_FPU_INTERAL"
+                        " group that are not defined by any FPU.\n"
+                        "       Check your arm-cpus.in.\n");
+       ASSERT_TRUE (bitmap_empty_p (isa_all_fpubits));
+    }
+}
+
 static void
 arm_run_selftests (void)
 {
   arm_test_cpu_arch_data ();
+  arm_test_fpu_data ();
 }
 } /* Namespace selftest.  */