diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index f0fab69b66b..4bfa5a8b5c6 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -1654,6 +1654,19 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, assert(Subtarget->isTargetMachO() && "WrapperPIC use on non-MachO?"); Callee = DAG.getNode(ARMISD::WrapperPIC, dl, getPointerTy(), DAG.getTargetGlobalAddress(GV, dl, getPointerTy())); + } else if (Subtarget->isTargetCOFF()) { + assert(Subtarget->isTargetWindows() && + "Windows is the only supported COFF target"); + unsigned TargetFlags = GV->hasDLLImportStorageClass() + ? ARMII::MO_DLLIMPORT + : ARMII::MO_NO_FLAG; + Callee = DAG.getTargetGlobalAddress(GV, dl, getPointerTy(), /*Offset=*/0, + TargetFlags); + if (GV->hasDLLImportStorageClass()) + Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), + DAG.getNode(ARMISD::Wrapper, dl, getPointerTy(), + Callee), MachinePointerInfo::getGOT(), + false, false, false, 0); } else { // On ELF targets for PIC code, direct calls should go through the PLT unsigned OpFlags = 0; @@ -2489,15 +2502,23 @@ SDValue ARMTargetLowering::LowerGlobalAddressWindows(SDValue Op, "Windows on ARM expects to use movw/movt"); const GlobalValue *GV = cast(Op)->getGlobal(); + const ARMII::TOF TargetFlags = + (GV->hasDLLImportStorageClass() ? ARMII::MO_DLLIMPORT : ARMII::MO_NO_FLAG); EVT PtrVT = getPointerTy(); + SDValue Result; SDLoc DL(Op); ++NumMovwMovt; // FIXME: Once remat is capable of dealing with instructions with register // operands, expand this into two nodes. - return DAG.getNode(ARMISD::Wrapper, DL, PtrVT, - DAG.getTargetGlobalAddress(GV, DL, PtrVT)); + Result = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, + DAG.getTargetGlobalAddress(GV, DL, PtrVT, /*Offset=*/0, + TargetFlags)); + if (GV->hasDLLImportStorageClass()) + Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result, + MachinePointerInfo::getGOT(), false, false, false, 0); + return Result; } SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, diff --git a/test/CodeGen/ARM/Windows/dllimport.ll b/test/CodeGen/ARM/Windows/dllimport.ll new file mode 100644 index 00000000000..bc737bd4182 --- /dev/null +++ b/test/CodeGen/ARM/Windows/dllimport.ll @@ -0,0 +1,61 @@ +; RUN: llc -mtriple thumbv7-windows -filetype asm -o - %s | FileCheck %s + +; ModuleID = 'dllimport.c' + +@var = external dllimport global i32 +@ext = external global i32 +declare dllimport arm_aapcs_vfpcc i32 @external() +declare arm_aapcs_vfpcc i32 @internal() + +define arm_aapcs_vfpcc i32 @get_var() { + %1 = load i32* @var, align 4 + ret i32 %1 +} + +; CHECK-LABEL: get_var +; CHECK: movw r0, :lower16:__imp_var +; CHECK: movt r0, :upper16:__imp_var +; CHECK: ldr r0, [r0] +; CHECK: ldr r0, [r0] +; CHECK: bx lr + +define arm_aapcs_vfpcc i32 @get_ext() { + %1 = load i32* @ext, align 4 + ret i32 %1 +} + +; CHECK-LABEL: get_ext +; CHECK: movw r0, :lower16:ext +; CHECK: movt r0, :upper16:ext +; CHECK: ldr r0, [r0] +; CHECK: bx lr + +define arm_aapcs_vfpcc i32* @get_var_pointer() { + ret i32* @var +} + +; CHECK-LABEL: get_var_pointer +; CHECK: movw r0, :lower16:__imp_var +; CHECK: movt r0, :upper16:__imp_var +; CHECK: ldr r0, [r0] +; CHECK: bx lr + +define arm_aapcs_vfpcc i32 @call_external() { + %call = tail call arm_aapcs_vfpcc i32 @external() + ret i32 %call +} + +; CHECK-LABEL: call_external +; CHECK: movw r0, :lower16:__imp_external +; CHECK: movt r0, :upper16:__imp_external +; CHECK: ldr r0, [r0] +; CHECK: bx r0 + +define arm_aapcs_vfpcc i32 @call_internal() { + %call = tail call arm_aapcs_vfpcc i32 @internal() + ret i32 %call +} + +; CHECK-LABEL: call_internal +; CHECK: b internal +