diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index a3e2edf14531..aab7448eb0af 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3951,7 +3951,7 @@ SDValue AArch64TargetLowering::LowerGlobalAddress(SDValue Op, } EVT PtrVT = getPointerTy(DAG.getDataLayout()); SDLoc DL(GN); - if (GV->hasDLLImportStorageClass()) + if (OpFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB)) Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result, MachinePointerInfo::getGOT(DAG.getMachineFunction())); return Result; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index 72d80ba61b1d..1152d3799f13 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1607,7 +1607,7 @@ bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 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 @@ AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const { using namespace AArch64II; static const std::pair<unsigned, const char *> TargetFlags[] = { + {MO_COFFSTUB, "aarch64-coffstub"}, {MO_GOT, "aarch64-got"}, {MO_NC, "aarch64-nc"}, {MO_TLS, "aarch64-tls"}, {MO_DLLIMPORT, "aarch64-dllimport"}}; return makeArrayRef(TargetFlags); diff --git a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp index 6c0263585933..6e1824f632ee 100644 --- a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp +++ b/llvm/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,31 @@ AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { 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<MachineModuleInfoCOFF>(); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMICOFF.getGVStubEntry(MCSym); + + if (!StubSym.getPointer()) + StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true); + } + + return MCSym; } MCSymbol * diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp index be655e3482c6..78eb3470e641 100644 --- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -196,8 +196,13 @@ AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV, 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<GlobalVariable>(GV)) + Flags = AArch64II::MO_COFFSTUB | AArch64II::MO_GOT; if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) return AArch64II::MO_GOT | Flags; diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h index 2874c4ab42ea..461a7dcf0904 100644 --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -507,7 +507,7 @@ namespace AArch64II { 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 @@ namespace AArch64II { /// 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. diff --git a/llvm/test/CodeGen/AArch64/mingw-refptr.ll b/llvm/test/CodeGen/AArch64/mingw-refptr.ll new file mode 100644 index 000000000000..3a76d8586270 --- /dev/null +++ b/llvm/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