[AArch64] [Windows] Use COFF stubs for calls to extern_weak functions

As the extern_weak target might be missing, resolving to the absolute
address zero, we can't use the normal direct PC-relative branch
instructions (as that would result in relocations out of range).

Improve the classifyGlobalFunctionReference method to set
MO_DLLIMPORT/MO_COFFSTUB, and simplify the existing code in
AArch64TargetLowering::LowerCall to use the return value from
classifyGlobalFunctionReference for these cases.

Add code in both AArch64FastISel and GlobalISel/IRTranslator to
bail out for function calls to extern weak functions on windows,
to let SelectionDAG handle them.

This matches what was done for X86 in 6bf108d77a.

Differential Revision: https://reviews.llvm.org/D71721
This commit is contained in:
Martin Storsjö 2019-12-19 14:00:44 +02:00
parent b774aa1011
commit 5a751e747d
7 changed files with 60 additions and 25 deletions

View File

@ -1593,7 +1593,9 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
const Function *F = CI.getCalledFunction();
// FIXME: support Windows dllimport function calls.
if (F && F->hasDLLImportStorageClass())
if (F && (F->hasDLLImportStorageClass() ||
(MF->getTarget().getTargetTriple().isOSWindows() &&
F->hasExternalWeakLinkage())))
return false;
// FIXME: support control flow guard targets.

View File

@ -3253,6 +3253,13 @@ bool AArch64FastISel::fastLowerCall(CallLoweringInfo &CLI) {
if (Callee && !computeCallAddress(Callee, Addr))
return false;
// The weak function target may be zero; in that case we must use indirect
// addressing via a stub on windows as it may be out of range for a
// PC-relative jump.
if (Subtarget->isTargetWindows() && Addr.getGlobalValue() &&
Addr.getGlobalValue()->hasExternalWeakLinkage())
return false;
// Handle the arguments now that we've gotten them.
unsigned NumBytes;
if (!processCallArgs(CLI, OutVTs, NumBytes))

View File

@ -4153,14 +4153,11 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
// node so that legalize doesn't hack it.
if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
auto GV = G->getGlobal();
if (Subtarget->classifyGlobalFunctionReference(GV, getTargetMachine()) ==
AArch64II::MO_GOT) {
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, AArch64II::MO_GOT);
unsigned OpFlags =
Subtarget->classifyGlobalFunctionReference(GV, getTargetMachine());
if (OpFlags & AArch64II::MO_GOT) {
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags);
Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
} else if (Subtarget->isTargetCOFF() && GV->hasDLLImportStorageClass()) {
assert(Subtarget->isTargetWindows() &&
"Windows is the only supported COFF target");
Callee = getGOT(G, DAG, AArch64II::MO_DLLIMPORT);
} else {
const GlobalValue *GV = G->getGlobal();
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, 0);

View File

@ -251,6 +251,10 @@ unsigned AArch64Subtarget::classifyGlobalFunctionReference(
!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return AArch64II::MO_GOT;
// Use ClassifyGlobalReference for setting MO_DLLIMPORT/MO_COFFSTUB.
if (getTargetTriple().isOSWindows())
return ClassifyGlobalReference(GV, TM);
return AArch64II::MO_NO_FLAG;
}

View File

@ -0,0 +1,15 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
; RUN: llc %s -stop-after=irtranslator -verify-machineinstrs -mtriple aarch64-apple-darwin -global-isel -o - 2>&1 | FileCheck %s --check-prefixes=DARWIN,COMMON
; Shouldn't tail call when the OS doesn't support it.
declare extern_weak void @extern_weak_fn()
define void @test_extern_weak() {
; DARWIN-LABEL: name: test_extern_weak
; DARWIN: bb.1 (%ir-block.0):
; DARWIN: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
; DARWIN: BL @extern_weak_fn, csr_aarch64_aapcs, implicit-def $lr, implicit $sp
; DARWIN: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
; DARWIN: RET_ReallyLR
tail call void @extern_weak_fn()
ret void
}

View File

@ -193,23 +193,6 @@ define void @test_inreg(i8* inreg %ptr) {
ret void
}
; Shouldn't tail call when the OS doesn't support it. Windows supports this,
; so we should be able to tail call there.
declare extern_weak void @extern_weak_fn()
define void @test_extern_weak() {
; DARWIN-LABEL: name: test_extern_weak
; DARWIN: bb.1 (%ir-block.0):
; DARWIN: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
; DARWIN: BL @extern_weak_fn, csr_aarch64_aapcs, implicit-def $lr, implicit $sp
; DARWIN: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
; DARWIN: RET_ReallyLR
; WINDOWS-LABEL: name: test_extern_weak
; WINDOWS: bb.1 (%ir-block.0):
; WINDOWS: TCRETURNdi @extern_weak_fn, 0, csr_aarch64_aapcs, implicit $sp
tail call void @extern_weak_fn()
ret void
}
declare fastcc void @fast_fn()
define void @test_mismatched_caller() {
; COMMON-LABEL: name: test_mismatched_caller

View File

@ -0,0 +1,27 @@
; RUN: llc -mtriple aarch64-windows -filetype asm -o - < %s | FileCheck %s
; RUN: llc -mtriple aarch64-windows -filetype asm -o - -fast-isel %s | FileCheck %s
; RUN: llc -mtriple aarch64-windows -filetype asm -o - -global-isel -global-isel-abort=0 %s | FileCheck %s
define void @func() {
; CHECK-LABEL: func:
; CHECK: str x30, [sp, #-16]!
; CHECK-NEXT: adrp x8, .refptr.weakfunc
; CHECK-NEXT: ldr x8, [x8, .refptr.weakfunc]
; CHECK-NEXT: cbz x8, .LBB0_2
; CHECK-NEXT: ; %bb.1:
; CHECK-NEXT: blr x8
; CHECK-NEXT: .LBB0_2:
; CHECK-NEXT: ldr x30, [sp], #16
; CHECK-NEXT: ret
br i1 icmp ne (void ()* @weakfunc, void ()* null), label %1, label %2
1:
call void @weakfunc()
br label %2
2:
ret void
}
declare extern_weak void @weakfunc()