[llvm] [Draft] Basic JITLink AArch32 support for clang-repl (PR #77313)
Stefan Gränitz via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 15 04:18:58 PST 2024
https://github.com/weliveindetail updated https://github.com/llvm/llvm-project/pull/77313
>From b50f4001ceba87a531143ad85ffe05cf1ed1d2d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Mon, 8 Jan 2024 15:05:08 +0100
Subject: [PATCH 1/7] [JITLink][AArch32] In warning output add decimal value
for CPUArch and missing newline
---
llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index f346cfb2a93112..d7869377a8baaa 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -146,7 +146,7 @@ inline ArmConfig getArmConfigForCPUArch(ARMBuildAttrs::CPUArch CPUArch) {
default:
DEBUG_WITH_TYPE("jitlink", {
dbgs() << " Warning: ARM config not defined for CPU architecture "
- << getCPUArchName(CPUArch);
+ << getCPUArchName(CPUArch) << " (" << CPUArch << ")\n";
});
break;
}
>From 36e9566e04577182ac6a456aac139d7b2cf54889 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Wed, 10 Jan 2024 17:07:28 +0100
Subject: [PATCH 2/7] [JITLink][AArch32] Streamline file-names of tests (NFC)
All other backends use the full term "relocations". Also, sorting by type (relocations/stubs/etc.) before CPU states (arm/thumb/other) makes it easier to filter in LIT.
---
.../AArch32/{ELF_static_arm_reloc.s => ELF_relocations_arm.s} | 0
.../AArch32/{ELF_static_data_reloc.s => ELF_relocations_data.s} | 0
.../AArch32/{ELF_static_thumb_reloc.s => ELF_relocations_thumb.s} | 0
.../JITLink/AArch32/{ELF_thumb_stubs.s => ELF_stubs_thumb.s} | 0
4 files changed, 0 insertions(+), 0 deletions(-)
rename llvm/test/ExecutionEngine/JITLink/AArch32/{ELF_static_arm_reloc.s => ELF_relocations_arm.s} (100%)
rename llvm/test/ExecutionEngine/JITLink/AArch32/{ELF_static_data_reloc.s => ELF_relocations_data.s} (100%)
rename llvm/test/ExecutionEngine/JITLink/AArch32/{ELF_static_thumb_reloc.s => ELF_relocations_thumb.s} (100%)
rename llvm/test/ExecutionEngine/JITLink/AArch32/{ELF_thumb_stubs.s => ELF_stubs_thumb.s} (100%)
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s
similarity index 100%
rename from llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
rename to llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_data_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
similarity index 100%
rename from llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_data_reloc.s
rename to llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_thumb_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumb.s
similarity index 100%
rename from llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_thumb_reloc.s
rename to llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumb.s
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
similarity index 100%
rename from llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
rename to llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
>From ed26d08ada2d6c9a335597181772e518293ab24d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Mon, 8 Jan 2024 15:06:33 +0100
Subject: [PATCH 3/7] [Orc] Make JITLink default in LLJIT for ELF-based ARM
targets
---
llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
index e259c393d07e03..833dcb9d5bf2e7 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
@@ -734,6 +734,12 @@ Error LLJITBuilderState::prepareForConstruction() {
case Triple::aarch64:
UseJITLink = !TT.isOSBinFormatCOFF();
break;
+ case Triple::arm:
+ case Triple::armeb:
+ case Triple::thumb:
+ case Triple::thumbeb:
+ UseJITLink = TT.isOSBinFormatELF();
+ break;
case Triple::x86_64:
UseJITLink = !TT.isOSBinFormatCOFF();
break;
>From 9913d3e67638ac4dcd0917a4dc8746f56a5302b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 13 Jan 2024 23:29:33 +0100
Subject: [PATCH 4/7] [JITLink][AArch32] Fix typo in thumb stubs test (NFC)
---
llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
index bd95c375279246..598d9d06100887 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
@@ -26,7 +26,7 @@ test_external_call:
.size test_external_call, .-test_external_call
.globl test_external_jump
- .type test_external_call,%function
+ .type test_external_jump,%function
.p2align 1
.code 16
.thumb_func
>From 5083c866901bf405260f95802fbedbec4009f7d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 13 Jan 2024 23:35:54 +0100
Subject: [PATCH 5/7] [Orc] Allow optional index argument in jitlink-check
stub_addr expressions
---
.../llvm/ExecutionEngine/RuntimeDyldChecker.h | 2 +-
.../RuntimeDyld/RuntimeDyldChecker.cpp | 21 +++++++++++++----
.../RuntimeDyld/RuntimeDyldCheckerImpl.h | 3 ++-
llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp | 6 ++---
llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp | 12 +++++-----
.../tools/llvm-jitlink/llvm-jitlink-macho.cpp | 6 ++---
llvm/tools/llvm-jitlink/llvm-jitlink.cpp | 23 ++++++++++++++-----
llvm/tools/llvm-jitlink/llvm-jitlink.h | 6 ++---
8 files changed, 51 insertions(+), 28 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h
index 80e4bbf494339c..55cc16834976d0 100644
--- a/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h
+++ b/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h
@@ -154,7 +154,7 @@ class RuntimeDyldChecker {
using GetSectionInfoFunction = std::function<Expected<MemoryRegionInfo>(
StringRef FileName, StringRef SectionName)>;
using GetStubInfoFunction = std::function<Expected<MemoryRegionInfo>(
- StringRef StubContainer, StringRef TargetName)>;
+ StringRef StubContainer, StringRef TargetName, int64_t StubIndex)>;
using GetGOTInfoFunction = std::function<Expected<MemoryRegionInfo>(
StringRef GOTContainer, StringRef TargetName)>;
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
index 7fadbdd6a1fff2..801496b8b91035 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
@@ -400,6 +400,15 @@ class RuntimeDyldCheckerExprEval {
StringRef Symbol;
std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
+ // Parse optional stub index parameter
+ int64_t StubIndex = 0;
+ if (RemainingExpr.starts_with(",")) {
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+ EvalResult Number;
+ std::tie(Number, RemainingExpr) = evalNumberExpr(RemainingExpr);
+ StubIndex = Number.getValue();
+ }
+
if (!RemainingExpr.starts_with(")"))
return std::make_pair(
unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
@@ -408,7 +417,7 @@ class RuntimeDyldCheckerExprEval {
uint64_t StubAddr;
std::string ErrorMsg;
std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor(
- StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr);
+ StubContainerName, Symbol, StubIndex, PCtx.IsInsideLoad, IsStubAddr);
if (ErrorMsg != "")
return std::make_pair(EvalResult(ErrorMsg), "");
@@ -985,11 +994,13 @@ std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
}
std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
- StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad,
- bool IsStubAddr) const {
+ StringRef StubContainerName, StringRef SymbolName, int64_t StubIndex,
+ bool IsInsideLoad, bool IsStubAddr) const {
- auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName)
- : GetGOTInfo(StubContainerName, SymbolName);
+ assert((StubIndex == 0 || IsStubAddr) && "Indexing only supported for stubs");
+ auto StubInfo = IsStubAddr
+ ? GetStubInfo(StubContainerName, SymbolName, StubIndex)
+ : GetGOTInfo(StubContainerName, SymbolName);
if (!StubInfo) {
std::string ErrMsg;
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
index 9f44a9389f4734..0f43e877318895 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
@@ -64,7 +64,8 @@ class RuntimeDyldCheckerImpl {
std::pair<uint64_t, std::string>
getStubOrGOTAddrFor(StringRef StubContainerName, StringRef Symbol,
- bool IsInsideLoad, bool IsStubAddr) const;
+ int64_t StubIndex, bool IsInsideLoad,
+ bool IsStubAddr) const;
std::optional<uint64_t> getSectionLoadAddress(void *LocalAddr) const;
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp
index 283e655205d780..5857ae88d3bb93 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp
@@ -130,9 +130,9 @@ Error registerCOFFGraphInfo(Session &S, LinkGraph &G) {
inconvertibleErrorCode());
if (auto TS = getCOFFStubTarget(G, Sym->getBlock()))
- FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue(),
- Sym->getTargetFlags()};
+ FileInfo.StubInfos[TS->getName()].insert(
+ 0, {Sym->getSymbolContent(), Sym->getAddress().getValue(),
+ Sym->getTargetFlags()});
else
return TS.takeError();
SectionContainsContent = true;
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
index a02468758b33f6..395d16308fe2fb 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
@@ -150,9 +150,9 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
inconvertibleErrorCode());
if (auto TS = getELFStubTarget(G, Sym->getBlock()))
- FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue(),
- Sym->getTargetFlags()};
+ FileInfo.StubInfos[TS->getName()].insert(
+ 0, {Sym->getSymbolContent(), Sym->getAddress().getValue(),
+ Sym->getTargetFlags()});
else
return TS.takeError();
SectionContainsContent = true;
@@ -162,9 +162,9 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
inconvertibleErrorCode());
if (auto Name = getELFAArch32StubTargetName(G, Sym->getBlock()))
- FileInfo.StubInfos[*Name] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue(),
- Sym->getTargetFlags()};
+ FileInfo.StubInfos[*Name].push_back({Sym->getSymbolContent(),
+ Sym->getAddress().getValue(),
+ Sym->getTargetFlags()});
else
return Name.takeError();
SectionContainsContent = true;
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp
index 7dcadd94c2365a..aeb9e84a2946cf 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp
@@ -129,9 +129,9 @@ Error registerMachOGraphInfo(Session &S, LinkGraph &G) {
inconvertibleErrorCode());
if (auto TS = getMachOStubTarget(G, Sym->getBlock()))
- FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue(),
- Sym->getTargetFlags()};
+ FileInfo.StubInfos[TS->getName()].insert(
+ 0, {Sym->getSymbolContent(), Sym->getAddress().getValue(),
+ Sym->getTargetFlags()});
else
return TS.takeError();
SectionContainsContent = true;
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index aa032c97485fbf..10327c3c768fa7 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -331,8 +331,12 @@ operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
for (auto &GOTKV : FI.GOTEntryInfos)
OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
- for (auto &StubKV : FI.StubInfos)
- OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
+ for (auto &StubKVs : FI.StubInfos) {
+ OS << " Stubs \"" << StubKVs.first() << "\":";
+ for (auto MemRegion : StubKVs.second)
+ OS << " " << MemRegion;
+ OS << "\n";
+ }
return OS;
}
@@ -1206,7 +1210,8 @@ Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
}
Expected<Session::MemoryRegionInfo &>
-Session::findStubInfo(StringRef FileName, StringRef TargetName) {
+Session::findStubInfo(StringRef FileName, StringRef TargetName,
+ uint64_t StubIndex) {
auto FI = findFileInfo(FileName);
if (!FI)
return FI.takeError();
@@ -1216,7 +1221,12 @@ Session::findStubInfo(StringRef FileName, StringRef TargetName) {
"\" registered for file \"" + FileName +
"\"",
inconvertibleErrorCode());
- return StubInfoItr->second;
+ if (StubIndex >= StubInfoItr->second.size())
+ return make_error<StringError>(
+ "no stub for \"" + TargetName + " with index " + Twine(StubIndex) +
+ "\" registered for file \"" + FileName + "\"",
+ inconvertibleErrorCode());
+ return StubInfoItr->second[StubIndex];
}
Expected<Session::MemoryRegionInfo &>
@@ -1985,8 +1995,9 @@ static Error runChecks(Session &S, Triple TT, SubtargetFeatures Features) {
return S.findSectionInfo(FileName, SectionName);
};
- auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
- return S.findStubInfo(FileName, SectionName);
+ auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName,
+ int64_t StubIndex) {
+ return S.findStubInfo(FileName, SectionName, StubIndex);
};
auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h b/llvm/tools/llvm-jitlink/llvm-jitlink.h
index 3ff406b7b82dfd..c3ed8981e1daf1 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.h
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h
@@ -49,7 +49,7 @@ struct Session {
struct FileInfo {
StringMap<MemoryRegionInfo> SectionInfos;
- StringMap<MemoryRegionInfo> StubInfos;
+ StringMap<SmallVector<MemoryRegionInfo, 1>> StubInfos;
StringMap<MemoryRegionInfo> GOTEntryInfos;
};
@@ -63,8 +63,8 @@ struct Session {
Expected<FileInfo &> findFileInfo(StringRef FileName);
Expected<MemoryRegionInfo &> findSectionInfo(StringRef FileName,
StringRef SectionName);
- Expected<MemoryRegionInfo &> findStubInfo(StringRef FileName,
- StringRef TargetName);
+ Expected<MemoryRegionInfo &>
+ findStubInfo(StringRef FileName, StringRef TargetName, uint64_t StubIndex);
Expected<MemoryRegionInfo &> findGOTEntryInfo(StringRef FileName,
StringRef TargetName);
>From 9730b7b81eaabd456d9ef10f1f886c2450f3db5b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 13 Jan 2024 23:45:15 +0100
Subject: [PATCH 6/7] [JITLink][AArch32] Rename stubs flavor Thumbv7 to v7
(NFC)
---
llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h | 12 ++++++------
llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp | 8 ++++----
llvm/lib/ExecutionEngine/JITLink/aarch32.cpp | 2 +-
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index d7869377a8baaa..53c9ef2fdf395e 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -123,15 +123,15 @@ const char *getEdgeKindName(Edge::Kind K);
///
/// Stubs are often called "veneers" in the official docs and online.
///
-enum StubsFlavor {
+enum class StubsFlavor {
Unsupported = 0,
- Thumbv7,
+ v7,
};
/// JITLink sub-arch configuration for Arm CPU models
struct ArmConfig {
bool J1J2BranchEncoding = false;
- StubsFlavor Stubs = Unsupported;
+ StubsFlavor Stubs = StubsFlavor::Unsupported;
};
/// Obtain the sub-arch configuration for a given Arm CPU model.
@@ -141,7 +141,7 @@ inline ArmConfig getArmConfigForCPUArch(ARMBuildAttrs::CPUArch CPUArch) {
case ARMBuildAttrs::v7:
case ARMBuildAttrs::v8_A:
ArmCfg.J1J2BranchEncoding = true;
- ArmCfg.Stubs = Thumbv7;
+ ArmCfg.Stubs = StubsFlavor::v7;
break;
default:
DEBUG_WITH_TYPE("jitlink", {
@@ -380,9 +380,9 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
/// Create a branch range extension stub with Thumb encoding for v7 CPUs.
template <>
-Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target);
+Symbol &StubsManager<StubsFlavor::v7>::createEntry(LinkGraph &G, Symbol &Target);
-template <> inline StringRef StubsManager<Thumbv7>::getSectionName() {
+template <> inline StringRef StubsManager<StubsFlavor::v7>::getSectionName() {
return "__llvm_jitlink_aarch32_STUBS_Thumbv7";
}
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index 132989fcbce021..3c596a414363e4 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -257,7 +257,7 @@ createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) {
case v7:
case v8_A:
ArmCfg = aarch32::getArmConfigForCPUArch(Arch);
- assert(ArmCfg.Stubs != aarch32::Unsupported &&
+ assert(ArmCfg.Stubs != aarch32::StubsFlavor::Unsupported &&
"Provide a config for each supported CPU");
break;
default:
@@ -309,11 +309,11 @@ void link_ELF_aarch32(std::unique_ptr<LinkGraph> G,
PassCfg.PrePrunePasses.push_back(markAllSymbolsLive);
switch (ArmCfg.Stubs) {
- case aarch32::Thumbv7:
+ case aarch32::StubsFlavor::v7:
PassCfg.PostPrunePasses.push_back(
- buildTables_ELF_aarch32<aarch32::Thumbv7>);
+ buildTables_ELF_aarch32<aarch32::StubsFlavor::v7>);
break;
- case aarch32::Unsupported:
+ case aarch32::StubsFlavor::Unsupported:
llvm_unreachable("Check before building graph");
}
}
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 671ee1a8125252..4e75bb4882a28a 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -685,7 +685,7 @@ const uint8_t Thumbv7ABS[] = {
};
template <>
-Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) {
+Symbol &StubsManager<StubsFlavor::v7>::createEntry(LinkGraph &G, Symbol &Target) {
constexpr uint64_t Alignment = 4;
Block &B = addStub(G, Thumbv7ABS, Alignment);
LLVM_DEBUG({
>From 13ce9e6c1e36bb7675ab74226bdf4b03a6f76ac4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Sat, 13 Jan 2024 23:58:36 +0100
Subject: [PATCH 7/7] [JITLink][AArch32] Multi-stub support and selection
armv7/thumbv7
---
.../llvm/ExecutionEngine/JITLink/aarch32.h | 66 ++------
.../ExecutionEngine/JITLink/ELF_aarch32.cpp | 8 +-
llvm/lib/ExecutionEngine/JITLink/aarch32.cpp | 144 ++++++++++++++++--
.../JITLink/AArch32/ELF_stubs_arm.s | 39 +++++
.../JITLink/AArch32/ELF_stubs_multi.s | 56 +++++++
5 files changed, 242 insertions(+), 71 deletions(-)
create mode 100644 llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_multi.s
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 53c9ef2fdf395e..44f11f6162be24 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -318,74 +318,32 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
}
-/// Stubs builder for a specific StubsFlavor
-///
-/// Right now we only have one default stub kind, but we want to extend this
-/// and allow creation of specific kinds in the future (e.g. branch range
-/// extension or interworking).
-///
+/// Stubs builder for v7 emits non-position-independent Arm and Thumb stubs.
/// Let's keep it simple for the moment and not wire this through a GOT.
///
-template <StubsFlavor Flavor>
-class StubsManager : public TableManager<StubsManager<Flavor>> {
+class StubsManager_v7 {
public:
- StubsManager() = default;
- /// Name of the object file section that will contain all our stubs.
- static StringRef getSectionName();
+ StubsManager_v7() = default;
- /// Implements link-graph traversal via visitExistingEdges().
- bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
- if (E.getTarget().isDefined())
- return false;
-
- switch (E.getKind()) {
- case Thumb_Call:
- case Thumb_Jump24: {
- DEBUG_WITH_TYPE("jitlink", {
- dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
- << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
- << formatv("{0:x}", E.getOffset()) << ")\n";
- });
- E.setTarget(this->getEntryForTarget(G, E.getTarget()));
- return true;
- }
- }
- return false;
+ /// Name of the object file section that will contain all our stubs.
+ static StringRef getSectionName() {
+ return "__llvm_jitlink_aarch32_STUBS_v7";
}
- /// Create a branch range extension stub for the class's flavor.
- Symbol &createEntry(LinkGraph &G, Symbol &Target);
+ /// Implements link-graph traversal via visitExistingEdges().
+ bool visitEdge(LinkGraph &G, Block *B, Edge &E);
private:
- /// Create a new node in the link-graph for the given stub template.
- template <size_t Size>
- Block &addStub(LinkGraph &G, const uint8_t (&Code)[Size],
- uint64_t Alignment) {
- ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size);
- return G.createContentBlock(getStubsSection(G), Template,
- orc::ExecutorAddr(), Alignment, 0);
- }
+ using StubMapEntry = SmallVector<std::tuple<bool, Symbol *>>;
+ enum ThumbStatePreference { Undefined = -1, Avoid = 0, PreferNot, Prefer, Force };
- /// Get or create the object file section that will contain all our stubs.
- Section &getStubsSection(LinkGraph &G) {
- if (!StubsSection)
- StubsSection = &G.createSection(getSectionName(),
- orc::MemProt::Read | orc::MemProt::Exec);
- return *StubsSection;
- }
+ Symbol *selectStub(const StubMapEntry &Candidates, ThumbStatePreference ThumbState);
+ DenseMap<StringRef, StubMapEntry> StubMap;
Section *StubsSection = nullptr;
};
-/// Create a branch range extension stub with Thumb encoding for v7 CPUs.
-template <>
-Symbol &StubsManager<StubsFlavor::v7>::createEntry(LinkGraph &G, Symbol &Target);
-
-template <> inline StringRef StubsManager<StubsFlavor::v7>::getSectionName() {
- return "__llvm_jitlink_aarch32_STUBS_Thumbv7";
-}
-
} // namespace aarch32
} // namespace jitlink
} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index 3c596a414363e4..6f77ac89b9c2cd 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -216,12 +216,12 @@ class ELFLinkGraphBuilder_aarch32
ArmCfg(std::move(ArmCfg)) {}
};
-template <aarch32::StubsFlavor Flavor>
+template <typename StubsManagerType>
Error buildTables_ELF_aarch32(LinkGraph &G) {
LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
- aarch32::StubsManager<Flavor> PLT;
- visitExistingEdges(G, PLT);
+ StubsManagerType Stubs;
+ visitExistingEdges(G, Stubs);
return Error::success();
}
@@ -311,7 +311,7 @@ void link_ELF_aarch32(std::unique_ptr<LinkGraph> G,
switch (ArmCfg.Stubs) {
case aarch32::StubsFlavor::v7:
PassCfg.PostPrunePasses.push_back(
- buildTables_ELF_aarch32<aarch32::StubsFlavor::v7>);
+ buildTables_ELF_aarch32<aarch32::StubsManager_v7>);
break;
case aarch32::StubsFlavor::Unsupported:
llvm_unreachable("Check before building graph");
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 4e75bb4882a28a..7932e24b6df245 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -15,6 +15,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ManagedStatic.h"
@@ -678,28 +679,145 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
}
}
+const uint8_t Armv7ABS[] = {
+ 0x00, 0xc0, 0x00, 0xe3, // movw r12, #0x0000 ; lower 16-bit
+ 0x00, 0xc0, 0x40, 0xe3, // movt r12, #0x0000 ; upper 16-bit
+ 0x1c, 0xff, 0x2f, 0xe1 // bx r12
+};
+
const uint8_t Thumbv7ABS[] = {
0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit
0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit
0x60, 0x47 // bx r12
};
-template <>
-Symbol &StubsManager<StubsFlavor::v7>::createEntry(LinkGraph &G, Symbol &Target) {
+/// Create a new node in the link-graph for the given stub template.
+template <size_t Size>
+static Block &allocStub(LinkGraph &G, Section &S, const uint8_t (&Code)[Size]) {
constexpr uint64_t Alignment = 4;
- Block &B = addStub(G, Thumbv7ABS, Alignment);
- LLVM_DEBUG({
- const char *StubPtr = B.getContent().data();
- HalfWords Reg12 = encodeRegMovtT1MovwT3(12);
- assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
- checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
- "Linker generated stubs may only corrupt register r12 (IP)");
- });
+ ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size);
+ return G.createContentBlock(S, Template, orc::ExecutorAddr(), Alignment, 0);
+}
+
+static Block &createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target) {
+ Block &B = allocStub(G, S, Thumbv7ABS);
B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
B.addEdge(Thumb_MovtAbs, 4, Target, 0);
- Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false);
- Stub.setTargetFlags(ThumbSymbol);
- return Stub;
+
+ [[maybe_unused]] const char *StubPtr = B.getContent().data();
+ [[maybe_unused]] HalfWords Reg12 = encodeRegMovtT1MovwT3(12);
+ assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
+ checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
+ "Linker generated stubs may only corrupt register r12 (IP)");
+ return B;
+}
+
+static Block &createStubArmv7(LinkGraph &G, Section &S, Symbol &Target) {
+ Block &B = allocStub(G, S, Armv7ABS);
+ B.addEdge(Arm_MovwAbsNC, 0, Target, 0);
+ B.addEdge(Arm_MovtAbs, 4, Target, 0);
+
+ [[maybe_unused]] const char *StubPtr = B.getContent().data();
+ [[maybe_unused]] uint32_t Reg12 = encodeRegMovtA1MovwA2(12);
+ assert(checkRegister<Arm_MovwAbsNC>(StubPtr, Reg12) &&
+ checkRegister<Arm_MovtAbs>(StubPtr + 4, Reg12) &&
+ "Linker generated stubs may only corrupt register r12 (IP)");
+ return B;
+}
+
+Symbol *StubsManager_v7::selectStub(const StubMapEntry &Candidates,
+ ThumbStatePreference ThumbState) {
+ Symbol *StubSymbol = nullptr;
+ for (auto [StubIsThumb, Sym] : Candidates) {
+ if (StubIsThumb) {
+ if (ThumbState == Avoid)
+ continue; // No match
+ StubSymbol = Sym;
+ break; // Best match
+ }
+ if (ThumbState == Avoid) {
+ StubSymbol = Sym;
+ break; // Best match
+ }
+ if (ThumbState == Prefer) {
+ StubSymbol = Sym;
+ continue; // Acceptable match
+ }
+ }
+ return StubSymbol;
+}
+
+bool StubsManager_v7::visitEdge(LinkGraph &G, Block *B, Edge &E) {
+ ThumbStatePreference ThumbState = Undefined;
+ switch (E.getKind()) {
+ case Arm_Call:
+ case Arm_Jump24:
+ ThumbState = Avoid;
+ break;
+ case Thumb_Call:
+ ThumbState = Prefer;
+ break;
+ case Thumb_Jump24:
+ ThumbState = Force;
+ break;
+ default:
+ return false;
+ }
+
+ assert(ThumbState != Undefined && "Define Thumb state preference");
+
+ // Stubs are usually created only for external targets.
+ Symbol &Target = E.getTarget();
+ if (Target.isDefined()) {
+ bool TargetIsThumb = Target.getTargetFlags() & ThumbSymbol;
+ bool InterworkingStub = ThumbState == Force && !TargetIsThumb;
+ if (!InterworkingStub)
+ return false;
+ }
+
+ LLVM_DEBUG(dbgs() << " Preparing stub with thumb-state '"
+ << (ThumbState == Avoid ? "Avoid" : "")
+ << (ThumbState == Prefer ? "Prefer" : "")
+ << (ThumbState == Force ? "Force" : "") << "' for "
+ << G.getEdgeKindName(E.getKind()) << " edge at "
+ << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
+ << formatv("{0:x}", E.getOffset()) << ")\n");
+
+ assert(Target.hasName() && "Edge cannot point to anonymous target");
+ auto TargetEntry = StubMap.try_emplace(Target.getName()).first;
+
+ Symbol *StubSymbol = selectStub(TargetEntry->second, ThumbState);
+ if (!StubSymbol) {
+ if (!StubsSection)
+ StubsSection = &G.createSection(getSectionName(),
+ orc::MemProt::Read | orc::MemProt::Exec);
+
+ bool MakeThumb = ThumbState >= Prefer;
+ Block &B = MakeThumb ? createStubThumbv7(G, *StubsSection, Target)
+ : createStubArmv7(G, *StubsSection, Target);
+
+ StubSymbol = &G.addAnonymousSymbol(B, 0, B.getSize(), true, false);
+ if (MakeThumb)
+ StubSymbol->setTargetFlags(ThumbSymbol);
+
+ LLVM_DEBUG({
+ dbgs() << " Created " << (MakeThumb ? "Thumb" : "Arm") << " entry for "
+ << Target.getName() << " in " << StubsSection->getName() << ": "
+ << *StubSymbol << "\n";
+ });
+
+ TargetEntry->second.emplace_back(MakeThumb, StubSymbol);
+ }
+
+ LLVM_DEBUG({
+ bool StubIsThumb = StubSymbol->getTargetFlags() & ThumbSymbol;
+ dbgs() << " Using " << (StubIsThumb ? "Thumb" : "Arm") << " entry "
+ << *StubSymbol << " in "
+ << StubSymbol->getBlock().getSection().getName() << "\n";
+ });
+
+ E.setTarget(*StubSymbol);
+ return true;
}
const char *getEdgeKindName(Edge::Kind K) {
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
new file mode 100644
index 00000000000000..afda0ec9dabf2f
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
@@ -0,0 +1,39 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=armv7-linux-gnueabi -arm-add-build-attributes \
+# RUN: -filetype=obj -filetype=obj -o %t/elf_stubs.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN: -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN: -abs ext_arm=0x76bbe880 \
+# RUN: -check %s %t/elf_stubs.o
+
+ .text
+ .syntax unified
+
+# Check that calls/jumps to external functions trigger the generation of
+# branch-range extension stubs. These stubs don't follow the default PLT model
+# where the branch-target address is loaded from a GOT entry. Instead, they
+# hard-code it in the immediate field.
+#
+# jitlink-check: decode_operand(test_external_call, 0) = stub_addr(elf_stubs.o, ext_arm) - (test_external_call + 8)
+# jitlink-check: decode_operand(test_external_jump, 0) = stub_addr(elf_stubs.o, ext_arm) - (test_external_jump + 8)
+ .globl test_external_call
+ .type test_external_call,%function
+ .p2align 2
+test_external_call:
+ bl ext_arm
+ .size test_external_call, .-test_external_call
+
+ .globl test_external_jump
+ .type test_external_jump,%function
+ .p2align 2
+test_external_jump:
+ b ext_arm
+ .size test_external_jump, .-test_external_jump
+
+# Empty main function for jitlink to be happy
+ .globl main
+ .type main,%function
+ .p2align 2
+main:
+ bx lr
+ .size main, .-main
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_multi.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_multi.s
new file mode 100644
index 00000000000000..2c1a6be85b1a91
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_multi.s
@@ -0,0 +1,56 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes \
+# RUN: -filetype=obj -filetype=obj -o %t/elf_stubs.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN: -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN: -abs external_func=0x76bbe880 \
+# RUN: -check %s %t/elf_stubs.o
+
+ .text
+ .syntax unified
+
+# Check support for multiple stubs for a single symbol
+
+# jitlink-check: decode_operand(test_avoid_thumb, 0) = stub_addr(elf_stubs.o, external_func, 0) - (test_avoid_thumb + 8)
+# jitlink-check: decode_operand(test_prefer_thumb, 2) = stub_addr(elf_stubs.o, external_func, 0) - next_pc(test_prefer_thumb)
+# jitlink-check: decode_operand(test_force_thumb, 0) = stub_addr(elf_stubs.o, external_func, 1) - next_pc(test_force_thumb)
+
+# Arm call will create an Arm stub first
+ .globl test_avoid_thumb
+ .type test_avoid_thumb,%function
+ .p2align 2
+ .code 32
+test_avoid_thumb:
+ bl external_func
+ .size test_avoid_thumb, .-test_avoid_thumb
+
+# Thumb call would create a Thumb stub if there was non at all, but it can be
+# rewritten to BLX and reuse the existing Arm stub.
+# TODO: Should we reconsider during relaxation?
+ .globl test_prefer_thumb
+ .type test_prefer_thumb,%function
+ .p2align 1
+ .code 16
+ .thumb_func
+test_prefer_thumb:
+ bl external_func
+ .size test_prefer_thumb, .-test_prefer_thumb
+
+# Thumb jump requires a Thumb stub, so it creates one in addition to the
+# existing Arm stub.
+ .globl test_force_thumb
+ .type test_force_thumb,%function
+ .p2align 1
+ .code 16
+ .thumb_func
+test_force_thumb:
+ b external_func
+ .size test_force_thumb, .-test_force_thumb
+
+# Empty main function for jitlink to be happy
+ .globl main
+ .type main,%function
+ .p2align 2
+main:
+ bx lr
+ .size main, .-main
More information about the llvm-commits
mailing list