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