diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index fb72bab03e750..242bec2735b6f 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2793,8 +2793,6 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, auto PtrVt = getPointerTy(DAG.getDataLayout()); if (Subtarget->genLongCalls()) { - assert((!isPositionIndependent() || Subtarget->isTargetWindows()) && - "long-calls codegen is not position independent!"); // Handle a global address or an external symbol. If it's not one of // those, the target's already in a register, so we don't need to do // anything extra. @@ -2804,6 +2802,14 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, ++NumMovwMovt; Callee = DAG.getNode(ARMISD::Wrapper, dl, PtrVt, DAG.getTargetGlobalAddress(GVal, dl, PtrVt)); + } else if (isPositionIndependent() && !Subtarget->isTargetWindows()){ + SDValue G = DAG.getTargetGlobalAddress( + GVal, dl, PtrVt, 0, GVal->isDSOLocal() ? 0 : ARMII::MO_GOT); + Callee = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVt, G); + if (!GVal->isDSOLocal()) + Callee = + DAG.getLoad(PtrVt, dl, DAG.getEntryNode(), Callee, + MachinePointerInfo::getGOT(DAG.getMachineFunction())); } else { // Create a constant pool entry for the callee address unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); @@ -2837,6 +2843,10 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Callee = DAG.getLoad( PtrVt, dl, DAG.getEntryNode(), Addr, MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); + if (isPositionIndependent() && !Subtarget->isTargetWindows()) { + SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, dl, MVT::i32); + Callee = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVt, Callee, PICLabel); + } } } } else if (isa(Callee)) { diff --git a/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll b/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll index 112a840ba92ee..7d4ea72ebd3cc 100644 --- a/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll +++ b/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll @@ -4,6 +4,9 @@ ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -O0 | FileCheck -check-prefix=NO-OPTION %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -O0 -mattr=+long-calls | FileCheck -check-prefix=LONGCALL %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -O0 -mattr=-long-calls | FileCheck -check-prefix=NO-LONGCALL %s +; RUN: llc -mtriple=arm-linux-gnueabi -mcpu=cortex-a8 -relocation-model=pic %s -o - -O0 -mattr=+long-calls | FileCheck -check-prefix=PIC-O0-LONGCALL %s +; RUN: llc -mtriple=arm-linux-gnueabi -mcpu=cortex-a8 -relocation-model=pic %s -o - -O1 -mattr=+long-calls | FileCheck -check-prefix=PIC-LONGCALL %s +; RUN: llc -mtriple=arm-linux-gnueabi -mcpu=cortex-a8 -relocation-model=pic %s -o - -O2 -mattr=+long-calls | FileCheck -check-prefix=PIC-LONGCALL %s ; NO-OPTION-LABEL: {{_?}}caller0 ; NO-OPTION: ldr [[R0:r[0-9]+]], [[L0:.*]] @@ -46,4 +49,62 @@ entry: declare void @callee0() +; PIC-O0-LONGCALL-LABEL: global_func: +; PIC-O0-LONGCALL: bx lr + +; PIC-LONGCALL-LABEL: global_func: +; PIC-LONGCALL: bx lr +define void @global_func() { +entry: + ret void +} + +; PIC-O0-LONGCALL-LABEL: test_global: +; PIC-O0-LONGCALL: push {r11, lr} +; PIC-O0-LONGCALL: ldr r0, [[GOT_LABEL:.*]] +; PIC-O0-LONGCALL: ldr r0, [pc, r0] +; PIC-O0-LONGCALL: blx r0 +; PIC-O0-LONGCALL: pop {r11, pc} +; PIC-O0-LONGCALL: [[GOT_LABEL]]: +; PIC-O0-LONGCALL: .long global_func(GOT_PREL) + +; PIC-LONGCALL-LABEL: test_global: +; PIC-LONGCALL: push {r11, lr} +; PIC-LONGCALL: ldr r0, [[GOT_LABEL:.*]] +; PIC-LONGCALL: ldr r0, [pc, r0] +; PIC-LONGCALL: blx r0 +; PIC-LONGCALL: pop {r11, pc} +; PIC-LONGCALL: [[GOT_LABEL]]: +; PIC-LONGCALL: .long global_func(GOT_PREL) +define void @test_global() { +entry: + call void @global_func() + ret void +} + +; PIC-O0-LONGCALL-LABEL: test_memset: +; PIC-O0-LONGCALL: push {r11, lr} +; PIC-O0-LONGCALL: ldr r3, [[GOT_LABEL:.*]] +; PIC-O0-LONGCALL: ldr r3, [pc, r3] +; PIC-O0-LONGCALL: blx r3 +; PIC-O0-LONGCALL: pop {r11, pc} +; PIC-O0-LONGCALL: [[GOT_LABEL]]: +; PIC-O0-LONGCALL: .long memset(GOT_PREL) + +; PIC-LONGCALL-LABEL: test_memset: +; PIC-LONGCALL: push {r11, lr} +; PIC-LONGCALL: ldr r3, [[MEMSET_LABEL:.*]] +; PIC-LONGCALL: add r3, pc, r3 +; PIC-LONGCALL: blx r3 +; PIC-LONGCALL: pop {r11, pc} +; PIC-LONGCALL: [[MEMSET_LABEL]]: +; PIC-LONGCALL: .long memset +declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) + +define void @test_memset(ptr %dst, i8 %val, i32 %len) { +entry: + call void @llvm.memset.p0.i32(ptr %dst, i8 %val, i32 %len, i1 false) + ret void +} + attributes #0 = { "target-features"="+long-calls" }