diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h index aa35e7db6bda4..b9a2af3341236 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -92,7 +92,12 @@ namespace MipsII { MO_CALL_LO16, /// Helper operand used to generate R_MIPS_JALR - MO_JALR + MO_JALR, + + /// MO_DLLIMPORT - On a symbol operand "FOO", this indicates that the + /// reference is actually to the "__imp_FOO" symbol. This is used for + /// dllimport linkage on windows. + MO_DLLIMPORT = 0x20, }; enum { diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index d5f38c414e703..469b7a566cea2 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -2146,6 +2146,14 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, GlobalAddressSDNode *N = cast(Op); const GlobalValue *GV = N->getGlobal(); + if (GV->hasDLLImportStorageClass()) { + assert(Subtarget.isTargetWindows() && + "Windows is the only supported COFF target"); + return getDllimportVariable( + N, SDLoc(N), Ty, DAG, DAG.getEntryNode(), + MachinePointerInfo::getGOT(DAG.getMachineFunction())); + } + if (!isPositionIndependent()) { const MipsTargetObjectFile *TLOF = static_cast( @@ -3501,7 +3509,14 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, } if (GlobalAddressSDNode *G = dyn_cast(Callee)) { - if (IsPIC) { + if (Subtarget.isTargetCOFF() && + G->getGlobal()->hasDLLImportStorageClass()) { + assert(Subtarget.isTargetWindows() && + "Windows is the only supported COFF target"); + auto PtrInfo = MachinePointerInfo(); + Callee = DAG.getLoad(Ty, DL, Chain, + getDllimportSymbol(G, SDLoc(G), Ty, DAG), PtrInfo); + } else if (IsPIC) { const GlobalValue *Val = G->getGlobal(); InternalLinkage = Val->hasInternalLinkage(); diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h index e245c056de649..efd0acef961f6 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.h +++ b/llvm/lib/Target/Mips/MipsISelLowering.h @@ -487,6 +487,33 @@ class TargetRegisterClass; DAG.getNode(MipsISD::GPRel, DL, DAG.getVTList(Ty), GPRel)); } + // This method creates the following nodes, which are necessary for + // loading a dllimported symbol: + // + // (lw (add (shl(%high(sym), 16), %low(sym))) + template + SDValue getDllimportSymbol(NodeTy *N, const SDLoc &DL, EVT Ty, + SelectionDAG &DAG) const { + SDValue Hi = + getTargetNode(N, Ty, DAG, MipsII::MO_ABS_HI | MipsII::MO_DLLIMPORT); + SDValue Lo = + getTargetNode(N, Ty, DAG, MipsII::MO_ABS_LO | MipsII::MO_DLLIMPORT); + return DAG.getNode(ISD::ADD, DL, Ty, DAG.getNode(MipsISD::Lo, DL, Ty, Lo), + DAG.getNode(MipsISD::Hi, DL, Ty, Hi)); + } + + // This method creates the following nodes, which are necessary for + // loading a dllimported global variable: + // + // (lw (lw (add (shl(%high(sym), 16), %low(sym)))) + template + SDValue getDllimportVariable(NodeTy *N, const SDLoc &DL, EVT Ty, + SelectionDAG &DAG, SDValue Chain, + const MachinePointerInfo &PtrInfo) const { + return DAG.getLoad(Ty, DL, Chain, getDllimportSymbol(N, DL, Ty, DAG), + PtrInfo); + } + /// This function fills Ops, which is the list of operands that will later /// be used when a function call node is created. It also generates /// copyToReg nodes to set up argument registers. diff --git a/llvm/lib/Target/Mips/MipsMCInstLower.cpp b/llvm/lib/Target/Mips/MipsMCInstLower.cpp index b0642f3d1ff28..e01d0d1e65cf7 100644 --- a/llvm/lib/Target/Mips/MipsMCInstLower.cpp +++ b/llvm/lib/Target/Mips/MipsMCInstLower.cpp @@ -18,6 +18,7 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/Support/ErrorHandling.h" @@ -38,8 +39,16 @@ MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, MipsMCExpr::MipsExprKind TargetKind = MipsMCExpr::MEK_None; bool IsGpOff = false; const MCSymbol *Symbol; + SmallString<128> Name; + unsigned TargetFlags = MO.getTargetFlags(); - switch(MO.getTargetFlags()) { + if (TargetFlags & MipsII::MO_DLLIMPORT) { + // Handle dllimport linkage + Name += "__imp_"; + TargetFlags &= ~MipsII::MO_DLLIMPORT; + } + + switch (TargetFlags) { default: llvm_unreachable("Invalid target flag!"); case MipsII::MO_NO_FLAG: @@ -125,7 +134,8 @@ MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, break; case MachineOperand::MO_GlobalAddress: - Symbol = AsmPrinter.getSymbol(MO.getGlobal()); + AsmPrinter.getNameWithPrefix(Name, MO.getGlobal()); + Symbol = Ctx->getOrCreateSymbol(Name); Offset += MO.getOffset(); break; diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h b/llvm/lib/Target/Mips/MipsSubtarget.h index c048ab29d5f9b..85cf45d4702ae 100644 --- a/llvm/lib/Target/Mips/MipsSubtarget.h +++ b/llvm/lib/Target/Mips/MipsSubtarget.h @@ -301,6 +301,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo { return (HasSym32 && isABI_N64()) || isABI_N32() || isABI_O32(); } bool isSingleFloat() const { return IsSingleFloat; } + bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); } bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } bool hasVFPU() const { return HasVFPU; } bool inMips16Mode() const { return InMips16Mode; } @@ -356,6 +357,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo { bool os16() const { return Os16; } bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); } + bool isTargetWindows() const { return TargetTriple.isOSWindows(); } bool isXRaySupported() const override { return true; } diff --git a/llvm/test/CodeGen/Mips/dllimport.ll b/llvm/test/CodeGen/Mips/dllimport.ll new file mode 100644 index 0000000000000..385199892821e --- /dev/null +++ b/llvm/test/CodeGen/Mips/dllimport.ll @@ -0,0 +1,55 @@ +; RUN: llc -mtriple mipsel-windows < %s | FileCheck %s + +@Var1 = external dllimport global i32 +@Var2 = available_externally dllimport unnamed_addr constant i32 1 + +declare dllimport void @fun() + +define available_externally dllimport void @inline1() { + ret void +} + +define available_externally dllimport void @inline2() alwaysinline { + ret void +} + +declare void @dummy(...) + +define void @use() nounwind { +; CHECK: lui $1, %hi(__imp_fun) +; CHECK: addiu $1, $1, %lo(__imp_fun) +; CHECK: lw $25, 0($1) +; CHECK: jalr $25 + call void @fun() + +; CHECK: lui $1, %hi(__imp_inline1) +; CHECK: addiu $1, $1, %lo(__imp_inline1) +; CHECK: lw $25, 0($1) +; CHECK: jalr $25 + call void @inline1() + +; CHECK: lui $1, %hi(__imp_inline2) +; CHECK: addiu $1, $1, %lo(__imp_inline2) +; CHECK: lw $25, 0($1) +; CHECK: jalr $25 + call void @inline2() + +; CHECK: lui $1, %hi(__imp_Var2) +; CHECK: addiu $1, $1, %lo(__imp_Var2) +; CHECK: lw $1, 0($1) +; CHECK: lw $5, 0($1) +; CHECK: lui $1, %hi(__imp_Var1) +; CHECK: addiu $1, $1, %lo(__imp_Var1) +; CHECK: lw $1, 0($1) +; CHECK: lw $4, 0($1) + %1 = load i32, ptr @Var1 + %2 = load i32, ptr @Var2 + call void(...) @dummy(i32 %1, i32 %2) + + ret void +} + +; CHECK: fp: +; CHECK-NEXT: .long fun +@fp = constant ptr @fun + diff --git a/llvm/test/MC/Mips/coff-relocs-dllimport.ll b/llvm/test/MC/Mips/coff-relocs-dllimport.ll new file mode 100644 index 0000000000000..a4d189faefdbc --- /dev/null +++ b/llvm/test/MC/Mips/coff-relocs-dllimport.ll @@ -0,0 +1,11 @@ +; RUN: llc -mtriple mipsel-windows -filetype obj < %s | llvm-objdump --reloc - | FileCheck %s + +declare dllimport void @fun() + +define void @use() nounwind { +; CHECK: 00000008 IMAGE_REL_MIPS_REFHI __imp_fun +; CHECK: 0000000c IMAGE_REL_MIPS_REFLO __imp_fun + call void() @fun() + + ret void +}