[PATCH v1 1/1] AArch64: Optimize ADD relocations that resolve to zero

Sivan Shani <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
The "ELF for the Arm 64-bit Architecture" specification, section 5.7.9,
recommends that linkers optimize ADD instructions whose immediate becomes
zero after relocation.  In particular:

   ADD x0, x1, 0
   ADD x2, x2, 0

may be replaced with:

   MOV x0, x1
   NOP

Apply this optimization to all supported relocations that set an ADD
immediate field.

Rewrite additions between different registers as MOV.  Rewrite 64-bit
additions whose source and destination registers are the same as NOP.
Keep the 32-bit same-register form as MOV because writing to a W register
clears the upper 32 bits.  Do not rewrite instructions that use SP, since
ADD and the ORR encoding underlying MOV interpret register 31 differently.

For input relocations and linker-generated stubs, the optimization honors
--no-relax.  Pass an explicit boolean to _bfd_aarch64_elf_put_addend
because this low-level BFD helper has no access to bfd_link_info.  Other
relocation paths pass the same flag for a uniform interface, although they
cannot reach the ADD-immediate cases.

Continue optimizing linker-generated PLT entries unconditionally.  These
instructions have no retained input relocations and therefore do not
present a relocation reapplication problem.

Add a test verifying that --no-relax preserves zero-immediate ADD
instructions while still applying their relocation values normally.

Add coverage for every affected relocation and update existing tests.

bfd/

	* elfnn-aarch64.c (aarch64_relocate): Add optimize_add_zero
	argument.
	(aarch64_build_one_stub): Honor --no-relax when relocating
	linker-generated stubs.
	(elfNN_aarch64_final_link_relocate): Pass the ADD-zero
	optimization policy to _bfd_aarch64_elf_put_addend.
	(elf_aarch64_update_plt_entry): Enable the optimization for
	linker-generated PLT entries.
	* elfxx-aarch64.c (AARCH64_MOV_REG_OPCODE)
	(AARCH64_NOP_OPCODE): Define.
	(reencode_add_to_mov): Accept the decoded register fields.
	(_bfd_aarch64_elf_put_addend): Add an optimize_add_zero argument.
	Optimize ADD relocations whose encoded immediate is zero when
	enabled.  Validate the expected ADD-immediate encoding before
	rewriting it.
	* elfxx-aarch64.h (_bfd_aarch64_elf_put_addend): Update
	declaration.

ld/testsuite/

	* ld-aarch64/aarch64-elf.exp: Run the new ADD-immediate
	optimization tests.
	* ld-aarch64/add-imm-zero-opt.ld: New test linker script.
	* ld-aarch64/add-imm-zero-opt.s: New test.
	* ld-aarch64/add-imm-zero-opt.d: New expected output.
	* ld-aarch64/add-imm-zero-opt-norelax.d: New test.
	* ld-aarch64/add-imm-zero-opt-tlsgd.s: New test.
	* ld-aarch64/add-imm-zero-opt-tlsgd.d: New expected output.
	* ld-aarch64/add-imm-zero-opt-tlsld.s: New test.
	* ld-aarch64/add-imm-zero-opt-tlsld.d: New expected output.
	* ld-aarch64/add-imm-zero-opt-tlsdesc.s: New test.
	* ld-aarch64/add-imm-zero-opt-tlsdesc.d: New expected output.
	* ld-aarch64/erratum843419.d: Expect NOP.
	* ld-aarch64/erratum843419_tls_ie.d: Likewise.
	* ld-aarch64/farcall-b-defsym.d: Likewise.
	* ld-aarch64/farcall-b-none-function.d: Likewise.
	* ld-aarch64/farcall-b-section.d: Likewise.
	* ld-aarch64/farcall-b.d: Likewise.
	* ld-aarch64/farcall-back.d: Likewise.
	* ld-aarch64/farcall-bl-defsym.d: Likewise.
	* ld-aarch64/farcall-bl-none-function.d: Likewise.
	* ld-aarch64/farcall-bl-section.d: Likewise.
	* ld-aarch64/farcall-bl.d: Likewise.
	* ld-aarch64/tls-relax-ld-le-small-ilp32.d: Expect MOV and NOP.
	* ld-aarch64/tls-relax-ld-le-small.d: Likewise.
	* ld-aarch64/tls-relax-ld-le-tiny-ilp32.d: Likewise.
	* ld-aarch64/tls-relax-ld-le-tiny.d: Likewise.
	* ld-aarch64/weak-undefined.d: Expect NOP.
---
 bfd/elfnn-aarch64.c                           | 33 ++++++++++-----
 bfd/elfxx-aarch64.c                           | 40 +++++++++++++++----
 bfd/elfxx-aarch64.h                           |  2 +-
 ld/testsuite/ld-aarch64/aarch64-elf.exp       |  6 +++
 .../ld-aarch64/add-imm-zero-opt-norelax.d     | 22 ++++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsdesc.d     | 16 ++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsdesc.s     | 16 ++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsgd.d       | 15 +++++++
 .../ld-aarch64/add-imm-zero-opt-tlsgd.s       | 16 ++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsld.d       | 15 +++++++
 .../ld-aarch64/add-imm-zero-opt-tlsld.s       | 15 +++++++
 ld/testsuite/ld-aarch64/add-imm-zero-opt.d    | 22 ++++++++++
 ld/testsuite/ld-aarch64/add-imm-zero-opt.ld   | 16 ++++++++
 ld/testsuite/ld-aarch64/add-imm-zero-opt.s    | 34 ++++++++++++++++
 ld/testsuite/ld-aarch64/erratum843419.d       |  4 +-
 .../ld-aarch64/erratum843419_tls_ie.d         |  2 +-
 ld/testsuite/ld-aarch64/farcall-b-defsym.d    |  2 +-
 .../ld-aarch64/farcall-b-none-function.d      |  2 +-
 ld/testsuite/ld-aarch64/farcall-b-section.d   |  2 +-
 ld/testsuite/ld-aarch64/farcall-b.d           |  2 +-
 ld/testsuite/ld-aarch64/farcall-back-be.d     |  2 +-
 ld/testsuite/ld-aarch64/farcall-back.d        |  2 +-
 ld/testsuite/ld-aarch64/farcall-bl-defsym.d   |  2 +-
 .../ld-aarch64/farcall-bl-none-function.d     |  2 +-
 ld/testsuite/ld-aarch64/farcall-bl-section.d  |  2 +-
 ld/testsuite/ld-aarch64/farcall-bl.d          |  2 +-
 .../non-contiguous-mem/non-contiguous-ok-2.d  |  2 +-
 .../non-contiguous-mem/non-contiguous-ok-4.d  |  2 +-
 .../non-contiguous-mem/non-contiguous-ok-5.d  |  2 +-
 .../ld-aarch64/tls-relax-ld-le-small-ilp32.d  |  4 +-
 .../ld-aarch64/tls-relax-ld-le-small.d        |  4 +-
 .../ld-aarch64/tls-relax-ld-le-tiny-ilp32.d   |  4 +-
 .../ld-aarch64/tls-relax-ld-le-tiny.d         |  4 +-
 .../ld-aarch64/tls-tiny-gd-le-ilp32.d         |  2 +-
 ld/testsuite/ld-aarch64/tls-tiny-gd-le.d      |  2 +-
 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d  | 14 +++++++
 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s  | 13 ++++++
 ld/testsuite/ld-aarch64/weak-undefined.d      |  2 +-
 38 files changed, 303 insertions(+), 46 deletions(-)
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt.ld
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt.s
 create mode 100644 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d
 create mode 100644 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index cbd4abea122..632e62e9e1a 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2967,7 +2967,7 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
 
 static bool
 aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
-		  bfd_vma offset, bfd_vma value)
+		  bfd_vma offset, bfd_vma value, bool optimize_add_zero)
 {
   reloc_howto_type *howto;
   bfd_vma place;
@@ -2981,7 +2981,7 @@ aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
 					       value, 0, false);
   return _bfd_aarch64_elf_put_addend (input_bfd,
 				      input_section->contents + offset, r_type,
-				      howto, value) == bfd_reloc_ok;
+				      howto, value, optimize_add_zero) == bfd_reloc_ok;
 }
 
 /* Determine the type of stub needed, if any, for a call.  */
@@ -3256,6 +3256,7 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
   unsigned int pad_size = 0;
   const uint32_t *template;
   unsigned int i;
+  bool optimize_add_zero;
   struct bfd_link_info *info;
   struct elf_aarch64_link_hash_table *htab;
 
@@ -3349,17 +3350,18 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
   template_size = (template_size + 7) & ~7;
   stub_sec->size += template_size;
 
+  optimize_add_zero = info->disable_target_specific_optimizations <= 1;
   switch (stub_entry->stub_type)
     {
     case aarch64_stub_adrp_branch:
       if (!aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
-			     stub_entry->stub_offset, sym_value))
+			     stub_entry->stub_offset, sym_value, optimize_add_zero))
 	/* The stub would not have been relaxed if the offset was out
 	   of range.  */
 	BFD_FAIL ();
 
       if (!aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 4, sym_value))
+			     stub_entry->stub_offset + 4, sym_value, optimize_add_zero))
 	BFD_FAIL ();
       break;
 
@@ -3367,13 +3369,14 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
       /* We want the value relative to the address 12 bytes back from the
 	 value itself.  */
       if (!aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 16, sym_value + 12))
+			     stub_entry->stub_offset + 16, sym_value + 12,
+			     optimize_add_zero))
 	BFD_FAIL ();
       break;
 
     case aarch64_stub_bti_direct_branch:
       if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 4, sym_value))
+			     stub_entry->stub_offset + 4, sym_value, optimize_add_zero))
 	BFD_FAIL ();
       break;
 
@@ -3395,7 +3398,8 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
 
     case aarch64_stub_erratum_843419_veneer:
       if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 4, sym_value + 4))
+			     stub_entry->stub_offset + 4, sym_value + 4,
+			     optimize_add_zero))
 	BFD_FAIL ();
       break;
 
@@ -5764,6 +5768,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
   bfd_vma orig_value = value;
   bool resolved_to_zero;
   bool abs_symbol_p;
+  bool optimize_add_zero;
 
   globals = elf_aarch64_hash_table (info);
 
@@ -5785,6 +5790,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 		  : bfd_is_und_section (sym_sec));
   abs_symbol_p = h != NULL && bfd_is_abs_symbol (&h->root);
 
+  optimize_add_zero = info->disable_target_specific_optimizations <= 1;
 
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
      it here if it is defined in a non-shared object.  */
@@ -5917,7 +5923,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 						       signed_addend,
 						       weak_undef_p);
 	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
-					      howto, value);
+					      howto, value, optimize_add_zero);
 	case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
 	case BFD_RELOC_AARCH64_GOT_LD_PREL19:
 	case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
@@ -5993,7 +5999,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 	  value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
 						       place, value,
 						       addend, weak_undef_p);
-	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value);
+	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data,
+					      bfd_r_type, howto, value,
+					      optimize_add_zero);
 	case BFD_RELOC_AARCH64_ADD_LO12:
 	case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
 	  break;
@@ -6542,7 +6550,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
     return bfd_reloc_continue;
 
   return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
-				      howto, value);
+				      howto, value, optimize_add_zero);
 }
 
 /* LP64 and ILP32 operates on x- and w-registers respectively.
@@ -9893,7 +9901,10 @@ elf_aarch64_update_plt_entry (bfd *output_bfd,
   reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (r_type);
 
   /* FIXME: We should check the return value from this function call.  */
-  (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
+  /* PLT entries are linker generated and have no retained input
+     relocations.  */
+  (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type,
+				      howto, value, true);
 }
 
 static void
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 69ef148bf9c..c9b8b01990b 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
@@ -161,7 +173,8 @@ aarch64_signed_overflow (bfd_vma value, unsigned int bits)
 bfd_reloc_status_type
 _bfd_aarch64_elf_put_addend (bfd *abfd,
 			     bfd_byte *address, bfd_reloc_code_real_type r_type,
-			     reloc_howto_type *howto, bfd_signed_vma addend)
+			     reloc_howto_type *howto, bfd_signed_vma addend,
+			     bool optimize_add_zero)
 {
   bfd_reloc_status_type status = bfd_reloc_ok;
   bfd_signed_vma old_addend = addend;
@@ -261,12 +274,25 @@ _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);
-      break;
+      /* Optimize an ADD whose relocated 12-bit immediate is zero.  */
+      {
+	unsigned int rd = contents & MASK (5);
+	unsigned int rn = (contents >> 5) & MASK (5);
+
+	if (optimize_add_zero && (addend & MASK (12)) == 0
+	    && (contents & 0x7f800000) == 0x11000000
+	    && rd != 31
+	    && rn != 31)
+	  {
+	    if (rd == rn && (contents & (1U << 31)) != 0)
+	      contents = AARCH64_NOP_OPCODE;
+	    else
+	      contents = reencode_add_to_mov (contents, rd, rn);
+	  }
+	else
+	  contents = reencode_add_imm (contents, addend);
+	break;
+      }
 
     case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index a312427bc75..8345086f9f4 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -218,7 +218,7 @@ _bfd_aarch64_reencode_adr_imm (uint32_t, uint32_t) ATTRIBUTE_HIDDEN;
 
 extern bfd_reloc_status_type
 _bfd_aarch64_elf_put_addend (bfd *, bfd_byte *, bfd_reloc_code_real_type,
-			     reloc_howto_type *, bfd_signed_vma)
+			     reloc_howto_type *, bfd_signed_vma, bool)
 			    ATTRIBUTE_HIDDEN;
 
 extern bfd_vma
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index fa80210500e..f4941b01518 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -284,6 +284,12 @@ 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-norelax"
+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-norelax.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.d
new file mode 100644
index 00000000000..2b28bcbe2ba
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.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 --no-relax
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	91000000 	add	x0, x0, #0x0
+ +10004:	91400041 	add	x1, x2, #0x0, lsl #12
+ +10008:	91000063 	add	x3, x3, #0x0
+ +1000c:	910000a4 	add	x4, x5, #0x0
+ +10010:	914000e6 	add	x6, x7, #0x0, lsl #12
+ +10014:	91000108 	add	x8, x8, #0x0
+ +10018:	91000149 	add	x9, x10, #0x0
+ +1001c:	1100016b 	add	w11, w11, #0x0
+ +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-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
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.