diff --git a/gcc/config.gcc b/gcc/config.gcc
index d9bfbfdc0d2..648cf28e105 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -322,7 +322,7 @@ aarch64*-*-*)
 	c_target_objs="aarch64-c.o"
 	cxx_target_objs="aarch64-c.o"
 	d_target_objs="aarch64-d.o"
-	extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o aarch64-cc-fusion.o"
+	extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch-bti-insert.o aarch64-cc-fusion.o"
 	target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc"
 	target_has_targetm_common=yes
 	;;
@@ -346,7 +346,7 @@ arc*-*-*)
 	;;
 arm*-*-*)
 	cpu_type=arm
-	extra_objs="arm-builtins.o aarch-common.o"
+	extra_objs="arm-builtins.o aarch-common.o aarch-bti-insert.o"
 	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h arm_cmse.h arm_bf16.h arm_mve_types.h arm_mve.h arm_cde.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index f9ddffa0078..5b8c03e094b 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -179,7 +179,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
   aarch64_def_or_undef (TARGET_RNG, "__ARM_FEATURE_RNG", pfile);
   aarch64_def_or_undef (TARGET_MEMTAG, "__ARM_FEATURE_MEMORY_TAGGING", pfile);
 
-  aarch64_def_or_undef (aarch64_bti_enabled (),
+  aarch64_def_or_undef (aarch_bti_enabled (),
 			"__ARM_FEATURE_BTI_DEFAULT", pfile);
 
   cpp_undef (pfile, "__ARM_FEATURE_PAC_DEFAULT");
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index b91eeeba101..fa87a4c7bb3 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -893,7 +893,6 @@ void aarch64_register_pragmas (void);
 void aarch64_relayout_simd_types (void);
 void aarch64_reset_previous_fndecl (void);
 bool aarch64_return_address_signing_enabled (void);
-bool aarch64_bti_enabled (void);
 void aarch64_save_restore_target_globals (tree);
 void aarch64_addti_scratch_regs (rtx, rtx, rtx *,
 				 rtx *, rtx *,
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 3213585a588..70edd179a61 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -7800,11 +7800,61 @@ aarch64_return_address_signing_enabled (void)
 
 /* Return TRUE if Branch Target Identification Mechanism is enabled.  */
 bool
-aarch64_bti_enabled (void)
+aarch_bti_enabled (void)
 {
   return (aarch64_enable_bti == 1);
 }
 
+/* Check if INSN is a BTI J insn.  */
+bool
+aarch_bti_j_insn_p (rtx_insn *insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  rtx pat = PATTERN (insn);
+  return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI_J;
+}
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction.  */
+bool
+aarch_pac_insn_p (rtx x)
+{
+  if (!INSN_P (x))
+    return false;
+
+  subrtx_var_iterator::array_type array;
+  FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (x), ALL)
+    {
+      rtx sub = *iter;
+      if (sub && GET_CODE (sub) == UNSPEC)
+	{
+	  int unspec_val = XINT (sub, 1);
+	  switch (unspec_val)
+	    {
+	    case UNSPEC_PACIASP:
+            case UNSPEC_PACIBSP:
+	      return true;
+
+	    default:
+	      return false;
+	    }
+	  iter.skip_subrtxes ();
+	}
+    }
+  return false;
+}
+
+rtx aarch_gen_bti_c (void)
+{
+  return gen_bti_c ();
+}
+
+rtx aarch_gen_bti_j (void)
+{
+  return gen_bti_j ();
+}
+
 /* The caller is going to use ST1D or LD1D to save or restore an SVE
    register in mode MODE at BASE_RTX + OFFSET, where OFFSET is in
    the range [1, 16] * GET_MODE_SIZE (MODE).  Prepare for this by:
@@ -9167,7 +9217,7 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
   rtx_insn *insn;
   const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk));
 
-  if (aarch64_bti_enabled ())
+  if (aarch_bti_enabled ())
     emit_insn (gen_bti_c());
 
   reload_completed = 1;
@@ -21407,7 +21457,7 @@ aarch64_print_patchable_function_entry (FILE *file,
 					bool record_p)
 {
   if (cfun->machine->label_is_assembled
-      && aarch64_bti_enabled ()
+      && aarch_bti_enabled ()
       && !cgraph_node::get (cfun->decl)->only_called_directly_p ())
     {
       /* Remove the BTI that follows the patch area and insert a new BTI
@@ -25531,7 +25581,7 @@ aarch64_file_end_indicate_exec_stack ()
   file_end_indicate_exec_stack ();
 
   unsigned feature_1_and = 0;
-  if (aarch64_bti_enabled ())
+  if (aarch_bti_enabled ())
     feature_1_and |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
 
   if (aarch64_ra_sign_scope != AARCH64_FUNCTION_NONE)
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index 7e1606c47ac..f6ace450e17 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -149,14 +149,14 @@ falkor-tag-collision-avoidance.o: \
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 		$(srcdir)/config/aarch64/falkor-tag-collision-avoidance.c
 
-aarch64-bti-insert.o: $(srcdir)/config/aarch64/aarch64-bti-insert.c \
+aarch-bti-insert.o: $(srcdir)/config/arm/aarch-bti-insert.c \
     $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(REGS_H) insn-config.h $(RTL_BASE_H) \
     dominance.h cfg.h cfganal.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(RECOG_H) \
     output.h hash-map.h $(DF_H) $(OBSTACK_H) $(TARGET_H) $(RTL_H) \
     $(CONTEXT_H) $(TREE_PASS_H) regrename.h \
     $(srcdir)/config/aarch64/aarch64-protos.h
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-		$(srcdir)/config/aarch64/aarch64-bti-insert.c
+		$(srcdir)/config/arm/aarch-bti-insert.c
 
 aarch64-cc-fusion.o: $(srcdir)/config/aarch64/aarch64-cc-fusion.cc \
     $(CONFIG_H) $(SYSTEM_H) $(CORETYPES_H) $(BACKEND_H) $(RTL_H) $(DF_H) \
diff --git a/gcc/config/aarch64/aarch64-bti-insert.c b/gcc/config/arm/aarch-bti-insert.c
similarity index 80%
rename from gcc/config/aarch64/aarch64-bti-insert.c
rename to gcc/config/arm/aarch-bti-insert.c
index 5d6bc169d6b..6b03238470b 100644
--- a/gcc/config/aarch64/aarch64-bti-insert.c
+++ b/gcc/config/arm/aarch-bti-insert.c
@@ -1,4 +1,4 @@
-/* Branch Target Identification for AArch64 architecture.
+/* Branch Target Identification for Arm/AArch64 architecture.
    Copyright (C) 2019-2021 Free Software Foundation, Inc.
    Contributed by Arm Ltd.
 
@@ -42,10 +42,11 @@
 #include "tree-pass.h"
 #include "cgraph.h"
 
-/* This pass enables the support for Branch Target Identification Mechanism
-   for AArch64.  This is a new security feature introduced in ARMv8.5-A
-   archtitecture.  A BTI instruction is used to guard against the execution
-   of instructions which are not the intended target of an indirect branch.
+/* This pass enables the support for Branch Target Identification Mechanism for
+   Arm/AArch64.  This is a security feature introduced in ARMv8.5-A
+   architecture and ARMv8.1-M.  A BTI instruction is used to guard against the
+   execution of instructions which are not the intended target of an indirect
+   branch.
 
    Outside of a guarded memory region, a BTI instruction executes as a NOP.
    Within a guarded memory region any target of an indirect branch must be
@@ -90,47 +91,6 @@ const pass_data pass_data_insert_bti =
   0, /* todo_flags_finish.  */
 };
 
-/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction.  */
-static bool
-aarch64_pac_insn_p (rtx x)
-{
-  if (!INSN_P (x))
-    return false;
-
-  subrtx_var_iterator::array_type array;
-  FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (x), ALL)
-    {
-      rtx sub = *iter;
-      if (sub && GET_CODE (sub) == UNSPEC)
-	{
-	  int unspec_val = XINT (sub, 1);
-	  switch (unspec_val)
-	    {
-	    case UNSPEC_PACIASP:
-            /* fall-through.  */
-            case UNSPEC_PACIBSP:
-	      return true;
-
-	    default:
-	      return false;
-	    }
-	  iter.skip_subrtxes ();
-	}
-    }
-  return false;
-}
-
-/* Check if INSN is a BTI J insn.  */
-static bool
-aarch64_bti_j_insn_p (rtx_insn *insn)
-{
-  if (!insn || !INSN_P (insn))
-    return false;
-
-  rtx pat = PATTERN (insn);
-  return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI_J;
-}
-
 /* Insert the BTI instruction.  */
 /* This is implemented as a late RTL pass that runs before branch
    shortening and does the following.  */
@@ -155,7 +115,7 @@ rest_of_insert_bti (void)
 	       && (LABEL_PRESERVE_P (insn)
 		   || bb->flags & BB_NON_LOCAL_GOTO_TARGET))
 	    {
-	      bti_insn = gen_bti_j ();
+	      bti_insn = aarch_gen_bti_j ();
 	      emit_insn_after (bti_insn, insn);
 	      continue;
 	    }
@@ -177,10 +137,10 @@ rest_of_insert_bti (void)
 		    {
 		      label = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, j), 0));
 		      rtx_insn *next = next_nonnote_nondebug_insn (label);
-		      if (aarch64_bti_j_insn_p (next))
+		      if (aarch_bti_j_insn_p (next))
 			continue;
 
-		      bti_insn = gen_bti_j ();
+		      bti_insn = aarch_gen_bti_j ();
 		      emit_insn_after (bti_insn, label);
 		    }
 		}
@@ -191,7 +151,7 @@ rest_of_insert_bti (void)
 	     will return.  */
 	  if (CALL_P (insn) && (find_reg_note (insn, REG_SETJMP, NULL)))
 	    {
-	      bti_insn = gen_bti_j ();
+	      bti_insn = aarch_gen_bti_j ();
 	      emit_insn_after (bti_insn, insn);
 	      continue;
 	    }
@@ -207,9 +167,9 @@ rest_of_insert_bti (void)
     {
       bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
       insn = BB_HEAD (bb);
-      if (!aarch64_pac_insn_p (get_first_nonnote_insn ()))
+      if (!aarch_pac_insn_p (get_first_nonnote_insn ()))
 	{
-	  bti_insn = gen_bti_c ();
+	  bti_insn = aarch_gen_bti_c ();
 	  emit_insn_before (bti_insn, insn);
 	}
     }
@@ -229,7 +189,7 @@ public:
   /* opt_pass methods: */
   virtual bool gate (function *)
     {
-      return aarch64_bti_enabled ();
+      return aarch_bti_enabled ();
     }
 
   virtual unsigned int execute (function *)
diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h
index 6be5fb1e083..1afebaabb9e 100644
--- a/gcc/config/arm/aarch-common-protos.h
+++ b/gcc/config/arm/aarch-common-protos.h
@@ -42,6 +42,11 @@ extern int arm_no_early_alu_shift_value_dep (rtx, rtx);
 extern int arm_no_early_mul_dep (rtx, rtx);
 extern int arm_no_early_store_addr_dep (rtx, rtx);
 extern bool arm_rtx_shift_left_p (rtx);
+extern bool aarch_bti_enabled (void);
+extern bool aarch_bti_j_insn_p (rtx_insn *);
+extern bool aarch_pac_insn_p (rtx);
+extern rtx aarch_gen_bti_c (void);
+extern rtx aarch_gen_bti_j (void);
 
 /* RTX cost table definitions.  These are used when tuning for speed rather
    than for size and should reflect the _additional_ cost over the cost
diff --git a/gcc/config/arm/arm-passes.def b/gcc/config/arm/arm-passes.def
new file mode 100644
index 00000000000..beecd2b5455
--- /dev/null
+++ b/gcc/config/arm/arm-passes.def
@@ -0,0 +1,21 @@
+/* Arm-specific passes declarations.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   Contributed by Arm Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_bti);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 9b1f61394ad..76064bafdca 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -24,6 +24,8 @@
 
 #include "sbitmap.h"
 
+rtl_opt_pass *make_pass_insert_bti (gcc::context *ctxt);
+
 extern enum unwind_info_type arm_except_unwind_info (struct gcc_options *);
 extern int use_return_insn (int, rtx);
 extern bool use_simple_return_p (void);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 11dafc70067..b62db21a734 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -32798,6 +32798,41 @@ arm_fusion_enabled_p (tune_params::fuse_ops op)
   return current_tune->fusible_ops & op;
 }
 
+/* Return TRUE if Branch Target Identification Mechanism is enabled.  */
+bool
+aarch_bti_enabled (void)
+{
+  return false; // FIXME
+}
+
+/* Check if INSN is a BTI J insn.  */
+bool
+aarch_bti_j_insn_p (rtx_insn *insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  rtx pat = PATTERN (insn);
+  return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI;
+}
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction.  */
+bool
+aarch_pac_insn_p (rtx x)
+{
+  return false;
+}
+
+rtx aarch_gen_bti_c (void)
+{
+  return gen_bti ();
+}
+
+rtx aarch_gen_bti_j (void)
+{
+  return gen_bti ();
+}
+
 /* Implement TARGET_SCHED_CAN_SPECULATE_INSN.  Return true if INSN can be
    scheduled for speculative execution.  Reject the long-running division
    and square-root instructions.  */
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 064604808cc..5fc8e76fb35 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -12800,6 +12800,12 @@
    (set_attr "length" "8")]
 )
 
+(define_insn "bti"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI)]
+  ""
+  "bti"
+  [(set_attr "type" "mov_reg")])
+
 ;; Vector bits common to IWMMXT, Neon and MVE
 (include "vec-common.md")
 ;; Load the Intel Wireless Multimedia Extension patterns
diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm
index 5f69ee6451e..358f7e5a707 100644
--- a/gcc/config/arm/t-arm
+++ b/gcc/config/arm/t-arm
@@ -165,3 +165,13 @@ arm-d.o: $(srcdir)/config/arm/arm-d.c
 arm-common.o: arm-cpu-cdata.h
 
 driver-arm.o: arm-native.h
+
+PASSES_EXTRA += $(srcdir)/config/arm/arm-passes.def
+
+aarch-bti-insert.o: $(srcdir)/config/arm/aarch-bti-insert.c \
+    $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(REGS_H) insn-config.h $(RTL_BASE_H) \
+    dominance.h cfg.h cfganal.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(RECOG_H) \
+    output.h hash-map.h $(DF_H) $(OBSTACK_H) $(TARGET_H) $(RTL_H) \
+    $(CONTEXT_H) $(TREE_PASS_H) regrename.h
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+		$(srcdir)/config/arm/aarch-bti-insert.c
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index ad1c6edd005..be89f0a171c 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -159,6 +159,7 @@
   UNSPEC_VCDE		; Custom Datapath Extension instruction.
   UNSPEC_VCDEA		; Custom Datapath Extension instruction.
   UNSPEC_DLS		; Used for DLS (Do Loop Start), Armv8.1-M Mainline instruction
+  UNSPECV_BTI		; Represent BTI
 ])
 
 
diff --git a/gcc/testsuite/gcc.target/arm/bti1.c b/gcc/testsuite/gcc.target/arm/bti1.c
new file mode 100644
index 00000000000..230ebb5a1da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/bti1.c
@@ -0,0 +1,12 @@
+/* Check that GCC does bti instruction.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mthumb -mbranch-protection=bti --save-temps" } */
+
+int
+main (void)
+{
+  return 0;
+}
+
+/* { dg-final { scan-assembler "bti" } } */
diff --git a/gcc/testsuite/gcc.target/arm/bti2.c b/gcc/testsuite/gcc.target/arm/bti2.c
new file mode 100644
index 00000000000..35aef6992e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/bti2.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* -Os to create jump table.  */
+/* { dg-options "-Os" } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mthumb -mbranch-protection=bti --save-temps" } */
+
+extern int f1 (void);
+extern int f2 (void);
+extern int f3 (void);
+extern int f4 (void);
+extern int f5 (void);
+extern int f6 (void);
+extern int f7 (void);
+extern int f8 (void);
+extern int f9 (void);
+extern int f10 (void);
+
+int (*ptr) (void);
+
+int
+f_jump_table (int y, int n)
+{
+  int i;
+  for (i = 0; i < n ;i ++)
+  {
+    switch (y)
+      {
+      case 0 : ptr = f1; break;
+      case 1 : ptr = f2; break;
+      case 2 : ptr = f3; break;
+      case 3 : ptr = f4; break;
+      case 4 : ptr = f5; break;
+      case 5 : ptr = f6; break;
+      case 6 : ptr = f7; break;
+      case 7 : ptr = f8; break;
+      case 8 : ptr = f9; break;
+      case 9 : ptr = f10; break;
+      default: break;
+      }
+    y += ptr ();
+  }
+  return (y == 0)? y+1:4;
+}
+
+int
+f_label_address ()
+{
+  static void * addr = &&lab1;
+  goto *addr;
+lab1:
+  addr = &&lab2;
+  return 1;
+lab2:
+  addr = &&lab1;
+  return 2;
+}
+
+/* { dg-final { scan-assembler-times "bti" 15 } } */
