diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h
index 9d5bf77c868dc6bebb37e04764ad42a58832996b..7e8f1babed8e6ab9b0b838cee25f169bc3851b7e 100644
--- a/gcc/config/aarch64/aarch64-opts.h
+++ b/gcc/config/aarch64/aarch64-opts.h
@@ -81,7 +81,8 @@ enum aarch64_tp_reg {
   AARCH64_TPIDR_EL0 = 0,
   AARCH64_TPIDR_EL1 = 1,
   AARCH64_TPIDR_EL2 = 2,
-  AARCH64_TPIDR_EL3 = 3
+  AARCH64_TPIDR_EL3 = 3,
+  AARCH64_TPIDRRO_EL0 = 4
 };
 
 /* SVE vector register sizes.  */
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 20517c75d8082c2f4a3d9a63e269b2890fe23b6b..df37bde6a78c1651111cc82404eaf26bd703d948 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -27693,7 +27693,8 @@ aarch64_indirect_call_asm (rtx addr)
 const char *
 aarch64_output_load_tp (rtx dest)
 {
-  const char *tpidrs[] = {"tpidr_el0", "tpidr_el1", "tpidr_el2", "tpidr_el3"};
+  const char *tpidrs[] = {"tpidr_el0", "tpidr_el1", "tpidr_el2",
+			  "tpidr_el3", "tpidrro_el0"};
   char buffer[64];
   snprintf (buffer, sizeof (buffer), "mrs\t%%0, %s",
 	    tpidrs[aarch64_tpidr_register]);
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 025e52d40e5c52e122890f657e3cc930f164e9ea..4a0580435a8d3c92eca8936515026882c7ea7f48 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -104,15 +104,30 @@ The register used to access the thread pointer:
 EnumValue
 Enum(tp_reg) String(el0) Value(AARCH64_TPIDR_EL0)
 
+EnumValue
+Enum(tp_reg) String(tpidr_el0) Value(AARCH64_TPIDR_EL0)
+
 EnumValue
 Enum(tp_reg) String(el1) Value(AARCH64_TPIDR_EL1)
 
+EnumValue
+Enum(tp_reg) String(tpidr_el1) Value(AARCH64_TPIDR_EL1)
+
 EnumValue
 Enum(tp_reg) String(el2) Value(AARCH64_TPIDR_EL2)
 
+EnumValue
+Enum(tp_reg) String(tpidr_el2) Value(AARCH64_TPIDR_EL2)
+
 EnumValue
 Enum(tp_reg) String(el3) Value(AARCH64_TPIDR_EL3)
 
+EnumValue
+Enum(tp_reg) String(tpidr_el3) Value(AARCH64_TPIDR_EL3)
+
+EnumValue
+Enum(tp_reg) String(tpidrro_el0) Value(AARCH64_TPIDRRO_EL0)
+
 mtp=
 Target RejectNegative Joined Enum(tp_reg) Var(aarch64_tpidr_reg) Init(AARCH64_TPIDR_EL0) Save
 Specify the thread pointer register.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 0870f7aff93616b0f92ab4097133e9419f3fd5f9..54c377fd8154c85a02e7f604b4db53a1cc20a60f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -20235,12 +20235,12 @@ addresses and sizes of sections.  Programs can be statically linked only.  The
 @item -mtp=@var{name}
 @opindex mtp
 Specify the system register to use as a thread pointer.  The valid values
-are @samp{el0}, @samp{el1}, @samp{el2}, @samp{el3}.  These correspond to
-using the @samp{tpidr_el0}, @samp{tpidr_el1}, @samp{tpidr_el2},
-@samp{tpidr_el3} registers accordingly.  The default setting is @samp{el0}.
-It is recommended to compile all code intended to interoperate with the same
-value of this option to avoid accessing a different thread pointer from the
-wrong exception level.
+are @samp{tpidr_el0}, @samp{tpidrro_el0}, @samp{tpidr_el1}, @samp{tpidr_el2},
+@samp{tpidr_el3}.  For backwards compatibility the aliases @samp{el0},
+@samp{el1}, @samp{el2}, @samp{el3} are also accepted.
+The default setting is @samp{tpidr_el0}.  It is recommended to compile all
+code intended to interoperate with the same value of this option to avoid
+accessing a different thread pointer from the wrong exception level.
 
 @opindex mstrict-align
 @opindex mno-strict-align
diff --git a/gcc/testsuite/gcc.target/aarch64/mtp_5.c b/gcc/testsuite/gcc.target/aarch64/mtp_5.c
new file mode 100644
index 0000000000000000000000000000000000000000..72bd86169a5c446febdb00baf8a2725d3ef1708c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mtp_5.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O -mtp=tpidrro_el0" } */
+
+#include "mtp.c"
+
+/* { dg-final { scan-assembler-times {mrs\tx[0-9]+, tpidrro_el0} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/mtp_6.c b/gcc/testsuite/gcc.target/aarch64/mtp_6.c
new file mode 100644
index 0000000000000000000000000000000000000000..0cdee12f67dc64e11fc6cdb0d82a5da87bc271c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mtp_6.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O -mtp=tpidr_el0" } */
+
+#include "mtp.c"
+
+/* { dg-final { scan-assembler-times {mrs\tx[0-9]+, tpidr_el0} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/mtp_7.c b/gcc/testsuite/gcc.target/aarch64/mtp_7.c
new file mode 100644
index 0000000000000000000000000000000000000000..2e4a1a4ee9b3122041ff610aee29c3083d5c0c20
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mtp_7.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O -mtp=tpidr_el1" } */
+
+#include "mtp.c"
+
+/* { dg-final { scan-assembler-times {mrs\tx[0-9]+, tpidr_el1} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/mtp_8.c b/gcc/testsuite/gcc.target/aarch64/mtp_8.c
new file mode 100644
index 0000000000000000000000000000000000000000..810fe38de9d473ed9633ab7162ba004009e0db2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mtp_8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O -mtp=tpidr_el2" } */
+
+#include "mtp.c"
+
+/* { dg-final { scan-assembler-times {mrs\tx[0-9]+, tpidr_el2} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/mtp_9.c b/gcc/testsuite/gcc.target/aarch64/mtp_9.c
new file mode 100644
index 0000000000000000000000000000000000000000..934cc18cbe8a0503ebe178e3d3bef3c1bcaff1c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/mtp_9.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O -mtp=tpidr_el3" } */
+
+#include "mtp.c"
+
+/* { dg-final { scan-assembler-times {mrs\tx[0-9]+, tpidr_el3} 1 } } */