-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Mips] Handle declspec(dllimport) on mipsel-windows-* triples #120912
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
Conversation
On Windows, imported symbols must be searched with '__imp_' prefix. Support imported global variables and imported functions.
@llvm/pr-subscribers-mc Author: Hervé Poussineau (hpoussin) ChangesOn Windows, imported symbols must be searched with '_imp' prefix. Full diff: https://github.com/llvm/llvm-project/pull/120912.diff 7 Files Affected:
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index aa35e7db6bda444..b9a2af3341236a5 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 d5f38c414e703d2..469b7a566cea25c 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<GlobalAddressSDNode>(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<const MipsTargetObjectFile *>(
@@ -3501,7 +3509,14 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
}
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(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 e245c056de6491e..efd0acef961f616 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 <class NodeTy>
+ 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 <class NodeTy>
+ 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 b0642f3d1ff283a..e01d0d1e65cf7e9 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 c048ab29d5f9b2e..85cf45d4702ae81 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 000000000000000..385199892821e7d
--- /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 000000000000000..a4d189faefdbcbb
--- /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
+}
|
This is an extract of PR #107744 |
You can test this locally with the following command:git-clang-format --diff 0575815b70b486240ace728a33f756cea8fe58fa 3289d9c3b7191456abc642ddc148b643b38c4d02 --extensions h,cpp -- llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h llvm/lib/Target/Mips/MipsISelLowering.cpp llvm/lib/Target/Mips/MipsISelLowering.h llvm/lib/Target/Mips/MipsMCInstLower.cpp llvm/lib/Target/Mips/MipsSubtarget.h View the diff from clang-format here.diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index b9a2af3341..11852681be 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -27,118 +27,118 @@ namespace llvm {
///
namespace MipsII {
/// Target Operand Flag enum.
- enum TOF {
- //===------------------------------------------------------------------===//
- // Mips Specific MachineOperand flags.
-
- MO_NO_FLAG,
-
- /// MO_GOT - Represents the offset into the global offset table at which
- /// the address the relocation entry symbol resides during execution.
- MO_GOT,
-
- /// MO_GOT_CALL - Represents the offset into the global offset table at
- /// which the address of a call site relocation entry symbol resides
- /// during execution. This is different from the above since this flag
- /// can only be present in call instructions.
- MO_GOT_CALL,
-
- /// MO_GPREL - Represents the offset from the current gp value to be used
- /// for the relocatable object file being produced.
- MO_GPREL,
-
- /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
- /// address.
- MO_ABS_HI,
- MO_ABS_LO,
-
- /// MO_TLSGD - Represents the offset into the global offset table at which
- // the module ID and TSL block offset reside during execution (General
- // Dynamic TLS).
- MO_TLSGD,
-
- /// MO_TLSLDM - Represents the offset into the global offset table at which
- // the module ID and TSL block offset reside during execution (Local
- // Dynamic TLS).
- MO_TLSLDM,
- MO_DTPREL_HI,
- MO_DTPREL_LO,
-
- /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
- // Exec TLS).
- MO_GOTTPREL,
-
- /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
- // the thread pointer (Local Exec TLS).
- MO_TPREL_HI,
- MO_TPREL_LO,
-
- // N32/64 Flags.
- MO_GPOFF_HI,
- MO_GPOFF_LO,
- MO_GOT_DISP,
- MO_GOT_PAGE,
- MO_GOT_OFST,
-
- /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a
- /// 64-bit symbol address.
- MO_HIGHER,
- MO_HIGHEST,
-
- /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs.
- MO_GOT_HI16,
- MO_GOT_LO16,
- MO_CALL_HI16,
- MO_CALL_LO16,
-
- /// Helper operand used to generate R_MIPS_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 {
- //===------------------------------------------------------------------===//
- // Instruction encodings. These are the standard/most common forms for
- // Mips instructions.
- //
-
- // Pseudo - This represents an instruction that is a pseudo instruction
- // or one that has not been implemented yet. It is illegal to code generate
- // it, but tolerated for intermediate implementation stages.
- Pseudo = 0,
-
- /// FrmR - This form is for instructions of the format R.
- FrmR = 1,
- /// FrmI - This form is for instructions of the format I.
- FrmI = 2,
- /// FrmJ - This form is for instructions of the format J.
- FrmJ = 3,
- /// FrmFR - This form is for instructions of the format FR.
- FrmFR = 4,
- /// FrmFI - This form is for instructions of the format FI.
- FrmFI = 5,
- /// FrmOther - This form is for instructions that have no specific format.
- FrmOther = 6,
-
- FormMask = 15,
- /// IsCTI - Instruction is a Control Transfer Instruction.
- IsCTI = 1 << 4,
- /// HasForbiddenSlot - Instruction has a forbidden slot.
- HasForbiddenSlot = 1 << 5,
- /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
- HasFCCRegOperand = 1 << 6
-
- };
-
- enum OperandType : unsigned {
- OPERAND_FIRST_MIPS_MEM_IMM = MCOI::OPERAND_FIRST_TARGET,
- OPERAND_MEM_SIMM9 = OPERAND_FIRST_MIPS_MEM_IMM,
- OPERAND_LAST_MIPS_MEM_IMM = OPERAND_MEM_SIMM9
- };
+enum TOF {
+ //===------------------------------------------------------------------===//
+ // Mips Specific MachineOperand flags.
+
+ MO_NO_FLAG,
+
+ /// MO_GOT - Represents the offset into the global offset table at which
+ /// the address the relocation entry symbol resides during execution.
+ MO_GOT,
+
+ /// MO_GOT_CALL - Represents the offset into the global offset table at
+ /// which the address of a call site relocation entry symbol resides
+ /// during execution. This is different from the above since this flag
+ /// can only be present in call instructions.
+ MO_GOT_CALL,
+
+ /// MO_GPREL - Represents the offset from the current gp value to be used
+ /// for the relocatable object file being produced.
+ MO_GPREL,
+
+ /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
+ /// address.
+ MO_ABS_HI,
+ MO_ABS_LO,
+
+ /// MO_TLSGD - Represents the offset into the global offset table at which
+ // the module ID and TSL block offset reside during execution (General
+ // Dynamic TLS).
+ MO_TLSGD,
+
+ /// MO_TLSLDM - Represents the offset into the global offset table at which
+ // the module ID and TSL block offset reside during execution (Local
+ // Dynamic TLS).
+ MO_TLSLDM,
+ MO_DTPREL_HI,
+ MO_DTPREL_LO,
+
+ /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
+ // Exec TLS).
+ MO_GOTTPREL,
+
+ /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
+ // the thread pointer (Local Exec TLS).
+ MO_TPREL_HI,
+ MO_TPREL_LO,
+
+ // N32/64 Flags.
+ MO_GPOFF_HI,
+ MO_GPOFF_LO,
+ MO_GOT_DISP,
+ MO_GOT_PAGE,
+ MO_GOT_OFST,
+
+ /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a
+ /// 64-bit symbol address.
+ MO_HIGHER,
+ MO_HIGHEST,
+
+ /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs.
+ MO_GOT_HI16,
+ MO_GOT_LO16,
+ MO_CALL_HI16,
+ MO_CALL_LO16,
+
+ /// Helper operand used to generate R_MIPS_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 {
+ //===------------------------------------------------------------------===//
+ // Instruction encodings. These are the standard/most common forms for
+ // Mips instructions.
+ //
+
+ // Pseudo - This represents an instruction that is a pseudo instruction
+ // or one that has not been implemented yet. It is illegal to code generate
+ // it, but tolerated for intermediate implementation stages.
+ Pseudo = 0,
+
+ /// FrmR - This form is for instructions of the format R.
+ FrmR = 1,
+ /// FrmI - This form is for instructions of the format I.
+ FrmI = 2,
+ /// FrmJ - This form is for instructions of the format J.
+ FrmJ = 3,
+ /// FrmFR - This form is for instructions of the format FR.
+ FrmFR = 4,
+ /// FrmFI - This form is for instructions of the format FI.
+ FrmFI = 5,
+ /// FrmOther - This form is for instructions that have no specific format.
+ FrmOther = 6,
+
+ FormMask = 15,
+ /// IsCTI - Instruction is a Control Transfer Instruction.
+ IsCTI = 1 << 4,
+ /// HasForbiddenSlot - Instruction has a forbidden slot.
+ HasForbiddenSlot = 1 << 5,
+ /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
+ HasFCCRegOperand = 1 << 6
+
+};
+
+enum OperandType : unsigned {
+ OPERAND_FIRST_MIPS_MEM_IMM = MCOI::OPERAND_FIRST_TARGET,
+ OPERAND_MEM_SIMM9 = OPERAND_FIRST_MIPS_MEM_IMM,
+ OPERAND_LAST_MIPS_MEM_IMM = OPERAND_MEM_SIMM9
+};
}
inline static MCRegister getMSARegFromFReg(MCRegister Reg) {
|
I didn't follow clang-format, because it seems unnecessary to reindent the whole However, if it is required, I can do it. |
Ping |
1 similar comment
Ping |
Ping |
On Windows, imported symbols must be searched with '_imp' prefix.
Support imported global variables and imported functions.