[llvm] [BOLT][AArch64] Add support for LDR relaxation on LDRSl/LDRDl/LDRQl (PR #196983)

Shanzhi Chen via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 07:08:10 PDT 2026


https://github.com/chenshanzhi updated https://github.com/llvm/llvm-project/pull/196983

>From c889d5ff1da0d50f7b5784b0e4dc220237786e76 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Mon, 11 May 2026 23:17:06 +0800
Subject: [PATCH 1/9] [BOLT][AArch64] Add support for LDR relaxtion on
 LDRSl/LDRDl/LDRQl

AArch64 currently has 6 `LoadLiteral` instructions:
- 3 with a GPR as the destination register (LDRWl, LDRXl, LDRSWl)
- 3 with an FPR as the destination register (LDRSl, LDRDl, LDRQl)

BOLT already supports LDR relaxation for the first three instructions.
For the latter three, the destination register cannot be used to hold the base
address directly. Therefore LivenessAnalysis can be used to obtain usable
registers for LDR relaxation, allowing BOLT to support LDR relaxation for
these instructions as well.

In addition, a hidden option is added to control the LDR relaxation for
LDRSl/LDRDl/LDRQl because LivenessAnalysis may be expensive and may not
always find usable registers for a specific ProgramPoint.
---
 bolt/include/bolt/Core/MCPlusBuilder.h        |  8 +-
 .../bolt/Passes/AArch64RelaxationPass.h       |  7 ++
 bolt/lib/Passes/AArch64RelaxationPass.cpp     | 40 ++++++--
 .../Target/AArch64/AArch64MCPlusBuilder.cpp   | 30 +++++-
 bolt/test/AArch64/ldr-relaxation.s            | 98 +++++++++++++++++++
 5 files changed, 171 insertions(+), 12 deletions(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 3a840615bec8f..8d7c39d05bb02 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -866,6 +866,11 @@ class MCPlusBuilder {
     return false;
   }
 
+  virtual bool isLoadLiteralFPR(const MCInst &Inst) const {
+    llvm_unreachable("not implemented");
+    return false;
+  }
+
   virtual bool isMOVW(const MCInst &Inst) const {
     llvm_unreachable("not implemented");
     return false;
@@ -1852,7 +1857,8 @@ class MCPlusBuilder {
   ///     adrp x0, PageBase(label)
   ///     ldr  x0, [x0, PageOffset(label)]
   virtual InstructionListType createAdrpLdr(const MCInst &LDRInst,
-                                            MCContext *Ctx) const {
+                                            MCContext *Ctx,
+                                            MCPhysReg Reg = 0) const {
     llvm_unreachable("not implemented");
   }
 
diff --git a/bolt/include/bolt/Passes/AArch64RelaxationPass.h b/bolt/include/bolt/Passes/AArch64RelaxationPass.h
index b9185a1e34388..36126c5436709 100644
--- a/bolt/include/bolt/Passes/AArch64RelaxationPass.h
+++ b/bolt/include/bolt/Passes/AArch64RelaxationPass.h
@@ -19,11 +19,18 @@
 #define BOLT_PASSES_AARCH64RELAXATIONPASS_H
 
 #include "bolt/Passes/BinaryPasses.h"
+#include <memory>
 
 namespace llvm {
 namespace bolt {
 
+class RegAnalysis;
+class BinaryFunctionCallGraph;
+
 class AArch64RelaxationPass : public BinaryFunctionPass {
+  std::unique_ptr<RegAnalysis> RA;
+  std::unique_ptr<BinaryFunctionCallGraph> CG;
+
 public:
   explicit AArch64RelaxationPass(const cl::opt<bool> &PrintPass)
       : BinaryFunctionPass(PrintPass) {}
diff --git a/bolt/lib/Passes/AArch64RelaxationPass.cpp b/bolt/lib/Passes/AArch64RelaxationPass.cpp
index 2b7384dc848dd..89cc030c4abc4 100644
--- a/bolt/lib/Passes/AArch64RelaxationPass.cpp
+++ b/bolt/lib/Passes/AArch64RelaxationPass.cpp
@@ -11,9 +11,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "bolt/Passes/AArch64RelaxationPass.h"
+#include "bolt/Core/BinaryFunctionCallGraph.h"
 #include "bolt/Core/ParallelUtilities.h"
+#include "bolt/Passes/DataflowInfoManager.h"
 #include "bolt/Utils/CommandLineOpts.h"
 #include <iterator>
+#include <memory>
 
 using namespace llvm;
 
@@ -24,6 +27,12 @@ static cl::opt<bool> AArch64PassOpt(
     "aarch64-relaxation",
     cl::desc("Replace ARM non-local ADR/LDR instructions with ADRP"),
     cl::init(true), cl::cat(BoltCategory), cl::ReallyHidden);
+
+static cl::opt<bool> AArch64RelaxLoadLiteralFPR(
+    "aarch64-relax-ldr-fp-using-la",
+    cl::desc("Replace AArch64 LDR (literal, SIMD&FP) with ADRP, "
+             "using LivenessAnalysis to find available regsiters"),
+    cl::init(true), cl::cat(BoltCategory), cl::Hidden);
 } // namespace opts
 
 namespace llvm {
@@ -44,9 +53,10 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
     for (auto It = BB.begin(); It != BB.end(); ++It) {
       MCInst &Inst = *It;
       bool IsADR = BC.MIB->isADR(Inst);
-
-      // TODO: Handle other types of LDR (literal, PC-relative) instructions.
-      if (!IsADR && !BC.MIB->isLoadLiteralGPR(Inst))
+      bool IsLoadLiteralGPR = BC.MIB->isLoadLiteralGPR(Inst);
+      bool IsLoadLiteralFPR =
+          (opts::AArch64RelaxLoadLiteralFPR && BC.MIB->isLoadLiteralFPR(Inst));
+      if (!IsADR && !IsLoadLiteralGPR && !IsLoadLiteralFPR)
         continue;
 
       const MCSymbol *Symbol = BC.MIB->getTargetSymbol(Inst, IsADR ? 0 : 1);
@@ -77,9 +87,27 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
       InstructionListType AdrpMaterialization;
       {
         auto L = BC.scopeLock();
-        AdrpMaterialization =
-            IsADR ? BC.MIB->undoAdrpAddRelaxation(Inst, BC.Ctx.get())
-                  : BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());
+        if (IsADR) {
+          AdrpMaterialization =
+              BC.MIB->undoAdrpAddRelaxation(Inst, BC.Ctx.get());
+        } else if (IsLoadLiteralGPR) {
+          AdrpMaterialization = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());
+        } else if (IsLoadLiteralFPR) {
+          if (!RA) {
+            CG.reset(new BinaryFunctionCallGraph(buildCallGraph(BC)));
+            RA.reset(new RegAnalysis(BC, &BC.getBinaryFunctions(), &*CG));
+          }
+          DataflowInfoManager Info(BF, RA.get(), nullptr);
+          auto Reg = Info.getLivenessAnalysis().scavengeRegAfter(&Inst);
+          if (Reg == 0) {
+            BC.outs()
+                << "BOLT-INFO: For lack of a register to hold the address, "
+                << "this LDR (literal, SIMD&FP) cannot be relaxed:\n";
+            BC.printInstruction(BC.outs(), Inst);
+            continue;
+          }
+          AdrpMaterialization = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get(), Reg);
+        }
       }
 
       if (It != BB.begin() && BC.MIB->isNoop(*std::prev(It))) {
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 6695198802006..03eb70a0fd7c4 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -721,6 +721,12 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
            OpCode == AArch64::LDRSWl;
   }
 
+  bool isLoadLiteralFPR(const MCInst &Inst) const override {
+    unsigned OpCode = Inst.getOpcode();
+    return OpCode == AArch64::LDRSl || OpCode == AArch64::LDRDl ||
+           OpCode == AArch64::LDRQl;
+  }
+
   MCPhysReg getADRReg(const MCInst &Inst) const {
     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
     assert(MCPlus::getNumPrimeOperands(Inst) != 0 &&
@@ -740,10 +746,8 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
     return materializeAddress(Target, Ctx, Reg, Addend);
   }
 
-  InstructionListType createAdrpLdr(const MCInst &LDRInst,
-                                    MCContext *Ctx) const override {
-    assert(isLoadLiteralGPR(LDRInst) &&
-           "LDR (literal) or LDRSW (literal) expected");
+  InstructionListType createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
+                                    MCPhysReg Reg) const override {
     assert(LDRInst.getOperand(0).isReg() &&
            "unexpected operand in LDR instruction");
     const MCPhysReg DataReg = LDRInst.getOperand(0).getReg();
@@ -768,8 +772,24 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
       OpCode = AArch64::LDRSWui;
       RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
       break;
+    case AArch64::LDRSl:
+      AddrReg = Reg;
+      OpCode = AArch64::LDRSui;
+      RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
+      break;
+    case AArch64::LDRDl:
+      AddrReg = Reg;
+      OpCode = AArch64::LDRDui;
+      RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
+      break;
+    case AArch64::LDRQl:
+      AddrReg = Reg;
+      OpCode = AArch64::LDRQui;
+      RelType = ELF::R_AARCH64_LDST128_ABS_LO12_NC;
+      break;
     default:
-      llvm_unreachable("LDR (literal) or LDRSW (literal) expected");
+      llvm_unreachable("LDR (literal), LDRSW (literal), LDR (literal, SIMD&FP) "
+                       "expected");
     }
 
     const MCSymbol *Target = getTargetSymbol(LDRInst, 1);
diff --git a/bolt/test/AArch64/ldr-relaxation.s b/bolt/test/AArch64/ldr-relaxation.s
index 58ffeb034c253..2c4f3e64e3c21 100644
--- a/bolt/test/AArch64/ldr-relaxation.s
+++ b/bolt/test/AArch64/ldr-relaxation.s
@@ -135,6 +135,98 @@ _start:
   ret
   .cfi_endproc
 .size _start, .-_start
+.endif
+
+## Check LDR relaxation works on loading S registers.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_SIMPLE_LDR_FP32=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDR_FP32
+
+# RELAX_LDR_FP32: adrp
+# RELAX_LDR_FP32-NEXT: ldr s0
+.ifdef RELAX_SIMPLE_LDR_FP32
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr s0, _bar
+  mov x0, xzr
+  ret
+  .cfi_endproc
+.size _start, .-_start
+.endif
+
+## Check LDR relaxation works on loading D registers.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_SIMPLE_LDR_FP64=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDR_FP64
+
+# RELAX_LDR_FP64: adrp
+# RELAX_LDR_FP64-NEXT: ldr d0
+.ifdef RELAX_SIMPLE_LDR_FP64
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr d0, _bar
+  mov x0, xzr
+  ret
+  .cfi_endproc
+.size _start, .-_start
+.endif
+
+## Check LDR relaxation works on loading Q registers.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_SIMPLE_LDR_FP128=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDR_FP128
+
+# RELAX_LDR_FP128: adrp
+# RELAX_LDR_FP128-NEXT: ldr q0
+.ifdef RELAX_SIMPLE_LDR_FP128
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr q0, _bar
+  mov x0, xzr
+  ret
+  .cfi_endproc
+.size _start, .-_start
+.endif
+
+## Check that disabling LDR relaxation for LDR (literal, SIMD&FP)
+## triggers a link error when such an instruction needs relaxation.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym NO_RELAX_SIMPLE_LDR_FP=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: not llvm-bolt %t.so -o %t.bolt -aarch64-relax-ldr-fp-using-la=false \
+# RUN:    2>&1 | FileCheck %s --check-prefix=NO_RELAX_LDR_FP
+
+# NO_RELAX_LDR_FP: BOLT-ERROR: JITLink failed: In graph in-memory object file, section .text: relocation target {{0x[0-9a-f]+}} {{.*}} is out of range of LDRLiteral19 fixup at address {{0x[0-9a-f]+}} {{.*}}
+.ifdef NO_RELAX_SIMPLE_LDR_FP
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr q0, _bar
+  mov x0, xzr
+  ret
+  .cfi_endproc
+.size _start, .-_start
 .endif
 
   .section .text_cold
@@ -143,3 +235,9 @@ _start:
 _foo:
   .long 0x12345678
 .size _foo, .-_foo
+  .global _bar
+  .align 4
+_bar:
+  .xword  0x0000000000000000
+  .xword  0x0000000000000000
+.size _bar, .-_bar

>From 380e9baa343568ed82470553f81308840bb0552b Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Thu, 11 Jun 2026 20:49:27 +0800
Subject: [PATCH 2/9] [BOLT][AArch64] Add initial support for LDR relaxtion on
 LDRSl/LDRDl/LDRQl

AArch64 currently has 6 `LoadLiteral` instructions:
- 3 with a GPR as the destination register (LDRWl, LDRXl, LDRSWl)
- 3 with an FPR as the destination register (LDRSl, LDRDl, LDRQl)

BOLT already supports LDR relaxation for the first three instructions.
For the latter three, the destination register cannot be used to hold the base
address directly. Therefore one general-purpose register firstly is saved to
the stack, then is used to hold the base address, and finally is restored from
the stack.
---
 bolt/include/bolt/Core/MCPlusBuilder.h        | 15 ++++++--
 .../bolt/Passes/AArch64RelaxationPass.h       |  7 ----
 bolt/lib/Passes/AArch64RelaxationPass.cpp     | 37 +++++++------------
 .../Target/AArch64/AArch64MCPlusBuilder.cpp   | 20 ++++++++++
 bolt/test/AArch64/ldr-relaxation.s            | 26 -------------
 5 files changed, 45 insertions(+), 60 deletions(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 8d7c39d05bb02..0b1736564cbdc 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1856,9 +1856,18 @@ class MCPlusBuilder {
   ///
   ///     adrp x0, PageBase(label)
   ///     ldr  x0, [x0, PageOffset(label)]
-  virtual InstructionListType createAdrpLdr(const MCInst &LDRInst,
-                                            MCContext *Ctx,
-                                            MCPhysReg Reg = 0) const {
+  ///
+  /// For
+  ///
+  ///     ldr  q0, [label]
+  ///
+  /// the following sequence will be generated:
+  ///
+  ///     adrp Reg, PageBase(label)
+  ///     ldr  x0, [Reg, PageOffset(label)]
+  virtual InstructionListType
+  createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
+                MCPhysReg Reg = MCRegister::NoRegister) const {
     llvm_unreachable("not implemented");
   }
 
diff --git a/bolt/include/bolt/Passes/AArch64RelaxationPass.h b/bolt/include/bolt/Passes/AArch64RelaxationPass.h
index 36126c5436709..b9185a1e34388 100644
--- a/bolt/include/bolt/Passes/AArch64RelaxationPass.h
+++ b/bolt/include/bolt/Passes/AArch64RelaxationPass.h
@@ -19,18 +19,11 @@
 #define BOLT_PASSES_AARCH64RELAXATIONPASS_H
 
 #include "bolt/Passes/BinaryPasses.h"
-#include <memory>
 
 namespace llvm {
 namespace bolt {
 
-class RegAnalysis;
-class BinaryFunctionCallGraph;
-
 class AArch64RelaxationPass : public BinaryFunctionPass {
-  std::unique_ptr<RegAnalysis> RA;
-  std::unique_ptr<BinaryFunctionCallGraph> CG;
-
 public:
   explicit AArch64RelaxationPass(const cl::opt<bool> &PrintPass)
       : BinaryFunctionPass(PrintPass) {}
diff --git a/bolt/lib/Passes/AArch64RelaxationPass.cpp b/bolt/lib/Passes/AArch64RelaxationPass.cpp
index 89cc030c4abc4..2d402c64810bf 100644
--- a/bolt/lib/Passes/AArch64RelaxationPass.cpp
+++ b/bolt/lib/Passes/AArch64RelaxationPass.cpp
@@ -11,12 +11,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "bolt/Passes/AArch64RelaxationPass.h"
-#include "bolt/Core/BinaryFunctionCallGraph.h"
 #include "bolt/Core/ParallelUtilities.h"
-#include "bolt/Passes/DataflowInfoManager.h"
 #include "bolt/Utils/CommandLineOpts.h"
 #include <iterator>
-#include <memory>
 
 using namespace llvm;
 
@@ -28,11 +25,6 @@ static cl::opt<bool> AArch64PassOpt(
     cl::desc("Replace ARM non-local ADR/LDR instructions with ADRP"),
     cl::init(true), cl::cat(BoltCategory), cl::ReallyHidden);
 
-static cl::opt<bool> AArch64RelaxLoadLiteralFPR(
-    "aarch64-relax-ldr-fp-using-la",
-    cl::desc("Replace AArch64 LDR (literal, SIMD&FP) with ADRP, "
-             "using LivenessAnalysis to find available regsiters"),
-    cl::init(true), cl::cat(BoltCategory), cl::Hidden);
 } // namespace opts
 
 namespace llvm {
@@ -54,8 +46,7 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
       MCInst &Inst = *It;
       bool IsADR = BC.MIB->isADR(Inst);
       bool IsLoadLiteralGPR = BC.MIB->isLoadLiteralGPR(Inst);
-      bool IsLoadLiteralFPR =
-          (opts::AArch64RelaxLoadLiteralFPR && BC.MIB->isLoadLiteralFPR(Inst));
+      bool IsLoadLiteralFPR = BC.MIB->isLoadLiteralFPR(Inst);
       if (!IsADR && !IsLoadLiteralGPR && !IsLoadLiteralFPR)
         continue;
 
@@ -93,20 +84,18 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
         } else if (IsLoadLiteralGPR) {
           AdrpMaterialization = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());
         } else if (IsLoadLiteralFPR) {
-          if (!RA) {
-            CG.reset(new BinaryFunctionCallGraph(buildCallGraph(BC)));
-            RA.reset(new RegAnalysis(BC, &BC.getBinaryFunctions(), &*CG));
-          }
-          DataflowInfoManager Info(BF, RA.get(), nullptr);
-          auto Reg = Info.getLivenessAnalysis().scavengeRegAfter(&Inst);
-          if (Reg == 0) {
-            BC.outs()
-                << "BOLT-INFO: For lack of a register to hold the address, "
-                << "this LDR (literal, SIMD&FP) cannot be relaxed:\n";
-            BC.printInstruction(BC.outs(), Inst);
-            continue;
-          }
-          AdrpMaterialization = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get(), Reg);
+          MCInst PushReg, PopReg;
+          InstructionListType Insts;
+
+          MCPhysReg X0 = BC.MIB->getIntArgRegister(0);
+          BC.MIB->createPushRegister(PushReg, X0, 8);
+          Insts = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get(), X0);
+          BC.MIB->createPopRegister(PopReg, X0, 8);
+
+          AdrpMaterialization.emplace_back(PushReg);
+          AdrpMaterialization.insert(AdrpMaterialization.end(), Insts.begin(),
+                                     Insts.end());
+          AdrpMaterialization.emplace_back(PopReg);
         }
       }
 
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 03eb70a0fd7c4..5f290be5d1553 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -2641,6 +2641,26 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
     return false;
   }
 
+  void createPushRegister(MCInst &Inst, MCPhysReg Reg,
+                          unsigned Size) const override {
+    assert(Size == 8 && "Unexpected Size");
+    Inst = MCInstBuilder(AArch64::STRXpre)
+               .addReg(AArch64::SP)
+               .addReg(Reg)
+               .addReg(AArch64::SP)
+               .addImm(-8);
+  }
+
+  void createPopRegister(MCInst &Inst, MCPhysReg Reg,
+                         unsigned Size) const override {
+    assert(Size == 8 && "Unexpected Size");
+    Inst = MCInstBuilder(AArch64::LDRXpost)
+               .addReg(AArch64::SP)
+               .addReg(Reg)
+               .addReg(AArch64::SP)
+               .addImm(8);
+  }
+
   void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,
                         bool IsTailCall) override {
     Inst.setOpcode(IsTailCall ? AArch64::B : AArch64::BL);
diff --git a/bolt/test/AArch64/ldr-relaxation.s b/bolt/test/AArch64/ldr-relaxation.s
index 2c4f3e64e3c21..b9cbc82cc10ea 100644
--- a/bolt/test/AArch64/ldr-relaxation.s
+++ b/bolt/test/AArch64/ldr-relaxation.s
@@ -154,7 +154,6 @@ _start:
 _start:
   .cfi_startproc
   ldr s0, _bar
-  mov x0, xzr
   ret
   .cfi_endproc
 .size _start, .-_start
@@ -177,7 +176,6 @@ _start:
 _start:
   .cfi_startproc
   ldr d0, _bar
-  mov x0, xzr
   ret
   .cfi_endproc
 .size _start, .-_start
@@ -200,30 +198,6 @@ _start:
 _start:
   .cfi_startproc
   ldr q0, _bar
-  mov x0, xzr
-  ret
-  .cfi_endproc
-.size _start, .-_start
-.endif
-
-## Check that disabling LDR relaxation for LDR (literal, SIMD&FP)
-## triggers a link error when such an instruction needs relaxation.
-
-# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
-# RUN:    --defsym NO_RELAX_SIMPLE_LDR_FP=1 %s -o %t.o
-# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
-# RUN: not llvm-bolt %t.so -o %t.bolt -aarch64-relax-ldr-fp-using-la=false \
-# RUN:    2>&1 | FileCheck %s --check-prefix=NO_RELAX_LDR_FP
-
-# NO_RELAX_LDR_FP: BOLT-ERROR: JITLink failed: In graph in-memory object file, section .text: relocation target {{0x[0-9a-f]+}} {{.*}} is out of range of LDRLiteral19 fixup at address {{0x[0-9a-f]+}} {{.*}}
-.ifdef NO_RELAX_SIMPLE_LDR_FP
-  .text
-  .global _start
-  .type _start, %function
-_start:
-  .cfi_startproc
-  ldr q0, _bar
-  mov x0, xzr
   ret
   .cfi_endproc
 .size _start, .-_start

>From 09134775324beff3db4dc0dc16eae39fda3a7ee0 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Sat, 13 Jun 2026 18:07:16 +0800
Subject: [PATCH 3/9] fixup! [BOLT][AArch64] Add initial support for LDR
 relaxtion on LDRSl/LDRDl/LDRQl

---
 bolt/lib/Passes/AArch64RelaxationPass.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/bolt/lib/Passes/AArch64RelaxationPass.cpp b/bolt/lib/Passes/AArch64RelaxationPass.cpp
index 2d402c64810bf..68be00fa103c0 100644
--- a/bolt/lib/Passes/AArch64RelaxationPass.cpp
+++ b/bolt/lib/Passes/AArch64RelaxationPass.cpp
@@ -24,7 +24,6 @@ static cl::opt<bool> AArch64PassOpt(
     "aarch64-relaxation",
     cl::desc("Replace ARM non-local ADR/LDR instructions with ADRP"),
     cl::init(true), cl::cat(BoltCategory), cl::ReallyHidden);
-
 } // namespace opts
 
 namespace llvm {

>From 5e5111aadf6211d2e10d957aea328225e1e02017 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Wed, 1 Jul 2026 15:47:50 +0800
Subject: [PATCH 4/9] fixup! [BOLT][AArch64] Add initial support for LDR
 relaxtion on LDRSl/LDRDl/LDRQl

---
 bolt/include/bolt/Core/MCPlusBuilder.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 0b1736564cbdc..2d371e6c5f284 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1864,7 +1864,9 @@ class MCPlusBuilder {
   /// the following sequence will be generated:
   ///
   ///     adrp Reg, PageBase(label)
-  ///     ldr  x0, [Reg, PageOffset(label)]
+  ///     ldr  q0, [Reg, PageOffset(label)]
+  ///
+  /// where Reg is provided by the 3rd argument.
   virtual InstructionListType
   createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
                 MCPhysReg Reg = MCRegister::NoRegister) const {

>From a1c62963b85e06a7ede72661efbc35357a1a9169 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Wed, 1 Jul 2026 15:58:10 +0800
Subject: [PATCH 5/9] fixup! [BOLT][AArch64] Add initial support for LDR
 relaxtion on LDRSl/LDRDl/LDRQl

---
 bolt/include/bolt/Core/MCPlusBuilder.h           | 2 +-
 bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 2d371e6c5f284..09ab372dbf257 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1869,7 +1869,7 @@ class MCPlusBuilder {
   /// where Reg is provided by the 3rd argument.
   virtual InstructionListType
   createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
-                MCPhysReg Reg = MCRegister::NoRegister) const {
+                const MCPhysReg Reg = MCRegister::NoRegister) const {
     llvm_unreachable("not implemented");
   }
 
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 5f290be5d1553..0c7ae3ca8bd51 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -747,7 +747,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
   }
 
   InstructionListType createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
-                                    MCPhysReg Reg) const override {
+                                    const MCPhysReg Reg) const override {
     assert(LDRInst.getOperand(0).isReg() &&
            "unexpected operand in LDR instruction");
     const MCPhysReg DataReg = LDRInst.getOperand(0).getReg();

>From 240cae4bdd08514c892902d465926209339959a4 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Thu, 23 Jul 2026 11:42:49 +0800
Subject: [PATCH 6/9] Address review comments

- Fix stack alignment issue
- Use x16 as base register
- Fix issue for a non-simple BinaryFunction
---
 bolt/include/bolt/Core/MCPlusBuilder.h        |  13 +-
 bolt/lib/Passes/AArch64RelaxationPass.cpp     |  45 +++--
 .../Target/AArch64/AArch64MCPlusBuilder.cpp   |  79 +++++----
 bolt/test/AArch64/ldr-relaxation.s            | 165 ++++++++++++++++--
 4 files changed, 219 insertions(+), 83 deletions(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 09ab372dbf257..1a372c2cb5d02 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1863,13 +1863,12 @@ class MCPlusBuilder {
   ///
   /// the following sequence will be generated:
   ///
-  ///     adrp Reg, PageBase(label)
-  ///     ldr  q0, [Reg, PageOffset(label)]
-  ///
-  /// where Reg is provided by the 3rd argument.
-  virtual InstructionListType
-  createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
-                const MCPhysReg Reg = MCRegister::NoRegister) const {
+  ///     stp x16, x17, [sp, #-16]!
+  ///     adrp x16, PageBase(label)
+  ///     ldr  q0, [x16, PageOffset(label)]
+  ///     ldp x16, x17, [sp], #16
+  virtual InstructionListType createAdrpLdr(const MCInst &LDRInst,
+                                            MCContext *Ctx) const {
     llvm_unreachable("not implemented");
   }
 
diff --git a/bolt/lib/Passes/AArch64RelaxationPass.cpp b/bolt/lib/Passes/AArch64RelaxationPass.cpp
index 68be00fa103c0..52759d717aac8 100644
--- a/bolt/lib/Passes/AArch64RelaxationPass.cpp
+++ b/bolt/lib/Passes/AArch64RelaxationPass.cpp
@@ -77,31 +77,27 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
       InstructionListType AdrpMaterialization;
       {
         auto L = BC.scopeLock();
-        if (IsADR) {
-          AdrpMaterialization =
-              BC.MIB->undoAdrpAddRelaxation(Inst, BC.Ctx.get());
-        } else if (IsLoadLiteralGPR) {
-          AdrpMaterialization = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());
-        } else if (IsLoadLiteralFPR) {
-          MCInst PushReg, PopReg;
-          InstructionListType Insts;
-
-          MCPhysReg X0 = BC.MIB->getIntArgRegister(0);
-          BC.MIB->createPushRegister(PushReg, X0, 8);
-          Insts = BC.MIB->createAdrpLdr(Inst, BC.Ctx.get(), X0);
-          BC.MIB->createPopRegister(PopReg, X0, 8);
-
-          AdrpMaterialization.emplace_back(PushReg);
-          AdrpMaterialization.insert(AdrpMaterialization.end(), Insts.begin(),
-                                     Insts.end());
-          AdrpMaterialization.emplace_back(PopReg);
-        }
+        AdrpMaterialization =
+            IsADR ? BC.MIB->undoAdrpAddRelaxation(Inst, BC.Ctx.get())
+                  : BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());
       }
 
-      if (It != BB.begin() && BC.MIB->isNoop(*std::prev(It))) {
-        It = BB.eraseInstruction(std::prev(It));
-      } else if (std::next(It) != BB.end() && BC.MIB->isNoop(*std::next(It))) {
-        BB.eraseInstruction(std::next(It));
+      size_t PrecedingNopCount = 0;
+      for (auto RevIt = std::make_reverse_iterator(It);
+           RevIt != BB.rend() && BC.MIB->isNoop(*RevIt); ++RevIt)
+        ++PrecedingNopCount;
+
+      size_t FollowingNopCount = 0;
+      for (auto FwdIt = std::next(It);
+           FwdIt != BB.end() && BC.MIB->isNoop(*FwdIt); ++FwdIt)
+        ++FollowingNopCount;
+
+      size_t InsertedInstCount = AdrpMaterialization.size() - 1;
+      if (PrecedingNopCount + FollowingNopCount >= InsertedInstCount) {
+        // Place the relaxed instruction sequence in place if possible.
+        auto Dst = It - std::min(InsertedInstCount, PrecedingNopCount);
+        std::copy(AdrpMaterialization.begin(), AdrpMaterialization.end(), Dst);
+        It += FollowingNopCount;
       } else if (!BF.isSimple()) {
         // If the function is not simple, it may contain a jump table undetected
         // by us. This jump table may use an offset from the branch instruction
@@ -113,8 +109,9 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
                   << " in non-simple function " << BF << '\n';
         PassFailed = true;
         return;
+      } else {
+        It = BB.replaceInstruction(It, AdrpMaterialization);
       }
-      It = BB.replaceInstruction(It, AdrpMaterialization);
     }
   }
 }
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 0c7ae3ca8bd51..6afb4d8a24d1d 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -746,8 +746,8 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
     return materializeAddress(Target, Ctx, Reg, Addend);
   }
 
-  InstructionListType createAdrpLdr(const MCInst &LDRInst, MCContext *Ctx,
-                                    const MCPhysReg Reg) const override {
+  InstructionListType createAdrpLdr(const MCInst &LDRInst,
+                                    MCContext *Ctx) const override {
     assert(LDRInst.getOperand(0).isReg() &&
            "unexpected operand in LDR instruction");
     const MCPhysReg DataReg = LDRInst.getOperand(0).getReg();
@@ -773,17 +773,17 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
       RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
       break;
     case AArch64::LDRSl:
-      AddrReg = Reg;
+      AddrReg = AArch64::X16;
       OpCode = AArch64::LDRSui;
       RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
       break;
     case AArch64::LDRDl:
-      AddrReg = Reg;
+      AddrReg = AArch64::X16;
       OpCode = AArch64::LDRDui;
       RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
       break;
     case AArch64::LDRQl:
-      AddrReg = Reg;
+      AddrReg = AArch64::X16;
       OpCode = AArch64::LDRQui;
       RelType = ELF::R_AARCH64_LDST128_ABS_LO12_NC;
       break;
@@ -792,23 +792,46 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
                        "expected");
     }
 
+    // For the relaxation of LDRSl/LDRDl/LDRQl, the destination register is a
+    // floating-point register and therefore cannot be reused as the base
+    // register. The current implementation uses X16 as the base register and
+    // saves/restores X16 and X17 by pushing them onto the stack before use and
+    // popping them afterward.
+    //
+    // X16 and X17 are pushed/popped together for two reasons:
+    // 1. AAPCS64 requires the stack to remain 16-byte (quad-word) aligned.
+    // 2. Pushing/popping registers that are already in use here may reduce
+    //    instruction-level parallelism (ILP) on out-of-order processors. X16
+    //    and X17 are more likely to be not in use at this point.
+    bool PreserveRegisters = isLoadLiteralFPR(LDRInst);
+
     const MCSymbol *Target = getTargetSymbol(LDRInst, 1);
     assert(Target && "missing target symbol in LDR instruction");
 
-    InstructionListType Insts(2);
-    Insts[0].setOpcode(AArch64::ADRP);
-    Insts[0].clear();
-    Insts[0].addOperand(MCOperand::createReg(AddrReg));
-    Insts[0].addOperand(MCOperand::createImm(0));
-    setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, 0, Ctx,
+    InstructionListType Insts;
+    if (PreserveRegisters) {
+      Insts.emplace_back();
+      createPushRegisters(Insts.back(), AArch64::X16, AArch64::X17);
+    }
+    Insts.emplace_back();
+    Insts.back().setOpcode(AArch64::ADRP);
+    Insts.back().clear();
+    Insts.back().addOperand(MCOperand::createReg(AddrReg));
+    Insts.back().addOperand(MCOperand::createImm(0));
+    setOperandToSymbolRef(Insts.back(), /* OpNum */ 1, Target, 0, Ctx,
                           ELF::R_AARCH64_NONE);
-    Insts[1].setOpcode(OpCode);
-    Insts[1].clear();
-    Insts[1].addOperand(MCOperand::createReg(DataReg));
-    Insts[1].addOperand(MCOperand::createReg(AddrReg));
-    Insts[1].addOperand(MCOperand::createImm(0));
-    Insts[1].addOperand(MCOperand::createImm(0));
-    setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, 0, Ctx, RelType);
+    Insts.emplace_back();
+    Insts.back().setOpcode(OpCode);
+    Insts.back().clear();
+    Insts.back().addOperand(MCOperand::createReg(DataReg));
+    Insts.back().addOperand(MCOperand::createReg(AddrReg));
+    Insts.back().addOperand(MCOperand::createImm(0));
+    Insts.back().addOperand(MCOperand::createImm(0));
+    setOperandToSymbolRef(Insts.back(), /* OpNum */ 2, Target, 0, Ctx, RelType);
+    if (PreserveRegisters) {
+      Insts.emplace_back();
+      createPopRegisters(Insts.back(), AArch64::X16, AArch64::X17);
+    }
     return Insts;
   }
 
@@ -2641,26 +2664,6 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
     return false;
   }
 
-  void createPushRegister(MCInst &Inst, MCPhysReg Reg,
-                          unsigned Size) const override {
-    assert(Size == 8 && "Unexpected Size");
-    Inst = MCInstBuilder(AArch64::STRXpre)
-               .addReg(AArch64::SP)
-               .addReg(Reg)
-               .addReg(AArch64::SP)
-               .addImm(-8);
-  }
-
-  void createPopRegister(MCInst &Inst, MCPhysReg Reg,
-                         unsigned Size) const override {
-    assert(Size == 8 && "Unexpected Size");
-    Inst = MCInstBuilder(AArch64::LDRXpost)
-               .addReg(AArch64::SP)
-               .addReg(Reg)
-               .addReg(AArch64::SP)
-               .addImm(8);
-  }
-
   void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,
                         bool IsTailCall) override {
     Inst.setOpcode(IsTailCall ? AArch64::B : AArch64::BL);
diff --git a/bolt/test/AArch64/ldr-relaxation.s b/bolt/test/AArch64/ldr-relaxation.s
index b9cbc82cc10ea..40f6adbc26a8c 100644
--- a/bolt/test/AArch64/ldr-relaxation.s
+++ b/bolt/test/AArch64/ldr-relaxation.s
@@ -18,7 +18,7 @@ _start:
   ldr x0, _foo
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check that LDR relaxation is not needed since the reference is not far away.
@@ -41,7 +41,7 @@ _start:
   ldr x0, _start
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check that LDR relaxation is done in a simple function, where NOP will
@@ -65,7 +65,7 @@ _start:
   ldr x0, _foo
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check that LDR relaxation is done in a non-simple function, where NOP
@@ -88,7 +88,7 @@ _start:
   nop
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check LDR relaxation works on loading W (low 32-bit of X) registers.
@@ -111,7 +111,7 @@ _start:
   ldr w0, _foo
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check LDR relaxation works on LDRSW (literal)
@@ -134,7 +134,7 @@ _start:
   ldrsw x0, _foo
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check LDR relaxation works on loading S registers.
@@ -145,8 +145,12 @@ _start:
 # RUN: llvm-bolt %t.so -o %t.bolt
 # RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDR_FP32
 
-# RELAX_LDR_FP32: adrp
+# RELAX_LDR_FP32: _start
+# RELAX_LDR_FP32-NEXT: stp x16, x17, [sp, #-0x10]!
+# RELAX_LDR_FP32-NEXT: adrp x16
 # RELAX_LDR_FP32-NEXT: ldr s0
+# RELAX_LDR_FP32-NEXT: ldp x16, x17, [sp], #0x10
+# RELAX_LDR_FP32-NEXT: ret
 .ifdef RELAX_SIMPLE_LDR_FP32
   .text
   .global _start
@@ -156,7 +160,7 @@ _start:
   ldr s0, _bar
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check LDR relaxation works on loading D registers.
@@ -167,8 +171,12 @@ _start:
 # RUN: llvm-bolt %t.so -o %t.bolt
 # RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDR_FP64
 
-# RELAX_LDR_FP64: adrp
+# RELAX_LDR_FP64: _start
+# RELAX_LDR_FP64-NEXT: stp x16, x17, [sp, #-0x10]!
+# RELAX_LDR_FP64-NEXT: adrp x16
 # RELAX_LDR_FP64-NEXT: ldr d0
+# RELAX_LDR_FP64-NEXT: ldp x16, x17, [sp], #0x10
+# RELAX_LDR_FP64-NEXT: ret
 .ifdef RELAX_SIMPLE_LDR_FP64
   .text
   .global _start
@@ -178,7 +186,7 @@ _start:
   ldr d0, _bar
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
 .endif
 
 ## Check LDR relaxation works on loading Q registers.
@@ -189,8 +197,12 @@ _start:
 # RUN: llvm-bolt %t.so -o %t.bolt
 # RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDR_FP128
 
-# RELAX_LDR_FP128: adrp
+# RELAX_LDR_FP128: _start
+# RELAX_LDR_FP128-NEXT: stp x16, x17, [sp, #-0x10]!
+# RELAX_LDR_FP128-NEXT: adrp x16
 # RELAX_LDR_FP128-NEXT: ldr q0
+# RELAX_LDR_FP128-NEXT: ldp x16, x17, [sp], #0x10
+# RELAX_LDR_FP128-NEXT: ret
 .ifdef RELAX_SIMPLE_LDR_FP128
   .text
   .global _start
@@ -200,7 +212,132 @@ _start:
   ldr q0, _bar
   ret
   .cfi_endproc
-.size _start, .-_start
+  .size _start, .-_start
+.endif
+
+## Check that LDR relaxation is done in a non-simple function when the load
+## instruction is preceded by enough nops.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_NON_SIMPLE_PRECEDED_BY_NOPS=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=PRECEDED_BY_NOPS
+
+# PRECEDED_BY_NOPS: _start
+# PRECEDED_BY_NOPS-NEXT: br x2
+# PRECEDED_BY_NOPS-NEXT: nop
+# PRECEDED_BY_NOPS-NEXT: stp x16, x17, [sp, #-0x10]!
+# PRECEDED_BY_NOPS-NEXT: adrp x16
+# PRECEDED_BY_NOPS-NEXT: ldr q0
+# PRECEDED_BY_NOPS-NEXT: ldp x16, x17, [sp], #0x10
+# PRECEDED_BY_NOPS-NEXT: ret
+.ifdef RELAX_NON_SIMPLE_PRECEDED_BY_NOPS
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  br x2
+  nop
+  nop
+  nop
+  nop
+  ldr q0, _bar
+  ret
+  .cfi_endproc
+  .size _start, .-_start
+.endif
+
+## Check that LDR relaxation is done in a non-simple function when the load
+## instruction is followed by enough nops.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_NON_SIMPLE_FOLLOWED_BY_NOPS=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=FOLLOWED_BY_NOPS
+
+# FOLLOWED_BY_NOPS: _start
+# FOLLOWED_BY_NOPS-NEXT: br x2
+# FOLLOWED_BY_NOPS-NEXT: stp x16, x17, [sp, #-0x10]!
+# FOLLOWED_BY_NOPS-NEXT: adrp x16
+# FOLLOWED_BY_NOPS-NEXT: ldr q0
+# FOLLOWED_BY_NOPS-NEXT: ldp x16, x17, [sp], #0x10
+# FOLLOWED_BY_NOPS-NEXT: nop
+# FOLLOWED_BY_NOPS-NEXT: ret
+.ifdef RELAX_NON_SIMPLE_FOLLOWED_BY_NOPS
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  br x2
+  ldr q0, _bar
+  nop
+  nop
+  nop
+  nop
+  ret
+  .cfi_endproc
+  .size _start, .-_start
+.endif
+
+## Check that LDR relaxation is done in a non-simple function when the load
+## instruction is surrouned by enough nops.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_NON_SIMPLE_SURROUNDED_BY_NOPS=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=SURROUNDED_BY_NOPS
+
+# SURROUNDED_BY_NOPS: _start
+# SURROUNDED_BY_NOPS-NEXT: br x2
+# SURROUNDED_BY_NOPS-NEXT: stp x16, x17, [sp, #-0x10]!
+# SURROUNDED_BY_NOPS-NEXT: adrp x16
+# SURROUNDED_BY_NOPS-NEXT: ldr q0
+# SURROUNDED_BY_NOPS-NEXT: ldp x16, x17, [sp], #0x10
+# SURROUNDED_BY_NOPS-NEXT: ret
+.ifdef RELAX_NON_SIMPLE_SURROUNDED_BY_NOPS
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  br x2
+  nop
+  nop
+  ldr q0, _bar
+  nop
+  ret
+  .cfi_endproc
+  .size _start, .-_start
+.endif
+
+## Check that LDR relaxation will fail in a non-simple function when there are
+## not enough NOPs around the load instruction to accommodate the relaxed
+## instruction sequence in place.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_NON_SIMPLE_NOT_ENOUGH_NOPS=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: not llvm-bolt %t.so -o %t.bolt 2>&1 | FileCheck %s --check-prefix=NOT_ENOUGH_NOPS
+
+# NOT_ENOUGH_NOPS: BOLT-ERROR: cannot relax LDR in non-simple function _start
+.ifdef RELAX_NON_SIMPLE_NOT_ENOUGH_NOPS
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  br x2
+  nop
+  ldr q0, _bar
+  nop
+  ret
+  .cfi_endproc
+  .size _start, .-_start
 .endif
 
   .section .text_cold
@@ -208,10 +345,10 @@ _start:
   .align 3
 _foo:
   .long 0x12345678
-.size _foo, .-_foo
+  .size _foo, .-_foo
   .global _bar
   .align 4
 _bar:
   .xword  0x0000000000000000
   .xword  0x0000000000000000
-.size _bar, .-_bar
+  .size _bar, .-_bar

>From a938093c91ade82c81249a7cda1f763d6aabc262 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Mon, 10 Aug 2026 21:53:39 +0800
Subject: [PATCH 7/9] Fix RelType for LDRSWl relaxation

LDRSWui is a 32-bit load, which means `RelType` should be
`ELF::R_AARCH64_LDST32_ABS_LO12_NC` for LDRSWl relaxation.
---
 bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 6afb4d8a24d1d..7e5d72617b125 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -770,7 +770,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
     case AArch64::LDRSWl:
       AddrReg = DataReg;
       OpCode = AArch64::LDRSWui;
-      RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
+      RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
       break;
     case AArch64::LDRSl:
       AddrReg = AArch64::X16;

>From 16016d95a180a4f25fe0bc466929a5a1c6ddb844 Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Mon, 10 Aug 2026 21:54:08 +0800
Subject: [PATCH 8/9] Add tests for constant islands and misaligned load

---
 bolt/test/AArch64/ldr-relaxation.s | 86 +++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 2 deletions(-)

diff --git a/bolt/test/AArch64/ldr-relaxation.s b/bolt/test/AArch64/ldr-relaxation.s
index 40f6adbc26a8c..89024c7c86829 100644
--- a/bolt/test/AArch64/ldr-relaxation.s
+++ b/bolt/test/AArch64/ldr-relaxation.s
@@ -340,6 +340,78 @@ _start:
   .size _start, .-_start
 .endif
 
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_CONSTANT_ISLANDS=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: not llvm-bolt %t.so -o %t.bolt -clone-constant-island=false 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=CONSTANT_ISLANDS
+
+# CONSTANT_ISLANDS: BOLT-ERROR: JITLink failed: PAGEOFF12 target is not aligned
+.ifdef RELAX_CONSTANT_ISLANDS
+  .text
+  .align 4
+  .global ci_func
+  .type ci_func, %function
+ci_func:
+  .cfi_startproc
+  mov x0, #0
+  ret
+  .p2align 4
+  .global ci_data
+ci_data:
+  .xword 0
+  .xword 0
+  .cfi_endproc
+  .size ci_func, .-ci_func
+
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr q0, ci_data
+  ret
+  .cfi_endproc
+  .size _start, .-_start
+.endif
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_MISALIGNED_LDR=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: not llvm-bolt %t.so -o %t.bolt 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=MISALIGNED_LDR
+
+# MISALIGNED_LDR: BOLT-ERROR: JITLink failed: PAGEOFF12 target is not aligned
+.ifdef RELAX_MISALIGNED_LDR
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr x0, _bar_plus_0x4
+  ret
+  .cfi_endproc
+  .size _start, .-_start
+.endif
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:    --defsym RELAX_MISALIGNED_LDR_FP=1 %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
+# RUN: not llvm-bolt %t.so -o %t.bolt -clone-constant-island=false 2>&1 | \
+# RUN:    FileCheck %s --check-prefix=MISALIGNED_LDR_FP
+
+# MISALIGNED_LDR_FP: BOLT-ERROR: JITLink failed: PAGEOFF12 target is not aligned
+.ifdef RELAX_MISALIGNED_LDR_FP
+  .text
+  .global _start
+  .type _start, %function
+_start:
+  .cfi_startproc
+  ldr q0, _bar_plus_0x8
+  ret
+  .cfi_endproc
+  .size _start, .-_start
+.endif
+
   .section .text_cold
   .global _foo
   .align 3
@@ -347,8 +419,18 @@ _foo:
   .long 0x12345678
   .size _foo, .-_foo
   .global _bar
+  .global _bar_plus_0x4
+  .global _bar_plus_0x8
+  .global _bar_plus_0xc
   .align 4
 _bar:
-  .xword  0x0000000000000000
-  .xword  0x0000000000000000
+  .word 0x00000000
+_bar_plus_0x4:
+  .word 0x11111111
+_bar_plus_0x8:
+  .word 0x22222222
+_bar_plus_0xc:
+  .word 0x33333333
+  .xword 0x0000000000000000
+  .xword 0x0000000000000000
   .size _bar, .-_bar

>From ed005f3c2dce03fd1308f3c2fa22528a94a5309e Mon Sep 17 00:00:00 2001
From: Shanzhi Chen <chenshanzhi at huawei.com>
Date: Tue, 11 Aug 2026 22:02:12 +0800
Subject: [PATCH 9/9] Use adrp+add+ldr by default

---
 bolt/include/bolt/Core/MCPlusBuilder.h        | 14 +++--
 bolt/lib/Passes/AArch64RelaxationPass.cpp     |  5 +-
 .../Target/AArch64/AArch64MCPlusBuilder.cpp   | 60 +++++++++++++------
 bolt/test/AArch64/ldr-relaxation.s            | 51 ++++++++++++----
 4 files changed, 97 insertions(+), 33 deletions(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 1a372c2cb5d02..386a59a1d19b8 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1848,7 +1848,11 @@ class MCPlusBuilder {
     llvm_unreachable("not implemented");
   }
 
-  /// Take \p LDRInst and return ADRP+LDR instruction sequence - for
+  /// Take \p LDRInst and return ADRP+LDR or ADRP+ADD+LDR instruction sequence.
+  /// \p TargetAlign represents the alignment of the target label.
+  /// Use ADRP+LDR if the target label is sufficiently aligned; otherwise use
+  /// ADRP+ADD+LDR. For example, assume that \p TargetAlign is 4.
+  /// For
   ///
   ///     ldr  x0, [label]
   ///
@@ -1865,10 +1869,12 @@ class MCPlusBuilder {
   ///
   ///     stp x16, x17, [sp, #-16]!
   ///     adrp x16, PageBase(label)
-  ///     ldr  q0, [x16, PageOffset(label)]
+  ///     add x16, x16, PageOffset(label)
+  ///     ldr  q0, [x16]
   ///     ldp x16, x17, [sp], #16
-  virtual InstructionListType createAdrpLdr(const MCInst &LDRInst,
-                                            MCContext *Ctx) const {
+  virtual InstructionListType relaxLoadLiteral(const MCInst &LDRInst,
+                                               MCContext *Ctx,
+                                               uint16_t TargetAlign) const {
     llvm_unreachable("not implemented");
   }
 
diff --git a/bolt/lib/Passes/AArch64RelaxationPass.cpp b/bolt/lib/Passes/AArch64RelaxationPass.cpp
index 52759d717aac8..711054652e283 100644
--- a/bolt/lib/Passes/AArch64RelaxationPass.cpp
+++ b/bolt/lib/Passes/AArch64RelaxationPass.cpp
@@ -76,10 +76,13 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
 
       InstructionListType AdrpMaterialization;
       {
+        // TODO: If possible, use the actual alignment of the target label
+        // instead of conservatively assuming 1-byte alignment when relaxing a
+        // LoadLiteral instruction.
         auto L = BC.scopeLock();
         AdrpMaterialization =
             IsADR ? BC.MIB->undoAdrpAddRelaxation(Inst, BC.Ctx.get())
-                  : BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());
+                  : BC.MIB->relaxLoadLiteral(Inst, BC.Ctx.get(), 1);
       }
 
       size_t PrecedingNopCount = 0;
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 7e5d72617b125..001ab140d8056 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -746,14 +746,17 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
     return materializeAddress(Target, Ctx, Reg, Addend);
   }
 
-  InstructionListType createAdrpLdr(const MCInst &LDRInst,
-                                    MCContext *Ctx) const override {
+  InstructionListType relaxLoadLiteral(const MCInst &LDRInst, MCContext *Ctx,
+                                       uint16_t TargetAlign) const override {
     assert(LDRInst.getOperand(0).isReg() &&
            "unexpected operand in LDR instruction");
+    assert(llvm::isPowerOf2_32(TargetAlign) &&
+           "TargetAlign should be power of 2");
     const MCPhysReg DataReg = LDRInst.getOperand(0).getReg();
     MCPhysReg AddrReg;
     unsigned OpCode;
     uint32_t RelType;
+    uint16_t RequiredAlign;
     switch (LDRInst.getOpcode()) {
     case AArch64::LDRWl:
       AddrReg = (MCPhysReg)RegInfo->getMatchingSuperReg(
@@ -761,31 +764,37 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
           &RegInfo->getRegClass(AArch64::GPR64RegClassID));
       OpCode = AArch64::LDRWui;
       RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
+      RequiredAlign = 4;
       break;
     case AArch64::LDRXl:
       AddrReg = DataReg;
       OpCode = AArch64::LDRXui;
       RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
+      RequiredAlign = 8;
       break;
     case AArch64::LDRSWl:
       AddrReg = DataReg;
       OpCode = AArch64::LDRSWui;
       RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
+      RequiredAlign = 4;
       break;
     case AArch64::LDRSl:
       AddrReg = AArch64::X16;
       OpCode = AArch64::LDRSui;
       RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
+      RequiredAlign = 4;
       break;
     case AArch64::LDRDl:
       AddrReg = AArch64::X16;
       OpCode = AArch64::LDRDui;
       RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
+      RequiredAlign = 8;
       break;
     case AArch64::LDRQl:
       AddrReg = AArch64::X16;
       OpCode = AArch64::LDRQui;
       RelType = ELF::R_AARCH64_LDST128_ABS_LO12_NC;
+      RequiredAlign = 16;
       break;
     default:
       llvm_unreachable("LDR (literal), LDRSW (literal), LDR (literal, SIMD&FP) "
@@ -813,21 +822,38 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
       Insts.emplace_back();
       createPushRegisters(Insts.back(), AArch64::X16, AArch64::X17);
     }
-    Insts.emplace_back();
-    Insts.back().setOpcode(AArch64::ADRP);
-    Insts.back().clear();
-    Insts.back().addOperand(MCOperand::createReg(AddrReg));
-    Insts.back().addOperand(MCOperand::createImm(0));
-    setOperandToSymbolRef(Insts.back(), /* OpNum */ 1, Target, 0, Ctx,
-                          ELF::R_AARCH64_NONE);
-    Insts.emplace_back();
-    Insts.back().setOpcode(OpCode);
-    Insts.back().clear();
-    Insts.back().addOperand(MCOperand::createReg(DataReg));
-    Insts.back().addOperand(MCOperand::createReg(AddrReg));
-    Insts.back().addOperand(MCOperand::createImm(0));
-    Insts.back().addOperand(MCOperand::createImm(0));
-    setOperandToSymbolRef(Insts.back(), /* OpNum */ 2, Target, 0, Ctx, RelType);
+
+    if (TargetAlign < RequiredAlign) {
+      // Use ADRP+ADD+LDR
+      InstructionListType Addr = materializeAddress(Target, Ctx, AddrReg, 0);
+      Insts.insert(Insts.end(), Addr.begin(), Addr.end());
+      Insts.emplace_back();
+      Insts.back().setOpcode(OpCode);
+      Insts.back().clear();
+      Insts.back().addOperand(MCOperand::createReg(DataReg));
+      Insts.back().addOperand(MCOperand::createReg(AddrReg));
+      Insts.back().addOperand(MCOperand::createImm(0));
+      Insts.back().addOperand(MCOperand::createImm(0));
+    } else {
+      // Use ADRP+LDR
+      Insts.emplace_back();
+      Insts.back().setOpcode(AArch64::ADRP);
+      Insts.back().clear();
+      Insts.back().addOperand(MCOperand::createReg(AddrReg));
+      Insts.back().addOperand(MCOperand::createImm(0));
+      setOperandToSymbolRef(Insts.back(), /* OpNum */ 1, Target, 0, Ctx,
+                            ELF::R_AARCH64_NONE);
+      Insts.emplace_back();
+      Insts.back().setOpcode(OpCode);
+      Insts.back().clear();
+      Insts.back().addOperand(MCOperand::createReg(DataReg));
+      Insts.back().addOperand(MCOperand::createReg(AddrReg));
+      Insts.back().addOperand(MCOperand::createImm(0));
+      Insts.back().addOperand(MCOperand::createImm(0));
+      setOperandToSymbolRef(Insts.back(), /* OpNum */ 2, Target, 0, Ctx,
+                            RelType);
+    }
+
     if (PreserveRegisters) {
       Insts.emplace_back();
       createPopRegisters(Insts.back(), AArch64::X16, AArch64::X17);
diff --git a/bolt/test/AArch64/ldr-relaxation.s b/bolt/test/AArch64/ldr-relaxation.s
index 89024c7c86829..df52054cf7846 100644
--- a/bolt/test/AArch64/ldr-relaxation.s
+++ b/bolt/test/AArch64/ldr-relaxation.s
@@ -54,6 +54,7 @@ _start:
 # RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX
 
 # RELAX: adrp
+# RELAX-NEXT: add
 # RELAX-NEXT: ldr
 
 .ifdef RELAX_SIMPLE
@@ -86,6 +87,7 @@ _start:
   br x2
   ldr x0, _foo
   nop
+  nop
   ret
   .cfi_endproc
   .size _start, .-_start
@@ -100,6 +102,7 @@ _start:
 # RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAXW
 
 # RELAXW: adrp x0
+# RELAXW-NEXT: add x0, x0
 # RELAXW-NEXT: ldr w0
 
 .ifdef RELAX_SIMPLE_WREG
@@ -123,6 +126,7 @@ _start:
 # RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDRSW
 
 # RELAX_LDRSW: adrp
+# RELAX_LDRSW-NEXT: add
 # RELAX_LDRSW-NEXT: ldrsw
 
 .ifdef RELAX_SIMPLE_LDRSW
@@ -148,6 +152,7 @@ _start:
 # RELAX_LDR_FP32: _start
 # RELAX_LDR_FP32-NEXT: stp x16, x17, [sp, #-0x10]!
 # RELAX_LDR_FP32-NEXT: adrp x16
+# RELAX_LDR_FP32-NEXT: add x16, x16
 # RELAX_LDR_FP32-NEXT: ldr s0
 # RELAX_LDR_FP32-NEXT: ldp x16, x17, [sp], #0x10
 # RELAX_LDR_FP32-NEXT: ret
@@ -174,6 +179,7 @@ _start:
 # RELAX_LDR_FP64: _start
 # RELAX_LDR_FP64-NEXT: stp x16, x17, [sp, #-0x10]!
 # RELAX_LDR_FP64-NEXT: adrp x16
+# RELAX_LDR_FP64-NEXT: add x16, x16
 # RELAX_LDR_FP64-NEXT: ldr d0
 # RELAX_LDR_FP64-NEXT: ldp x16, x17, [sp], #0x10
 # RELAX_LDR_FP64-NEXT: ret
@@ -200,6 +206,7 @@ _start:
 # RELAX_LDR_FP128: _start
 # RELAX_LDR_FP128-NEXT: stp x16, x17, [sp, #-0x10]!
 # RELAX_LDR_FP128-NEXT: adrp x16
+# RELAX_LDR_FP128-NEXT: add x16, x16
 # RELAX_LDR_FP128-NEXT: ldr q0
 # RELAX_LDR_FP128-NEXT: ldp x16, x17, [sp], #0x10
 # RELAX_LDR_FP128-NEXT: ret
@@ -229,6 +236,7 @@ _start:
 # PRECEDED_BY_NOPS-NEXT: nop
 # PRECEDED_BY_NOPS-NEXT: stp x16, x17, [sp, #-0x10]!
 # PRECEDED_BY_NOPS-NEXT: adrp x16
+# PRECEDED_BY_NOPS-NEXT: add x16, x16
 # PRECEDED_BY_NOPS-NEXT: ldr q0
 # PRECEDED_BY_NOPS-NEXT: ldp x16, x17, [sp], #0x10
 # PRECEDED_BY_NOPS-NEXT: ret
@@ -243,6 +251,7 @@ _start:
   nop
   nop
   nop
+  nop
   ldr q0, _bar
   ret
   .cfi_endproc
@@ -262,6 +271,7 @@ _start:
 # FOLLOWED_BY_NOPS-NEXT: br x2
 # FOLLOWED_BY_NOPS-NEXT: stp x16, x17, [sp, #-0x10]!
 # FOLLOWED_BY_NOPS-NEXT: adrp x16
+# FOLLOWED_BY_NOPS-NEXT: add x16, x16
 # FOLLOWED_BY_NOPS-NEXT: ldr q0
 # FOLLOWED_BY_NOPS-NEXT: ldp x16, x17, [sp], #0x10
 # FOLLOWED_BY_NOPS-NEXT: nop
@@ -278,6 +288,7 @@ _start:
   nop
   nop
   nop
+  nop
   ret
   .cfi_endproc
   .size _start, .-_start
@@ -296,6 +307,7 @@ _start:
 # SURROUNDED_BY_NOPS-NEXT: br x2
 # SURROUNDED_BY_NOPS-NEXT: stp x16, x17, [sp, #-0x10]!
 # SURROUNDED_BY_NOPS-NEXT: adrp x16
+# SURROUNDED_BY_NOPS-NEXT: add x16, x16
 # SURROUNDED_BY_NOPS-NEXT: ldr q0
 # SURROUNDED_BY_NOPS-NEXT: ldp x16, x17, [sp], #0x10
 # SURROUNDED_BY_NOPS-NEXT: ret
@@ -310,6 +322,7 @@ _start:
   nop
   ldr q0, _bar
   nop
+  nop
   ret
   .cfi_endproc
   .size _start, .-_start
@@ -343,10 +356,16 @@ _start:
 # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
 # RUN:    --defsym RELAX_CONSTANT_ISLANDS=1 %s -o %t.o
 # RUN: %clang %cflags %t.o -o %t.so -Wl,-q
-# RUN: not llvm-bolt %t.so -o %t.bolt -clone-constant-island=false 2>&1 | \
-# RUN:    FileCheck %s --check-prefix=CONSTANT_ISLANDS
-
-# CONSTANT_ISLANDS: BOLT-ERROR: JITLink failed: PAGEOFF12 target is not aligned
+# RUN: llvm-bolt %t.so -o %t.bolt -clone-constant-island=false
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=CONSTANT_ISLANDS
+
+# CONSTANT_ISLANDS: _start
+# CONSTANT_ISLANDS-NEXT: stp x16, x17, [sp, #-0x10]!
+# CONSTANT_ISLANDS-NEXT: adrp x16
+# CONSTANT_ISLANDS-NEXT: add x16, x16
+# CONSTANT_ISLANDS-NEXT: ldr q0
+# CONSTANT_ISLANDS-NEXT: ldp x16, x17, [sp], #0x10
+# CONSTANT_ISLANDS-NEXT: ret
 .ifdef RELAX_CONSTANT_ISLANDS
   .text
   .align 4
@@ -377,10 +396,14 @@ _start:
 # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
 # RUN:    --defsym RELAX_MISALIGNED_LDR=1 %s -o %t.o
 # RUN: %clang %cflags %t.o -o %t.so -Wl,-q
-# RUN: not llvm-bolt %t.so -o %t.bolt 2>&1 | \
-# RUN:    FileCheck %s --check-prefix=MISALIGNED_LDR
+# RUN: llvm-bolt %t.so -o %t.bolt
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=MISALIGNED_LDR
 
-# MISALIGNED_LDR: BOLT-ERROR: JITLink failed: PAGEOFF12 target is not aligned
+# MISALIGNED_LDR: _start
+# MISALIGNED_LDR-NEXT: adrp x0
+# MISALIGNED_LDR-NEXT: add x0, x0
+# MISALIGNED_LDR-NEXT: ldr x0
+# MISALIGNED_LDR-NEXT: ret
 .ifdef RELAX_MISALIGNED_LDR
   .text
   .global _start
@@ -396,10 +419,16 @@ _start:
 # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
 # RUN:    --defsym RELAX_MISALIGNED_LDR_FP=1 %s -o %t.o
 # RUN: %clang %cflags %t.o -o %t.so -Wl,-q
-# RUN: not llvm-bolt %t.so -o %t.bolt -clone-constant-island=false 2>&1 | \
-# RUN:    FileCheck %s --check-prefix=MISALIGNED_LDR_FP
-
-# MISALIGNED_LDR_FP: BOLT-ERROR: JITLink failed: PAGEOFF12 target is not aligned
+# RUN: llvm-bolt %t.so -o %t.bolt -clone-constant-island=false
+# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=MISALIGNED_LDR_FP
+
+# MISALIGNED_LDR_FP: _start
+# MISALIGNED_LDR_FP-NEXT: stp x16, x17, [sp, #-0x10]!
+# MISALIGNED_LDR_FP-NEXT: adrp x16
+# MISALIGNED_LDR_FP-NEXT: add x16, x16
+# MISALIGNED_LDR_FP-NEXT: ldr q0
+# MISALIGNED_LDR_FP-NEXT: ldp x16, x17, [sp], #0x10
+# MISALIGNED_LDR_FP-NEXT: ret
 .ifdef RELAX_MISALIGNED_LDR_FP
   .text
   .global _start



More information about the llvm-commits mailing list