Skip to content

[AArch64] Add support for -mlong-calls code generation #142982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AArch64/AArch64Features.td
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down
13 changes: 10 additions & 3 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand All @@ -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);
}
}

Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,17 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
DstOp(getLLTForType(*F.getType(), DL)).addDefToMIB(MRI, MIB);
MIB.addExternalSymbol(Info.Callee.getSymbolName(), AArch64II::MO_GOT);
Info.Callee = MachineOperand::CreateReg(MIB.getReg(0), false);
} else if (Subtarget.genLongCalls()) {
// If -mlong-calls are enabled, materialize the symbol/global with MO_PAGE
// to allow ADRP+LDR relocation sequence for calls beyond 128MB range.
auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_GLOBAL_VALUE);
DstOp(getLLTForType(*F.getType(), DL)).addDefToMIB(MRI, MIB);
if (Info.Callee.isGlobal()) {
const GlobalValue *GV = Info.Callee.getGlobal();
MIB.addGlobalAddress(GV, 0, AArch64II::MO_PAGE);
} else if (Info.Callee.isSymbol())
MIB.addExternalSymbol(Info.Callee.getSymbolName(), AArch64II::MO_PAGE);
Info.Callee = MachineOperand::CreateReg(MIB.getReg(0), false);
}
Opc = getCallOpcode(MF, Info.Callee.isReg(), false, Info.PAI, MRI);
}
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,14 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
"Expected small code model");
auto Op1 = BaseMI->getOperand(1);
auto Op2 = I.getOperand(2);
if (Subtarget->genLongCalls() && Op1.isSymbol()) {
auto MovAddr =
MIB.buildInstr(AArch64::MOVaddr, {I.getOperand(0)}, {})
.addExternalSymbol(Op1.getSymbolName(), Op1.getTargetFlags())
.addExternalSymbol(Op2.getSymbolName(), Op2.getTargetFlags());
I.eraseFromParent();
return constrainSelectedInstRegOperands(*MovAddr, TII, TRI, RBI);
}
auto MovAddr = MIB.buildInstr(AArch64::MOVaddr, {I.getOperand(0)}, {})
.addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
Op1.getTargetFlags())
Expand Down
38 changes: 34 additions & 4 deletions llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1571,15 +1571,21 @@ bool AArch64LegalizerInfo::legalizeSmallCMGlobalValue(
// By splitting this here, we can optimize accesses in the small code model by
// folding in the G_ADD_LOW into the load/store offset.
auto &GlobalOp = MI.getOperand(1);
// Don't modify an intrinsic call.
if (GlobalOp.isSymbol())
return true;
if (GlobalOp.isSymbol()) {
// For symbol operands, use long call expansion if required.
return ST->genLongCalls()
? legalizeSmallCMSymbol(MI, MRI, MIRBuilder, Observer)
: true;
}
const auto* GV = GlobalOp.getGlobal();
if (GV->isThreadLocal())
return true; // Don't want to modify TLS vars.

auto &TM = ST->getTargetLowering()->getTargetMachine();
unsigned OpFlags = ST->ClassifyGlobalReference(GV, TM);
unsigned OpFlags = 0;

if (!ST->genLongCalls())
OpFlags = ST->ClassifyGlobalReference(GV, TM);

if (OpFlags & AArch64II::MO_GOT)
return true;
Expand Down Expand Up @@ -1621,6 +1627,30 @@ bool AArch64LegalizerInfo::legalizeSmallCMGlobalValue(
return true;
}

bool AArch64LegalizerInfo::legalizeSmallCMSymbol(
MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &MIRBuilder,
GISelChangeObserver &Observer) const {
assert(MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
// We do this custom legalization to convert G_GLOBAL_VALUE into target ADRP +
// G_ADD_LOW instructions.
// By splitting this here, we can optimize accesses in the small code model by
// folding in the G_ADD_LOW into the load/store offset.
auto &SymbolOp = MI.getOperand(1);

Register DstReg = MI.getOperand(0).getReg();
auto ADRP =
MIRBuilder.buildInstr(AArch64::ADRP, {LLT::pointer(0, 64)}, {})
.addExternalSymbol(SymbolOp.getSymbolName(), AArch64II::MO_PAGE);
// Set the regclass on the dest reg too.
MRI.setRegClass(ADRP.getReg(0), &AArch64::GPR64RegClass);

MIRBuilder.buildInstr(AArch64::G_ADD_LOW, {DstReg}, {ADRP})
.addExternalSymbol(SymbolOp.getSymbolName(),
AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
MI.eraseFromParent();
return true;
}

bool AArch64LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
MachineInstr &MI) const {
MachineIRBuilder &MIB = Helper.MIRBuilder;
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class AArch64LegalizerInfo : public LegalizerInfo {
bool legalizeShlAshrLshr(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &MIRBuilder,
GISelChangeObserver &Observer) const;

bool legalizeSmallCMSymbol(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &MIRBuilder,
GISelChangeObserver &Observer) const;
bool legalizeSmallCMGlobalValue(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &MIRBuilder,
GISelChangeObserver &Observer) const;
Expand Down
27 changes: 27 additions & 0 deletions llvm/test/CodeGen/AArch64/aarch64-long-calls.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; RUN: llc -O2 -mtriple=aarch64-linux-gnu -mcpu=generic -mattr=+long-calls < %s | FileCheck %s
; RUN: llc -O0 -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]+}}
Loading