Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3933,9 +3933,13 @@ SelectionDAG &DAG) const { GlobalAddressSDNode *GN = cast(Op); const GlobalValue *GV = GN->getGlobal(); - const AArch64II::TOF TargetFlags = - (GV->hasDLLImportStorageClass() ? AArch64II::MO_DLLIMPORT - : AArch64II::MO_NO_FLAG); + AArch64II::TOF TargetFlags = AArch64II::MO_NO_FLAG; + if (GV->hasDLLImportStorageClass()) + TargetFlags = AArch64II::MO_DLLIMPORT; + else if (Subtarget->getTargetTriple().isWindowsGNUEnvironment() && + !GV->isDSOLocal() && GV->isDeclarationForLinker() && + isa(GV)) + TargetFlags = AArch64II::MO_COFFSTUB; unsigned char OpFlags = Subtarget->ClassifyGlobalReference(GV, getTargetMachine()); @@ -3959,7 +3963,7 @@ } EVT PtrVT = getPointerTy(DAG.getDataLayout()); SDLoc DL(GN); - if (GV->hasDLLImportStorageClass()) + if (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB)) Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result, MachinePointerInfo::getGOT(DAG.getMachineFunction())); return Result; Index: lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.cpp +++ lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1607,7 +1607,7 @@ if ((OpFlags & AArch64II::MO_GOT) != 0) { BuildMI(MBB, MI, DL, get(AArch64::LOADgot), Reg) - .addGlobalAddress(GV, 0, AArch64II::MO_GOT); + .addGlobalAddress(GV, 0, OpFlags); BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg) .addReg(Reg, RegState::Kill) .addImm(0) @@ -4842,6 +4842,7 @@ using namespace AArch64II; static const std::pair TargetFlags[] = { + {MO_COFFSTUB, "aarch64-coffstub"}, {MO_GOT, "aarch64-got"}, {MO_NC, "aarch64-nc"}, {MO_TLS, "aarch64-tls"}, {MO_DLLIMPORT, "aarch64-dllimport"}}; return makeArrayRef(TargetFlags); Index: lib/Target/AArch64/AArch64MCInstLower.cpp =================================================================== --- lib/Target/AArch64/AArch64MCInstLower.cpp +++ lib/Target/AArch64/AArch64MCInstLower.cpp @@ -18,6 +18,7 @@ #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/IR/Mangler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" @@ -44,16 +45,32 @@ assert(TheTriple.isOSWindows() && "Windows is the only supported COFF target"); - bool IsIndirect = (TargetFlags & AArch64II::MO_DLLIMPORT); + bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB)); if (!IsIndirect) return Printer.getSymbol(GV); SmallString<128> Name; - Name = "__imp_"; + if (TargetFlags & AArch64II::MO_DLLIMPORT) + Name = "__imp_"; + else if (TargetFlags & AArch64II::MO_COFFSTUB) + Name = ".refptr."; Printer.TM.getNameWithPrefix(Name, GV, Printer.getObjFileLowering().getMangler()); - return Ctx.getOrCreateSymbol(Name); + MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name); + + if (TargetFlags & AArch64II::MO_COFFSTUB) { + MachineModuleInfoCOFF &MMICOFF = + Printer.MMI->getObjFileInfo(); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMICOFF.getGVStubEntry(MCSym); + + if (!StubSym.getPointer()) + StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), + !GV->hasInternalLinkage()); + } + + return MCSym; } MCSymbol * Index: lib/Target/AArch64/AArch64Subtarget.cpp =================================================================== --- lib/Target/AArch64/AArch64Subtarget.cpp +++ lib/Target/AArch64/AArch64Subtarget.cpp @@ -196,8 +196,13 @@ if (TM.getCodeModel() == CodeModel::Large && isTargetMachO()) return AArch64II::MO_GOT; - unsigned Flags = GV->hasDLLImportStorageClass() ? AArch64II::MO_DLLIMPORT - : AArch64II::MO_NO_FLAG; + unsigned Flags = AArch64II::MO_NO_FLAG; + if (GV->hasDLLImportStorageClass()) + Flags = AArch64II::MO_DLLIMPORT; + else if (getTargetTriple().isWindowsGNUEnvironment() && + !GV->isDSOLocal() && GV->isDeclarationForLinker() && + isa(GV)) + Flags = AArch64II::MO_COFFSTUB | AArch64II::MO_GOT; if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) return AArch64II::MO_GOT | Flags; Index: lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -507,7 +507,7 @@ MO_NO_FLAG, - MO_FRAGMENT = 0xf, + MO_FRAGMENT = 0x7, /// MO_PAGE - A symbol operand with this flag represents the pc-relative /// offset of the 4K page containing the symbol. This is used with the @@ -540,6 +540,11 @@ /// by-12-bits instruction. MO_HI12 = 7, + /// MO_COFFSTUB - On a symbol operand "FOO", this indicates that the + /// reference is actually to the ".refptrp.FOO" symbol. This is used for + /// stub symbols on windows. + MO_COFFSTUB = 0x8, + /// MO_GOT - This flag indicates that a symbol operand represents the /// address of the GOT entry for the symbol, rather than the address of /// the symbol itself. Index: test/CodeGen/AArch64/mingw-refptr.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/mingw-refptr.ll @@ -0,0 +1,97 @@ +; RUN: llc < %s -mtriple=aarch64-w64-mingw32 | FileCheck %s + +@var = external local_unnamed_addr global i32, align 4 +@dsolocalvar = external dso_local local_unnamed_addr global i32, align 4 +@localvar = dso_local local_unnamed_addr global i32 0, align 4 +@localcommon = common dso_local local_unnamed_addr global i32 0, align 4 +@extvar = external dllimport local_unnamed_addr global i32, align 4 + +define dso_local i32 @getVar() { +; CHECK-LABEL: getVar: +; CHECK: adrp x8, .refptr.var +; CHECK: ldr x8, [x8, .refptr.var] +; CHECK: ldr w0, [x8] +; CHECK: ret +entry: + %0 = load i32, i32* @var, align 4 + ret i32 %0 +} + +define dso_local i32 @getDsoLocalVar() { +; CHECK-LABEL: getDsoLocalVar: +; CHECK: adrp x8, dsolocalvar +; CHECK: ldr w0, [x8, dsolocalvar] +; CHECK: ret +entry: + %0 = load i32, i32* @dsolocalvar, align 4 + ret i32 %0 +} + +define dso_local i32 @getLocalVar() { +; CHECK-LABEL: getLocalVar: +; CHECK: adrp x8, localvar +; CHECK: ldr w0, [x8, localvar] +; CHECK: ret +entry: + %0 = load i32, i32* @localvar, align 4 + ret i32 %0 +} + +define dso_local i32 @getLocalCommon() { +; CHECK-LABEL: getLocalCommon: +; CHECK: adrp x8, localcommon +; CHECK: ldr w0, [x8, localcommon] +; CHECK: ret +entry: + %0 = load i32, i32* @localcommon, align 4 + ret i32 %0 +} + +define dso_local i32 @getExtVar() { +; CHECK-LABEL: getExtVar: +; CHECK: adrp x8, __imp_extvar +; CHECK: ldr x8, [x8, __imp_extvar] +; CHECK: ldr w0, [x8] +; CHECK: ret +entry: + %0 = load i32, i32* @extvar, align 4 + ret i32 %0 +} + +define dso_local void @callFunc() { +; CHECK-LABEL: callFunc: +; CHECK: b otherFunc +entry: + tail call void @otherFunc() + ret void +} + +declare dso_local void @otherFunc() + +define dso_local void @sspFunc() #0 { +; CHECK-LABEL: sspFunc: +; CHECK: adrp x8, .refptr.__stack_chk_guard +; CHECK: ldr x8, [x8, .refptr.__stack_chk_guard] +; CHECK: ldr x8, [x8] +entry: + %c = alloca i8, align 1 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %c) + call void @ptrUser(i8* nonnull %c) + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %c) + ret void +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare dso_local void @ptrUser(i8*) local_unnamed_addr #2 +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +attributes #0 = { sspstrong } + +; CHECK: .section .rdata$.refptr.__stack_chk_guard,"dr",discard,.refptr.__stack_chk_guard +; CHECK: .globl .refptr.__stack_chk_guard +; CHECK: .refptr.__stack_chk_guard: +; CHECK: .xword __stack_chk_guard +; CHECK: .section .rdata$.refptr.var,"dr",discard,.refptr.var +; CHECK: .globl .refptr.var +; CHECK: .refptr.var: +; CHECK: .xword var