https://github.com/dongjianqiang2 created 
https://github.com/llvm/llvm-project/pull/142982

This patch implements backend support for -mlong-calls on AArch64 targets. When 
enabled, calls to external functions are lowered to an indirect call via an 
address computed using `adrp` and `add` rather than a direct `bl` instruction, 
which is limited to a ±128MB PC-relative offset.

This is particularly useful when code and/or data exceeds the 26-bit immediate 
range of `bl`, such as in large binaries or link-time-optimized builds.

Key changes:
- In SelectionDAG lowering (`LowerCall`), detect `-mlong-calls` and emit:
    - `adrp + add` address calculation
    - `blr` indirect call instruction

This patch ensures that long-calls are emitted correctly for both GlobalAddress 
and ExternalSymbol call targets.

Tested:
- New codegen tests under `llvm/test/CodeGen/AArch64/aarch64-long-calls.ll`
- Verified `adrp + add + blr` output in `.s` for global and external functions

>From fcf661d89713e589af497b63366ca37db8aad9f9 Mon Sep 17 00:00:00 2001
From: dong jianqiang <dongjianqia...@huawei.com>
Date: Thu, 5 Jun 2025 22:46:26 +0800
Subject: [PATCH] [AArch64] Add support for -mlong-calls code generation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch implements backend support for -mlong-calls on AArch64 targets.
When enabled, calls to external functions are lowered to an indirect call via
an address computed using `adrp` and `add` rather than a direct `bl` 
instruction,
which is limited to a ±128MB PC-relative offset.

This is particularly useful when code and/or data exceeds the 26-bit immediate
range of `bl`, such as in large binaries or link-time-optimized builds.

Key changes:
- In SelectionDAG lowering (`LowerCall`), detect `-mlong-calls` and emit:
    - `adrp + add` address calculation
    - `blr` indirect call instruction

This patch ensures that long-calls are emitted correctly for both GlobalAddress
and ExternalSymbol call targets.

Tested:
- New codegen tests under `llvm/test/CodeGen/AArch64/aarch64-long-calls.ll`
- Verified `adrp + add + blr` output in `.s` for global and external functions
---
 clang/lib/Driver/ToolChains/Arch/AArch64.cpp  |  6 +++++
 llvm/lib/Target/AArch64/AArch64Features.td    |  4 +++
 .../Target/AArch64/AArch64ISelLowering.cpp    | 13 +++++++---
 .../CodeGen/AArch64/aarch64-long-calls.ll     | 26 +++++++++++++++++++
 4 files changed, 46 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/aarch64-long-calls.ll

diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp 
b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index eaae9f876e3ad..2463bcdae2f4f 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -466,6 +466,12 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
 
   if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
     Features.push_back("+no-bti-at-return-twice");
+
+  if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
+                               options::OPT_mno_long_calls)) {
+    if (A->getOption().matches(options::OPT_mlong_calls))
+      Features.push_back("+long-calls");
+  }
 }
 
 void aarch64::setPAuthABIInTriple(const Driver &D, const ArgList &Args,
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td 
b/llvm/lib/Target/AArch64/AArch64Features.td
index 469c76752c78c..5af6ed5f1ffa2 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -825,6 +825,10 @@ def FeatureDisableFastIncVL : 
SubtargetFeature<"disable-fast-inc-vl",
                                                "HasDisableFastIncVL", "true",
                                                "Do not prefer INC/DEC, ALL, { 
1, 2, 4 } over ADDVL">;
 
+def FeatureLongCalls : SubtargetFeature<"long-calls", "GenLongCalls", "true",
+                                        "Generate calls via indirect call "
+                                        "instructions">;
+
 
//===----------------------------------------------------------------------===//
 // Architectures.
 //
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp 
b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 9f51caef6d228..d6015ccf94afc 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -9286,8 +9286,12 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
       Callee = DAG.getTargetGlobalAddress(CalledGlobal, DL, PtrVT, 0, OpFlags);
       Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
     } else {
-      const GlobalValue *GV = G->getGlobal();
-      Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags);
+      if (Subtarget->genLongCalls())
+        Callee = getAddr(G, DAG, OpFlags);
+      else {
+        const GlobalValue *GV = G->getGlobal();
+        Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags);
+      }
     }
   } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
     bool UseGot = (getTargetMachine().getCodeModel() == CodeModel::Large &&
@@ -9298,7 +9302,10 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
       Callee = DAG.getTargetExternalSymbol(Sym, PtrVT, AArch64II::MO_GOT);
       Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
     } else {
-      Callee = DAG.getTargetExternalSymbol(Sym, PtrVT, 0);
+      if (Subtarget->genLongCalls())
+        Callee = getAddr(S, DAG, 0);
+      else
+        Callee = DAG.getTargetExternalSymbol(Sym, PtrVT, 0);
     }
   }
 
diff --git a/llvm/test/CodeGen/AArch64/aarch64-long-calls.ll 
b/llvm/test/CodeGen/AArch64/aarch64-long-calls.ll
new file mode 100644
index 0000000000000..cb41c3cf519e0
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-long-calls.ll
@@ -0,0 +1,26 @@
+; RUN: llc -O2 -mtriple=aarch64-linux-gnu -mcpu=generic -mattr=+long-calls < 
%s | FileCheck %s
+
+declare void @far_func()
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
+
+define void @test() {
+entry:
+  call void @far_func()
+  ret void
+}
+
+define void @test2(ptr %dst, i8 %val, i64 %len) {
+entry:
+  call void @llvm.memset.p0.i64(ptr %dst, i8 %val, i64 %len, i1 false)
+  ret void
+}
+
+; CHECK-LABEL: test:
+; CHECK: adrp {{x[0-9]+}}, far_func
+; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, :lo12:far_func
+; CHECK: blr {{x[0-9]+}}
+
+; CHECK-LABEL: test2:
+; CHECK: adrp {{x[0-9]+}}, memset
+; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, :lo12:memset
+; CHECK: blr {{x[0-9]+}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to