diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 69ef148bf9c..ef25d673798 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -57,6 +57,18 @@ reencode_add_imm (uint32_t insn, uint32_t imm)
   return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10);
 }
 
+/* Base encoding for MOV Wd, Wm (ORR Wd, WZR, Wm).  */
+#define AARCH64_MOV_REG_OPCODE 0x2a0003e0U
+/* NOP encoding  */
+#define AARCH64_NOP_OPCODE 0xd503201fU
+
+/* Reencode ADD immediate as MOV-register (ORR Rd, ZR, Rm).  */
+static inline uint32_t
+reencode_add_to_mov (uint32_t insn, unsigned int rd, unsigned int rn)
+{
+  return ((insn & (1U << 31)) | AARCH64_MOV_REG_OPCODE | (rn << 16) | rd);
+}
+
 /* Reencode the IMM field of ADR.  */
 
 uint32_t
@@ -261,11 +273,23 @@ _bfd_aarch64_elf_put_addend (bfd *abfd,
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
-      /* Corresponds to: add rd, rn, #uimm12 to provide the low order
-	 12 bits of the page offset following
-	 BFD_RELOC_AARCH64_ADR_HI21_PCREL which computes the
-	 (pc-relative) page base.  */
-      contents = reencode_add_imm (contents, addend);
+      /* Optimize an ADD whose relocated 12-bit immediate is zero.  */
+      if ((addend & MASK (12)) == 0)
+	{
+	  unsigned int rd = contents & MASK (5);
+	  unsigned int rn = (contents >> 5) & MASK (5);
+	  /* ADD Xd, Xd, #0 --> NOP, check for the 32 bit version
+	     since it clear the upper half of the destination register.  */
+	  if (rd == rn && rd != 31 && (contents & (1U << 31)) != 0)
+	    contents = AARCH64_NOP_OPCODE;
+	  /* Register 31 denotes SP in ADD but ZR in MOV (ORR).  */
+	  else if (rd != 31 && rn != 31)
+	    contents = reencode_add_to_mov (contents, rd, rn);
+	  else
+	    contents = reencode_add_imm (contents, addend);
+	}
+      else
+	contents = reencode_add_imm (contents, addend);
       break;
 
     case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index fa80210500e..5e8f7e0d22f 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -284,6 +284,11 @@ run_dump_test_lp64 "tls-large-desc-be"
 run_dump_test "tls-tiny-ld"
 run_dump_test "tls-small-ld"
 run_dump_test_lp64 "tlsle"
+run_dump_test_lp64 "tlsle-add-hi12-opt"
+run_dump_test_lp64 "add-imm-zero-opt"
+run_dump_test_lp64 "add-imm-zero-opt-tlsgd"
+run_dump_test_lp64 "add-imm-zero-opt-tlsld"
+run_dump_test_lp64 "add-imm-zero-opt-tlsdesc"
 run_dump_test "tlsle-symbol-offset"
 run_dump_test "gc-got-relocs"
 run_dump_test "gc-tls-relocs"
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d
new file mode 100644
index 00000000000..092f891395f
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d
@@ -0,0 +1,16 @@
+#source: add-imm-zero-opt-tlsdesc.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x1ffd8 -e0 --no-warn-rwx-segments
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	d503201f 	nop
+ +10008:	910003e3 	mov	x3, sp
+ +1000c:	9100009f 	mov	sp, x4
+ +10010:	d65f03c0 	ret
+#...
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s
new file mode 100644
index 00000000000..6fa1f19314c
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s
@@ -0,0 +1,16 @@
+	.section .tbss,"awT",%nobits
+	.global tls_desc
+tls_desc:
+	.zero 8
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x1, #:tlsdesc_lo12:tls_desc
+	add	x2, x2, #:tlsdesc_lo12:tls_desc
+	add	x3, sp, #:tlsdesc_lo12:tls_desc
+	add	sp, x4, #:tlsdesc_lo12:tls_desc
+	ret
+	.size test, .-test
+
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d
new file mode 100644
index 00000000000..cba5d38f3af
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d
@@ -0,0 +1,15 @@
+#source: add-imm-zero-opt-tlsgd.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x1fff8 -e0 --no-warn-rwx-segments
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	d503201f 	nop
+ +10008:	910003e3 	mov	x3, sp
+ +1000c:	9100009f 	mov	sp, x4
+ +10010:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s
new file mode 100644
index 00000000000..349f92cfbd8
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s
@@ -0,0 +1,16 @@
+	.section .tbss,"awT",%nobits
+	.global tls_gd
+tls_gd:
+	.zero 8
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x1, #:tlsgd_lo12:tls_gd
+	add	x2, x2, #:tlsgd_lo12:tls_gd
+	add	x3, sp, #:tlsgd_lo12:tls_gd
+	add	sp, x4, #:tlsgd_lo12:tls_gd
+	ret
+	.size test, .-test
+
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d
new file mode 100644
index 00000000000..ad08392b798
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d
@@ -0,0 +1,15 @@
+#source: add-imm-zero-opt-tlsld.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x1fff8 -e0 --no-warn-rwx-segments
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	d503201f 	nop
+ +10008:	910003e3 	mov	x3, sp
+ +1000c:	9100009f 	mov	sp, x4
+ +10010:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s
new file mode 100644
index 00000000000..a08675f6ffc
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s
@@ -0,0 +1,15 @@
+	.section .tbss,"awT",%nobits
+tls_ld:
+	.zero 8
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x1, #:tlsldm_lo12_nc:tls_ld
+	add	x2, x2, #:tlsldm_lo12_nc:tls_ld
+	add	x3, sp, #:tlsldm_lo12_nc:tls_ld
+	add	sp, x4, #:tlsldm_lo12_nc:tls_ld
+	ret
+	.size test, .-test
+
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt.d
new file mode 100644
index 00000000000..4395bd01ab2
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt.d
@@ -0,0 +1,22 @@
+#source: add-imm-zero-opt.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x20000 -e0
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	d503201f 	nop
+ +10004:	aa0203e1 	mov	x1, x2
+ +10008:	d503201f 	nop
+ +1000c:	aa0503e4 	mov	x4, x5
+ +10010:	aa0703e6 	mov	x6, x7
+ +10014:	d503201f 	nop
+ +10018:	aa0a03e9 	mov	x9, x10
+ +1001c:	2a0b03eb 	mov	w11, w11
+ +10020:	910003ec 	mov	x12, sp
+ +10024:	910001bf 	mov	sp, x13
+ +10028:	910021ce 	add	x14, x14, #0x8
+ +1002c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt.ld b/ld/testsuite/ld-aarch64/add-imm-zero-opt.ld
new file mode 100644
index 00000000000..666ec64e47a
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt.ld
@@ -0,0 +1,16 @@
+OUTPUT_ARCH(aarch64)
+SECTIONS
+{
+  . = 0x10000;
+  .text : { *(.text) }
+  . = got_base;
+  .got : { *(.got) *(.got.plt) }
+  . = 0x30000;
+  .tdata : { *(.tdata) }
+  .tbss : { *(.tbss) }
+  .data :
+  {
+    *(.data)
+    *(.data.*)
+  }
+}
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt.s
new file mode 100644
index 00000000000..8f71acb3a7d
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt.s
@@ -0,0 +1,34 @@
+	.section .tbss,"awT",%nobits
+tls0:
+	.zero 4096
+tls_page:
+	.zero 8
+
+	.section .data.page,"aw"
+	.p2align 12
+page_sym:
+	.xword 0
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x0, #:lo12:page_sym
+	add	x1, x2, #:dtprel_hi12:tls0, lsl #12
+	add	x3, x3, #:dtprel_lo12:tls0
+	add	x4, x5, #:dtprel_lo12_nc:tls_page
+	add	x6, x7, #:tprel_hi12:tls0, lsl #12
+	add	x8, x8, #:tprel_lo12:tls0-16
+	add	x9, x10, #:tprel_lo12_nc:tls_page-16
+
+	/* A 32-bit write must not be replaced with NOP.  */
+	add	w11, w11, #:lo12:page_sym
+
+	/* Uses of SP must remain ADD instructions.  */
+	add	x12, sp, #:lo12:page_sym
+	add	sp, x13, #:lo12:page_sym
+
+	/* A nonzero immediate must remain an ADD instruction.  */
+	add	x14, x14, #:lo12:page_sym+8
+	ret
+	.size test, .-test
diff --git a/ld/testsuite/ld-aarch64/erratum843419.d b/ld/testsuite/ld-aarch64/erratum843419.d
index 7adfafde95a..2127194ac39 100644
--- a/ld/testsuite/ld-aarch64/erratum843419.d
+++ b/ld/testsuite/ld-aarch64/erratum843419.d
@@ -33,7 +33,7 @@ Disassembly of section .e843419:
 
 0*20001030 <__e835769_veneer>:
 [ ]*20001030:	f0f17ff0 	adrp	x16, 3000000 <e835769>
-[ ]*20001034:	91000210 	add	x16, x16, #0x0
+[ ]*20001034:	d503201f 	nop
 [ ]*20001038:	d61f0200 	br	x16
 	...
 
@@ -68,6 +68,6 @@ Disassembly of section .text:
 
 0*400020 <__e843419_veneer>:
 [ ]*400020:	900fe010 	adrp	x16, 20000000 <e843419>
-[ ]*400024:	91000210 	add	x16, x16, #0x0
+[ ]*400024:	d503201f 	nop
 [ ]*400028:	d61f0200 	br	x16
 	...
diff --git a/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d b/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d
index 4d2b1116442..bd18d629ef6 100644
--- a/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d
+++ b/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d
@@ -44,6 +44,6 @@ Disassembly of section .text:
 
 0*400020 <__farbranch_veneer>:
 [ ]*400020:	900fe010 	adrp	x16, 20000000 <farbranch>
-[ ]*400024:	91000210 	add	x16, x16, #0x0
+[ ]*400024:	d503201f 	nop
 [ ]*400028:	d61f0200 	br	x16
 	...
diff --git a/ld/testsuite/ld-aarch64/farcall-b-defsym.d b/ld/testsuite/ld-aarch64/farcall-b-defsym.d
index f6b092116cd..da049f9badc 100644
--- a/ld/testsuite/ld-aarch64/farcall-b-defsym.d
+++ b/ld/testsuite/ld-aarch64/farcall-b-defsym.d
@@ -14,6 +14,6 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
diff --git a/ld/testsuite/ld-aarch64/farcall-b-none-function.d b/ld/testsuite/ld-aarch64/farcall-b-none-function.d
index e06936c347a..54738452e61 100644
--- a/ld/testsuite/ld-aarch64/farcall-b-none-function.d
+++ b/ld/testsuite/ld-aarch64/farcall-b-none-function.d
@@ -15,7 +15,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-b-section.d b/ld/testsuite/ld-aarch64/farcall-b-section.d
index 3872cd0b7c6..2c9df42d0a7 100644
--- a/ld/testsuite/ld-aarch64/farcall-b-section.d
+++ b/ld/testsuite/ld-aarch64/farcall-b-section.d
@@ -17,7 +17,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1018:	90040010 	adrp	x16, 8001000 <bar>
-    101c:	91000210 	add	x16, x16, #0x0
+    101c:	d503201f 	nop
     1020:	d61f0200 	br	x16
     1024:	00000000 	udf	#0
 
diff --git a/ld/testsuite/ld-aarch64/farcall-b.d b/ld/testsuite/ld-aarch64/farcall-b.d
index cfa0688646e..05bc7c29ece 100644
--- a/ld/testsuite/ld-aarch64/farcall-b.d
+++ b/ld/testsuite/ld-aarch64/farcall-b.d
@@ -14,7 +14,7 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-back-be.d b/ld/testsuite/ld-aarch64/farcall-back-be.d
index 80992aab67c..42bd5913e09 100644
--- a/ld/testsuite/ld-aarch64/farcall-back-be.d
+++ b/ld/testsuite/ld-aarch64/farcall-back-be.d
@@ -38,7 +38,7 @@ Disassembly of section .text:
 
 000000000000204c <__bar1_veneer>:
     204c:	d07ffff0 	adrp	x16, 100000000 <bar1>
-    2050:	91000210 	add	x16, x16, #0x0
+    2050:	d503201f 	nop
     2054:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-back.d b/ld/testsuite/ld-aarch64/farcall-back.d
index 20204eef5e2..2eea4bb19d1 100644
--- a/ld/testsuite/ld-aarch64/farcall-back.d
+++ b/ld/testsuite/ld-aarch64/farcall-back.d
@@ -39,7 +39,7 @@ Disassembly of section .text:
 
 0000000000002050 <__bar1_veneer>:
     2050:	d07ffff0 	adrp	x16, 100000000 <bar1>
-    2054:	91000210 	add	x16, x16, #0x0
+    2054:	d503201f 	nop
     2058:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-defsym.d b/ld/testsuite/ld-aarch64/farcall-bl-defsym.d
index 4a3ab80d85a..1d682169a45 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl-defsym.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl-defsym.d
@@ -14,6 +14,6 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
 [ \t]+1010:[ \t]+90040010[ \t]+adrp[ \t]+x16, 8001000 <bar>
-[ \t]+1014:[ \t]+91000210[ \t]+add[ \t]+x16, x16, #0x0
+[ \t]+1014:[ \t]+d503201f[ \t]+nop
 [ \t]+1018:[ \t]+d61f0200[ \t]+br[ \t]+x16
 	...
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-none-function.d b/ld/testsuite/ld-aarch64/farcall-bl-none-function.d
index 4ab9c7eed40..6c9385ea689 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl-none-function.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl-none-function.d
@@ -15,7 +15,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-section.d b/ld/testsuite/ld-aarch64/farcall-bl-section.d
index 03ebe2991d6..c2cf3da903d 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl-section.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl-section.d
@@ -17,7 +17,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1018:	90040010 	adrp	x16, 8001000 <bar>
-    101c:	91000210 	add	x16, x16, #0x0
+    101c:	d503201f 	nop
     1020:	d61f0200 	br	x16
     1024:	00000000 	udf	#0
 
diff --git a/ld/testsuite/ld-aarch64/farcall-bl.d b/ld/testsuite/ld-aarch64/farcall-bl.d
index 637225be4dd..971d61dfef1 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl.d
@@ -14,7 +14,7 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
 [ \t]+1010:[ \t]+90040010[ \t]+adrp[ \t]+x16, 8001000 <bar>
-[ \t]+1014:[ \t]+91000210[ \t]+add[ \t]+x16, x16, #0x0
+[ \t]+1014:[ \t]+d503201f[ \t]+nop
 [ \t]+1018:[ \t]+d61f0200[ \t]+br[ \t]+x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d
index 74131fb5b58..43fb330c637 100644
--- a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d
+++ b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d
@@ -58,7 +58,7 @@ Disassembly of section \.ramu:
 
 0000000020000010 \<__code4_veneer\>:
     20000010:	90080210 	adrp	x16, 30040000 \<code4\>
-    20000014:	91000210 	add	x16, x16, #0x0
+    20000014:	d503201f 	nop
     20000018:	d61f0200 	br	x16
 	\.\.\.
 
diff --git a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d
index 18a46b79acc..d6f2dc391d7 100644
--- a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d
+++ b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d
@@ -53,7 +53,7 @@ Disassembly of section \.raml:
 
 000000001fff0028 \<__code4_veneer\>:
     1fff0028:	90100290 	adrp	x16, 40040000 \<code4\>
-    1fff002c:	91000210 	add	x16, x16, #0x0
+    1fff002c:	d503201f 	nop
     1fff0030:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d
index 5dd222ea342..dea3fad1f17 100644
--- a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d
+++ b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d
@@ -57,7 +57,7 @@ Disassembly of section \.raml:
 
 000000001fff0028 \<__code4_veneer\>:
     1fff0028:	90100290 	adrp	x16, 40040000 \<code4\>
-    1fff002c:	91000210 	add	x16, x16, #0x0
+    1fff002c:	d503201f 	nop
     1fff0030:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d
index 2b80db5a542..ac80543d897 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d
@@ -9,7 +9,7 @@
  +10008:	11002000 	add	w0, w0, #0x8
  +1000c:	d503201f 	nop
  +10010:	d503201f 	nop
- +10014:	91400001 	add	x1, x0, #0x0, lsl #12
- +10018:	91000021 	add	x1, x1, #0x0
+ +10014:	aa0003e1 	mov	x1, x0
+ +10018:	d503201f 	nop
  +1001c:	90000000 	adrp	x0, 10000 <.*>
  +10020:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d
index fa648291fdb..b8094889fda 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d
@@ -7,7 +7,7 @@
  +10008:	91004000 	add	x0, x0, #0x10
  +1000c:	d503201f 	nop
  +10010:	d503201f 	nop
- +10014:	91400001 	add	x1, x0, #0x0, lsl #12
- +10018:	91000021 	add	x1, x1, #0x0
+ +10014:	aa0003e1 	mov	x1, x0
+ +10018:	d503201f 	nop
  +1001c:	90000000 	adrp	x0, 10000 <.*>
  +10020:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d
index 445e79dccf6..7ed81e247f0 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d
@@ -8,7 +8,7 @@
  +10004:	d53bd040 	mrs	x0, tpidr_el0
  +10008:	11002000 	add	w0, w0, #0x8
  +1000c:	d503201f 	nop
- +10010:	91400001 	add	x1, x0, #0x0, lsl #12
- +10014:	91000021 	add	x1, x1, #0x0
+ +10010:	aa0003e1 	mov	x1, x0
+ +10014:	d503201f 	nop
  +10018:	90000000 	adrp	x0, 10000 <main>
  +1001c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d
index db226775346..c6d1a9884a0 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d
@@ -6,7 +6,7 @@
  +10004:	d53bd040 	mrs	x0, tpidr_el0
  +10008:	91004000 	add	x0, x0, #0x10
  +1000c:	d503201f 	nop
- +10010:	91400001 	add	x1, x0, #0x0, lsl #12
- +10014:	91000021 	add	x1, x1, #0x0
+ +10010:	aa0003e1 	mov	x1, x0
+ +10014:	d503201f 	nop
  +10018:	90000000 	adrp	x0, 10000 <main>
  +1001c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d b/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d
index cc13bbde21b..8d7cc6866e6 100644
--- a/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d
+++ b/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d
@@ -9,5 +9,5 @@ Disassembly of section .text:
 
 00010000 \<test\>:
  +10000:	d53bd041 	mrs	x1, tpidr_el0
- +10004:	11400020 	add	w0, w1, #0x0, lsl #12
+ +10004:	2a0103e0 	mov	w0, w1
  +10008:	11002000 	add	w0, w0, #0x8
diff --git a/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d b/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d
index 016ca70658f..6a1777e5c06 100644
--- a/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d
+++ b/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d
@@ -7,5 +7,5 @@ Disassembly of section .text:
 
 0000000000010000 \<test\>:
  +10000:	d53bd041 	mrs	x1, tpidr_el0
- +10004:	91400020 	add	x0, x1, #0x0, lsl #12
+ +10004:	aa0103e0 	mov	x0, x1
  +10008:	91004000 	add	x0, x0, #0x10
diff --git a/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d
new file mode 100644
index 00000000000..0f2c90a4cc4
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d
@@ -0,0 +1,14 @@
+#source: tlsle-add-hi12-opt.s
+#target: [check_shared_lib_support]
+#ld: -shared -T relocs.ld -e0
+#objdump: -dr
+
+.*: .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	914003e2 	add	x2, sp, #0x0, lsl #12
+ +10008:	9140007f 	add	sp, x3, #0x0, lsl #12
+ +1000c:	914004a4 	add	x4, x5, #0x1, lsl #12
diff --git a/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s
new file mode 100644
index 00000000000..f7a8d876122
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s
@@ -0,0 +1,13 @@
+	.global	test
+	.section	.tbss,"awT",%nobits
+tlsvar:
+	.zero	4080
+tlsvar_hi12:
+	.zero	8
+
+	.text
+test:
+	add	x0, x1, #:tprel_hi12:tlsvar
+	add	x2, sp, #:tprel_hi12:tlsvar
+	add	sp, x3, #:tprel_hi12:tlsvar
+	add	x4, x5, #:tprel_hi12:tlsvar_hi12
diff --git a/ld/testsuite/ld-aarch64/weak-undefined.d b/ld/testsuite/ld-aarch64/weak-undefined.d
index 29ba2e5c672..3627d46c82b 100644
--- a/ld/testsuite/ld-aarch64/weak-undefined.d
+++ b/ld/testsuite/ld-aarch64/weak-undefined.d
@@ -15,4 +15,4 @@
  +f0000028:	58000000 	ldr	x0, f0000028 <main\+0x28>
  +f000002c:	10000000 	adr	x0, f000002c <main\+0x2c>
  +f0000030:	90000000 	adrp	x0, f0000000 <main>
- +f0000034:	91000000 	add	x0, x0, #0x0
+ +f0000034:	d503201f 	nop
