diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h
index 9f37b9b432e5ed978032fa3356b138e2c7433760..ba5d052e9b694289574a68f156ca68b66ad6e2ee 100644
--- a/gcc/config/aarch64/aarch64-opts.h
+++ b/gcc/config/aarch64/aarch64-opts.h
@@ -71,4 +71,14 @@ enum aarch64_code_model {
   AARCH64_CMODEL_LARGE
 };
 
+/* Function types -msign-return-address should sign.  */
+enum aarch64_function_type {
+  /* Don't sign any function.  */
+  AARCH64_FUNCTION_NONE,
+  /* Non-leaf functions.  */
+  AARCH64_FUNCTION_NON_LEAF,
+  /* All functions.  */
+  AARCH64_FUNCTION_ALL
+};
+
 #endif
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 29a3bd71151aa4fb7c6728f0fb52e2f3f233f41d..632dd4768d82c340ae4e9b4a93206743756c06e7 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -386,6 +386,7 @@ void aarch64_emit_call_insn (rtx);
 void aarch64_register_pragmas (void);
 void aarch64_relayout_simd_types (void);
 void aarch64_reset_previous_fndecl (void);
+bool aarch64_return_address_signing_enabled (void);
 void aarch64_save_restore_target_globals (tree);
 
 /* Initialize builtins for SIMD intrinsics.  */
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 9dd75b07498871db3e37b335dc8a3e1d66ec1d8b..002895a167ce0deb45a5c1726527651af18bb4df 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -3117,6 +3117,22 @@ aarch64_gen_load_pair (machine_mode mode, rtx reg1, rtx mem1, rtx reg2,
     }
 }
 
+/* Return TRUE if return address signing should be enabled for one function,
+   otherwise return FALSE.  */
+
+bool
+aarch64_return_address_signing_enabled (void)
+{
+  /* This function should only be called after frame laid out.   */
+  gcc_assert (cfun->machine->frame.laid_out);
+
+  /* If signing scope is AARCH64_FUNCTION_NON_LEAF, we only sign a leaf function
+     if it's LR is pushed onto stack.  */
+  return (aarch64_ra_sign_scope == AARCH64_FUNCTION_ALL
+	  || (aarch64_ra_sign_scope == AARCH64_FUNCTION_NON_LEAF
+	      && cfun->machine->frame.reg_offset[LR_REGNUM] >= 0));
+}
+
 /* Emit code to save the callee-saved registers from register number START
    to LIMIT to the stack at the location starting at offset START_OFFSET,
    skipping any write-back candidates if SKIP_WB is true.  */
@@ -3535,6 +3551,10 @@ aarch64_expand_prologue (void)
   unsigned reg2 = cfun->machine->frame.wb_candidate2;
   rtx_insn *insn;
 
+  /* Sign return address for functions.  */
+  if (aarch64_return_address_signing_enabled ())
+    emit_insn (gen_pacisp ());
+
   if (flag_stack_usage_info)
     current_function_static_stack_size = frame_size;
 
@@ -3670,6 +3690,16 @@ aarch64_expand_epilogue (bool for_sibcall)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
+  /* sibcall won't generate normally return, therefore we need to authenticate
+     at here.  !TARGET_ARMV8_3 disallows GCC to use combined authentication
+     instruction which we prefer, so we need to generate a seperate
+     authentication. eh_return path can't do combined authentication, as it will
+     do extra stack adjustment which updates CFA to EH handler's CFA while we
+     want to use the CFA of the function which calls eh_return.  */
+  if (aarch64_return_address_signing_enabled ()
+      && (for_sibcall || !TARGET_ARMV8_3 || crtl->calls_eh_return))
+    emit_insn (gen_autisp ());
+
   /* Stack adjustment for exception handler.  */
   if (crtl->calls_eh_return)
     {
@@ -8894,6 +8924,9 @@ aarch64_override_options (void)
     error ("Assembler does not support -mabi=ilp32");
 #endif
 
+  if (aarch64_ra_sign_scope != AARCH64_FUNCTION_NONE && TARGET_ILP32)
+    error ("Return address signing is only supported on LP64");
+
   /* Make sure we properly set up the explicit options.  */
   if ((aarch64_cpu_string && valid_cpu)
        || (aarch64_tune_string && valid_tune))
@@ -9277,6 +9310,8 @@ static const struct aarch64_attribute_info aarch64_attributes[] =
   { "cpu", aarch64_attr_custom, false, aarch64_handle_attr_cpu, OPT_mcpu_ },
   { "tune", aarch64_attr_custom, false, aarch64_handle_attr_tune,
      OPT_mtune_ },
+  { "sign-return-address", aarch64_attr_enum, false, NULL,
+     OPT_msign_return_address_ },
   { NULL, aarch64_attr_custom, false, NULL, OPT____ }
 };
 
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index bde42317f1bfd91a9d38a4cfa94d4cedd5246003..9b6f99dee3cecc0f15f24ec2375d3641fe03892d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -67,6 +67,8 @@
 )
 
 (define_c_enum "unspec" [
+    UNSPEC_AUTI1716
+    UNSPEC_AUTISP
     UNSPEC_CASESI
     UNSPEC_CRC32B
     UNSPEC_CRC32CB
@@ -106,6 +108,8 @@
     UNSPEC_LD4_LANE
     UNSPEC_MB
     UNSPEC_NOP
+    UNSPEC_PACI1716
+    UNSPEC_PACISP
     UNSPEC_PRLG_STK
     UNSPEC_RBIT
     UNSPEC_SCVTF
@@ -135,6 +139,7 @@
     UNSPEC_RSQRTE
     UNSPEC_RSQRTS
     UNSPEC_NZCV
+    UNSPEC_XPACLRI
 ])
 
 (define_c_enum "unspecv" [
@@ -575,7 +580,14 @@
 (define_insn "*do_return"
   [(return)]
   ""
-  "ret"
+  {
+    if (aarch64_return_address_signing_enabled ()
+	&& TARGET_ARMV8_3
+	&& !crtl->calls_eh_return)
+      return "retaa";
+
+    return "ret";
+  }
   [(set_attr "type" "branch")]
 )
 
@@ -5341,6 +5353,31 @@
   [(set_attr "length" "0")]
 )
 
+;; Pointer authentication patterns are available for all architectures.  On
+;; pre-ARMv8.3-A architectures they are NOP.  This let the user write portable
+;; software which can get pointer authentication on new hardware while still
+;; runs correctly on old hardware though no pointer authentication protection.
+
+(define_insn "<pauth_mnem_prefix>sp"
+  [(set (reg:DI R30_REGNUM)
+	(unspec:DI [(reg:DI R30_REGNUM) (reg:DI SP_REGNUM)] PAUTH_LR_SP))]
+  ""
+  "hint\t<pauth_hint_num_a> // <pauth_mnem_prefix>asp";
+)
+
+(define_insn "<pauth_mnem_prefix>1716"
+  [(set (reg:DI R17_REGNUM)
+	(unspec:DI [(reg:DI R17_REGNUM) (reg:DI R16_REGNUM)] PAUTH_17_16))]
+  ""
+  "hint\t<pauth_hint_num_a> // <pauth_mnem_prefix>a1716";
+)
+
+(define_insn "xpaclri"
+  [(set (reg:DI R30_REGNUM) (unspec:DI [(reg:DI R30_REGNUM)] UNSPEC_XPACLRI))]
+  ""
+  "hint\t7 // xpaclri"
+)
+
 ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
 ;; all of memory.  This blocks insns from being moved across this point.
 
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 56b920dfe5abda1349c441c2188e5ac3ca05ab5a..54368848bbb249949921a3018d927c4bd61b1fbd 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -149,6 +149,23 @@ mpc-relative-literal-loads
 Target Report Save Var(pcrelative_literal_loads) Init(2) Save
 PC relative literal loads.
 
+msign-return-address=
+Target RejectNegative Report Joined Enum(aarch64_ra_sign_scope_t) Var(aarch64_ra_sign_scope) Init(AARCH64_FUNCTION_NONE) Save
+Select return address signing scope.
+
+Enum
+Name(aarch64_ra_sign_scope_t) Type(enum aarch64_function_type)
+Supported AArch64 return address signing scope (for use with -msign-return-address= option):
+
+EnumValue
+Enum(aarch64_ra_sign_scope_t) String(none) Value(AARCH64_FUNCTION_NONE)
+
+EnumValue
+Enum(aarch64_ra_sign_scope_t) String(non-leaf) Value(AARCH64_FUNCTION_NON_LEAF)
+
+EnumValue
+Enum(aarch64_ra_sign_scope_t) String(all) Value(AARCH64_FUNCTION_ALL)
+
 mlow-precision-recip-sqrt
 Common Var(flag_mrecip_low_precision_sqrt) Optimization
 Enable the reciprocal square root approximation.  Enabling this reduces
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index e2377c1cb2161c52ccadec3804294c494819cbb8..c59d31e5053a28fa31259341e82b6696f6ac8781 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -1032,6 +1032,10 @@
 (define_int_iterator FMAXMIN_UNS [UNSPEC_FMAX UNSPEC_FMIN
 				  UNSPEC_FMAXNM UNSPEC_FMINNM])
 
+(define_int_iterator PAUTH_LR_SP [UNSPEC_PACISP UNSPEC_AUTISP])
+
+(define_int_iterator PAUTH_17_16 [UNSPEC_PACI1716 UNSPEC_AUTI1716])
+
 (define_int_iterator VQDMULH [UNSPEC_SQDMULH UNSPEC_SQRDMULH])
 
 (define_int_iterator USSUQADD [UNSPEC_SUQADD UNSPEC_USQADD])
@@ -1218,6 +1222,18 @@
 				  (UNSPEC_FCVTZS "fcvtzs")
 				  (UNSPEC_FCVTZU "fcvtzu")])
 
+;; Pointer authentication mnemonic prefix.
+(define_int_attr pauth_mnem_prefix [(UNSPEC_PACISP "paci")
+				    (UNSPEC_AUTISP "auti")
+				    (UNSPEC_PACI1716 "paci")
+				    (UNSPEC_AUTI1716 "auti")])
+
+;; Pointer authentication HINT number for NOP space instructions using A Key.
+(define_int_attr pauth_hint_num_a [(UNSPEC_PACISP "25")
+				    (UNSPEC_AUTISP "29")
+				    (UNSPEC_PACI1716 "8")
+				    (UNSPEC_AUTI1716 "12")])
+
 (define_int_attr perm_insn [(UNSPEC_ZIP1 "zip") (UNSPEC_ZIP2 "zip")
 			    (UNSPEC_TRN1 "trn") (UNSPEC_TRN2 "trn")
 			    (UNSPEC_UZP1 "uzp") (UNSPEC_UZP2 "uzp")])
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 30bdcf07ad8b1bd086bbb87acb36fb0333944087..47250ebb149bbde021ef64eba8e96e35c2623284 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3513,6 +3513,12 @@ Specifies the core for which to tune the performance of this function and also
 whose architectural features to use.  The behavior and valid arguments are the
 same as for the @option{-mcpu=} command-line option.
 
+@item sign-return-address
+@cindex @code{sign-return-address} function attribute, AArch64
+Select the function scope we want to do return address signing on.  The behavior
+and permissible arguments are the same as for the command-line option
+@option{-msign-return-address=}.  The default value is @code{none}
+
 @end table
 
 The above target attributes can be specified as follows:
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index aa0ac8b41128483be53645b91bdcead096582e23..2792dbd0a2d0ed9e3f46237685f8ae65a5d8bcf5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -14044,6 +14044,13 @@ accessed using a single instruction and emitted after each function.  This
 limits the maximum size of functions to 1MB.  This is enabled by default for
 @option{-mcmodel=tiny}.
 
+@item -msign-return-address=@var{scope}
+@opindex msign-return-address
+Select the function scope we want to do return address signing on.  Permissible
+values are @samp{none}, @samp{none-leaf} and @samp{all}.  @samp{none} means
+return address signing is disabled.  @samp{non-leaf} enables it for non-leaf
+functions.  @samp{all} for all functions and is the default value.
+
 @end table
 
 @subsubsection @option{-march} and @option{-mcpu} Feature Modifiers
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a0332abd41ca6ae994e6ed72771fca8ee532cd0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msign-return-address=all" } */
+
+int foo (int);
+int bar (int, int);
+
+/* sibcall only.  */
+int __attribute__ ((target ("arch=armv8.3-a")))
+func1 (int a, int b)
+{
+  /* paciasp */
+  return foo (a + b);
+  /* autiasp */
+}
+
+/* non-leaf function with sibcall.  */
+int __attribute__ ((target ("arch=armv8.3-a")))
+func2 (int a, int b)
+{
+  /* paciasp */
+  if (a < b)
+    return b;
+
+  a = foo (b);
+
+  return foo (a);
+  /* autiasp */
+}
+
+/* non-leaf function, legacy arch.  */
+int __attribute__ ((target ("arch=armv8.2-a")))
+func3 (int a, int b, int c)
+{
+  /* paciasp */
+  return a + foo (b) + c;
+  /* autiasp */
+}
+
+/* non-leaf function.  */
+int __attribute__ ((target ("arch=armv8.3-a")))
+func4 (int a, int b, int c)
+{
+  /* paciasp */
+  return a + foo (b) + c;
+  /* retab */
+}
+
+int __attribute__ ((target ("arch=armv8.3-a, sign-return-address=none")))
+func4_disable (int a, int b, int c, int d)
+{
+  return c + bar (a, b) + d;
+}
+
+/* { dg-final { scan-assembler-times "autiasp" 3 } } */
+/* { dg-final { scan-assembler-times "paciasp" 4 } } */
+/* { dg-final { scan-assembler-times "retaa" 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_scope_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_scope_1.c
new file mode 100644
index 0000000000000000000000000000000000000000..6876e26a6a38eb670f8676f8f06dd74dfc18f41d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_scope_1.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msign-return-address=non-leaf" } */
+
+int foo (int);
+int bar (int, int);
+
+/* sibcall only.  */
+int __attribute__ ((target ("arch=armv8.3-a, sign-return-address=non-leaf")))
+func1 (int a, int b)
+{
+  /* No authentication.  */
+  return foo (a + b);
+}
+
+/* non-leaf function with sibcall.  */
+int __attribute__ ((target ("arch=armv8.3-a")))
+func2 (int a, int b)
+{
+  /* paciasp */
+  if (a < b)
+    return b;
+
+  a = foo (b);
+
+  return foo (a);
+  /* autiasp */
+}
+
+/* non-leaf function, legacy arch.  */
+int __attribute__ ((target ("arch=armv8.2-a")))
+func3 (int a, int b, int c)
+{
+  /* pacibsp */
+  return a + foo (b) + c;
+  /* autibsp */
+}
+
+/* non-leaf function.  */
+int __attribute__ ((target ("arch=armv8.3-a")))
+func4 (int a, int b, int c)
+{
+  /* pacibsp */
+  return a + foo (b) + c;
+  /* retab */
+}
+
+int __attribute__ ((target ("arch=armv8.3-a, sign-return-address=none")))
+func4_disable (int a, int b, int c, int d)
+{
+  return c + bar (a, b) + d;
+}
+
+/* { dg-final { scan-assembler-times "paciasp" 3 } } */
+/* { dg-final { scan-assembler-times "autiasp" 2 } } */
+/* { dg-final { scan-assembler-times "retaa" 1 } } */
