Index: lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- lib/Target/PowerPC/PPCISelLowering.cpp +++ lib/Target/PowerPC/PPCISelLowering.cpp @@ -4232,6 +4232,42 @@ } static bool +isCodeModelMediumOrLarge(CodeModel::Model CM, const Triple& TT) { + switch (CM) { + case CodeModel::Medium: + case CodeModel::Large: + return true; + case CodeModel::Default: + return !TT.isOSDarwin() && + (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le); + case CodeModel::Small: + case CodeModel::JITDefault: + case CodeModel::Kernel: + return false; + default: + llvm_unreachable("All CodeModel values should be covered in switch!"); + return false; + } +} + +static bool +shouldAssumeDifferentTOC(const Function *Caller, SDValue Callee, + const TargetMachine &TM) { + if (isCodeModelMediumOrLarge(TM.getCodeModel(), TM.getTargetTriple())) { + GlobalAddressSDNode *G = dyn_cast(Callee); + if (!G) + return true; + + return !TM.shouldAssumeDSOLocal(*Caller->getParent(), G->getGlobal()); + } + + // Check if Callee resides in the same section, because for Small codemodel, + // we could end up with multiple TOCs in the same module. + // ref: https://bugzilla.mozilla.org/show_bug.cgi?id=973977 + return !resideInSameSection(Caller, Callee, TM); +} + +static bool needStackSlotPassParameters(const PPCSubtarget &Subtarget, const SmallVectorImpl &Outs) { assert(Subtarget.isSVR4ABI() && Subtarget.isPPC64()); @@ -4341,11 +4377,10 @@ !isa(Callee)) return false; - // Check if Callee resides in the same section, because for now, PPC64 SVR4 - // ABI (ELFv1/ELFv2) doesn't allow tail calls to a symbol resides in another - // section. + // If the caller and callee potentially have different TOC bases then we + // cannot tail call since we need to restore the TOC pointer after the call. // ref: https://bugzilla.mozilla.org/show_bug.cgi?id=973977 - if (!resideInSameSection(MF.getFunction(), Callee, getTargetMachine())) + if (shouldAssumeDifferentTOC(MF.getFunction(), Callee, getTargetMachine())) return false; // TCO allows altering callee ABI, so we don't have to check further. @@ -4927,7 +4962,7 @@ // any other variadic arguments). Ops.insert(std::next(Ops.begin()), AddTOC); } else if (CallOpc == PPCISD::CALL && - !resideInSameSection(MF.getFunction(), Callee, DAG.getTarget())) { + shouldAssumeDifferentTOC(MF.getFunction(), Callee, DAG.getTarget())) { // Otherwise insert NOP for non-local calls. CallOpc = PPCISD::CALL_NOP; } Index: test/CodeGen/PowerPC/ppc64-blnop.ll =================================================================== --- test/CodeGen/PowerPC/ppc64-blnop.ll +++ test/CodeGen/PowerPC/ppc64-blnop.ll @@ -5,6 +5,8 @@ ; RUN: llc < %s -function-sections -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu | FileCheck %s -check-prefix=CHECK-FS ; RUN: llc < %s -relocation-model=pic -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu | FileCheck %s ; RUN: llc < %s -function-sections -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu | FileCheck %s -check-prefix=CHECK-FS +; RUN: llc < %s -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -code-model=small -mcpu=pwr8 | FileCheck %s -check-prefix=SCM %class.T = type { [2 x i8] } @@ -74,7 +76,11 @@ ; CHECK-LABEL: wo_hcaller: ; CHECK: bl wo_hcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop + +; SCM-LABEL: wo_hcaller: +; SCM: wo_hcallee +; SCM-NEXT: nop } define weak_odr protected void @wo_pcallee(%class.T* %this, i8* %c) { ret void } @@ -84,7 +90,11 @@ ; CHECK-LABEL: wo_pcaller: ; CHECK: bl wo_pcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop + +; SCM-LABEL: wo_pcaller: +; SCM: wo_pcallee +; SCM-NEXT: nop } define weak_odr void @wo_callee(%class.T* %this, i8* %c) { ret void } @@ -104,7 +114,11 @@ ; CHECK-LABEL: w_pcaller: ; CHECK: bl w_pcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop + +; SCM-LABEL: w_pcaller: +; SCM: w_pcallee +; SCM-NEXT: nop } define weak hidden void @w_hcallee(i8* %ptr) { ret void } @@ -114,7 +128,11 @@ ; CHECK-LABEL: w_hcaller: ; CHECK: bl w_hcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop + +; SCM-LABEL: w_hcaller: +; SCM: bl w_hcallee +; SCM-NEXT: nop } define weak void @w_callee(i8* %ptr) { ret void } Index: test/CodeGen/PowerPC/ppc64-calls.ll =================================================================== --- test/CodeGen/PowerPC/ppc64-calls.ll +++ test/CodeGen/PowerPC/ppc64-calls.ll @@ -1,4 +1,6 @@ ; RUN: llc -relocation-model=static -verify-machineinstrs < %s -march=ppc64 -mcpu=pwr7 | FileCheck %s +; RUN: llc -relocation-model=static -verify-machineinstrs < %s -march=ppc64 -code-model=small -mcpu=pwr7 | FileCheck %s -check-prefix=SCM + target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64" target triple = "powerpc64-unknown-linux-gnu" @@ -21,13 +23,18 @@ ret void } -; Calls to weak function requires a TOC restore 'nop' because they -; may be overridden in a different module. +; Calls to weak function requires a TOC restore 'nop' with the small codemodel +; because they may be overridden in a different module. With large and medium +; codemodels, no TOC restore is needed. define void @test_weak() nounwind readnone { -; CHECK-LABEL: test_weak: tail call void @foo_weak() nounwind -; CHECK: bl foo -; CHECK-NEXT: nop +; CHECK-LABEL: test_weak: +; CHECK: b foo_weak +; CHECK-NOT: nop + +; SCM-LABEL: test_weak: +; SCM: bl foo_weak +; SCM-NEXT: nop ret void } Index: test/CodeGen/PowerPC/ppc64-sibcall.ll =================================================================== --- test/CodeGen/PowerPC/ppc64-sibcall.ll +++ test/CodeGen/PowerPC/ppc64-sibcall.ll @@ -1,6 +1,7 @@ ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu | FileCheck %s -check-prefix=CHECK-SCO ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-SCO-HASQPX ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-SCO-HASQPX +; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 -code-model=small | FileCheck %s -check-prefix=SCM ; No combination of "powerpc64le-unknown-linux-gnu" + "CHECK-SCO", because ; only Power8 (and later) fully support LE. @@ -142,7 +143,10 @@ ret void ; CHECK-SCO-LABEL: wo_hcaller: -; CHECK-SCO: bl wo_hcallee +; CHECK-SCO: b wo_hcallee + +; SCM-LABEL: wo_hcaller: +; SCM: bl wo_hcallee } define weak_odr protected void @wo_pcallee(%class.T* %this, i8* %c) { ret void } @@ -151,7 +155,10 @@ ret void ; CHECK-SCO-LABEL: wo_pcaller: -; CHECK-SCO: bl wo_pcallee +; CHECK-SCO: b wo_pcallee + +; SCM-LABEL: wo_pcaller: +; SCM: bl wo_pcallee } define weak_odr void @wo_callee(%class.T* %this, i8* %c) { ret void } @@ -160,7 +167,10 @@ ret void ; CHECK-SCO-LABEL: wo_caller: -; CHECK-SCO: bl wo_callee +; CHECK-SCO: b wo_callee + +; SCM-LABEL: wo_caller: +; SCM: bl wo_callee } define weak protected void @w_pcallee(i8* %ptr) { ret void } @@ -169,7 +179,10 @@ ret void ; CHECK-SCO-LABEL: w_pcaller: -; CHECK-SCO: bl w_pcallee +; CHECK-SCO: b w_pcallee + +; SCM-LABEL: w_pcaller: +; SCM: bl w_pcallee } define weak hidden void @w_hcallee(i8* %ptr) { ret void } @@ -178,7 +191,10 @@ ret void ; CHECK-SCO-LABEL: w_hcaller: -; CHECK-SCO: bl w_hcallee +; CHECK-SCO: b w_hcallee + +; SCM-LABEL: w_hcaller: +; SCM: bl w_hcallee } define weak void @w_callee(i8* %ptr) { ret void } @@ -187,7 +203,10 @@ ret void ; CHECK-SCO-LABEL: w_caller: -; CHECK-SCO: bl w_callee +; CHECK-SCO: b w_callee + +; SCM-LABEL: w_caller: +; SCM: bl w_callee } %struct.byvalTest = type { [8 x i8] }