diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h --- a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h @@ -36,17 +36,18 @@ CallBranchDelta, // Need to restore r2 after the bl, suggesting the bl is followed by a nop. CallBranchDeltaRestoreTOC, - // Need PLT call stub using TOC, TOC pointer is not saved before branching. - RequestPLTCallStub, - // Need PLT call stub using TOC, TOC pointer is saved before branching. - RequestPLTCallStubSaveTOC, - // Need PLT call stub without using TOC. - RequestPLTCallStubNoTOC, + // Request calling function with TOC. + RequestCall, + // Request calling function without TOC. + RequestCallNoTOC, }; enum PLTCallStubKind { + // Setup function entry(r12) and long branch to target using TOC. LongBranch, + // Save TOC pointer, setup function entry and long branch to target using TOC. LongBranchSaveR2, + // Setup function entry(r12) and long branch to target without using TOC. LongBranchNoTOC, }; @@ -141,8 +142,7 @@ case TOCDelta16DS: case TOCDelta16LODS: case CallBranchDeltaRestoreTOC: - case RequestPLTCallStub: - case RequestPLTCallStubSaveTOC: + case RequestCall: // Create TOC section if TOC relocation, PLT or GOT is used. getOrCreateTOCSection(G); return false; @@ -174,14 +174,25 @@ static StringRef getSectionName() { return "$__STUBS"; } bool visitEdge(LinkGraph &G, Block *B, Edge &E) { + bool isExternal = E.getTarget().isExternal(); Edge::Kind K = E.getKind(); - if (K == ppc64::RequestPLTCallStubSaveTOC && E.getTarget().isExternal()) { - E.setKind(ppc64::CallBranchDeltaRestoreTOC); - this->StubKind = LongBranchSaveR2; - E.setTarget(this->getEntryForTarget(G, E.getTarget())); + if (K == ppc64::RequestCall) { + if (isExternal) { + E.setKind(ppc64::CallBranchDeltaRestoreTOC); + this->StubKind = LongBranchSaveR2; + E.setTarget(this->getEntryForTarget(G, E.getTarget())); + // We previously set branching to local entry. Now reverse that + // operation. + E.setAddend(0); + } else + // TODO: There are cases a local function call need a call stub. + // 1. Caller uses TOC, the callee doesn't, need a r2 save stub. + // 2. Caller doesn't use TOC, the callee does, need a r12 setup stub. + // 3. Branching target is out of range. + E.setKind(ppc64::CallBranchDelta); return true; } - if (K == ppc64::RequestPLTCallStubNoTOC && E.getTarget().isExternal()) { + if (K == ppc64::RequestCallNoTOC) { E.setKind(ppc64::CallBranchDelta); this->StubKind = LongBranchNoTOC; E.setTarget(this->getEntryForTarget(G, E.getTarget())); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp @@ -217,23 +217,14 @@ Kind = ppc64::Delta32; break; case ELF::R_PPC64_REL24_NOTOC: - case ELF::R_PPC64_REL24: { - bool isLocal = !GraphSymbol->isExternal(); - if (isLocal) { - // TODO: There are cases a local function call need a call stub. - // 1. Caller uses TOC, the callee doesn't, need a r2 save stub. - // 2. Caller doesn't use TOC, the callee does, need a r12 setup stub. - // FIXME: For a local call, we might need a thunk if branch target is - // out of range. - Kind = ppc64::CallBranchDelta; - // Branch to local entry. - Addend += ELF::decodePPC64LocalEntryOffset((*ObjSymbol)->st_other); - } else { - Kind = ELFReloc == ELF::R_PPC64_REL24 ? ppc64::RequestPLTCallStubSaveTOC - : ppc64::RequestPLTCallStubNoTOC; - } + Kind = ppc64::RequestCallNoTOC; + break; + case ELF::R_PPC64_REL24: + Kind = ppc64::RequestCall; + assert(Addend == 0 && "Addend is expected to be 0 for a function call"); + // We assume branching to local entry, will reverse the addend if not. + Addend = ELF::decodePPC64LocalEntryOffset((*ObjSymbol)->st_other); break; - } case ELF::R_PPC64_REL64: Kind = ppc64::Delta64; break; diff --git a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp @@ -88,12 +88,10 @@ return "CallBranchDelta"; case CallBranchDeltaRestoreTOC: return "CallBranchDeltaRestoreTOC"; - case RequestPLTCallStub: - return "RequestPLTCallStub"; - case RequestPLTCallStubSaveTOC: - return "RequestPLTCallStubSaveTOC"; - case RequestPLTCallStubNoTOC: - return "RequestPLTCallStubNoTOC"; + case RequestCall: + return "RequestCall"; + case RequestCallNoTOC: + return "RequestCallNoTOC"; default: return getGenericEdgeKindName(static_cast(K)); } diff --git a/llvm/test/ExecutionEngine/JITLink/ppc64/external_weak.s b/llvm/test/ExecutionEngine/JITLink/ppc64/external_weak.s --- a/llvm/test/ExecutionEngine/JITLink/ppc64/external_weak.s +++ b/llvm/test/ExecutionEngine/JITLink/ppc64/external_weak.s @@ -11,7 +11,7 @@ # CHECK: External symbols: # CHECK: {{.*}} linkage: weak, scope: default, dead - foo # CHECK: section .text: -# CHECK: {{.*}} kind = CallBranchDelta, target = foo +# CHECK: {{.*}} kind = CallBranchDeltaRestoreTOC, target = addressable@{{.*}} # `foo` is weak in both relocatable files. `foo` is resolved to the one # defined in `%t/external_weak.o`. So calling `foo` in `%t/external_weak_main.o` # is expected to be an external function call.