1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
From 78f39dc70c1feaea5130b90ea3fb7b3ddd62446b Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hahnjo@hahnjo.de>
Date: Mon, 12 Feb 2024 19:45:52 +0100
Subject: [PATCH] [JITLink][RISCV] Use hashmap to find PCREL_HI20 edge (#78849)
As noted in issues #68594 and #73935, `JITLink/RISCV/ELF_ehframe.s`
fails with libstdc++'s expensive checks because `getRISCVPCRelHi20`
calls `std::equal_range` on the edges which may not be ordered by their
offset. Instead let `ELFJITLinker_riscv` build a hashmap of all edges
with type `R_RISCV_PCREL_HI20` that can be looked up in constant time.
Bugs: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1080435
Closes #73935
---
.../lib/ExecutionEngine/JITLink/ELF_riscv.cpp | 68 ++++++++++---------
1 file changed, 35 insertions(+), 33 deletions(-)
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
@@ -133,38 +133,6 @@
namespace llvm {
namespace jitlink {
-static Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) {
- using namespace riscv;
- assert((E.getKind() == R_RISCV_PCREL_LO12_I ||
- E.getKind() == R_RISCV_PCREL_LO12_S) &&
- "Can only have high relocation for R_RISCV_PCREL_LO12_I or "
- "R_RISCV_PCREL_LO12_S");
-
- const Symbol &Sym = E.getTarget();
- const Block &B = Sym.getBlock();
- orc::ExecutorAddrDiff Offset = Sym.getOffset();
-
- struct Comp {
- bool operator()(const Edge &Lhs, orc::ExecutorAddrDiff Offset) {
- return Lhs.getOffset() < Offset;
- }
- bool operator()(orc::ExecutorAddrDiff Offset, const Edge &Rhs) {
- return Offset < Rhs.getOffset();
- }
- };
-
- auto Bound =
- std::equal_range(B.edges().begin(), B.edges().end(), Offset, Comp{});
-
- for (auto It = Bound.first; It != Bound.second; ++It) {
- if (It->getKind() == R_RISCV_PCREL_HI20)
- return *It;
- }
-
- return make_error<JITLinkError>(
- "No HI20 PCREL relocation type be found for LO12 PCREL relocation type");
-}
-
static uint32_t extractBits(uint32_t Num, unsigned Low, unsigned Size) {
return (Num & (((1ULL << Size) - 1) << Low)) >> Low;
}
@@ -184,9 +152,43 @@
public:
ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx,
std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
- : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
+ : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
+ JITLinkerBase::getPassConfig().PostAllocationPasses.push_back(
+ [this](LinkGraph &G) { return gatherRISCVPCRelHi20(G); });
+ }
private:
+ DenseMap<std::pair<const Block *, orc::ExecutorAddrDiff>, const Edge *>
+ RelHi20;
+
+ Error gatherRISCVPCRelHi20(LinkGraph &G) {
+ for (Block *B : G.blocks())
+ for (Edge &E : B->edges())
+ if (E.getKind() == R_RISCV_PCREL_HI20)
+ RelHi20[{B, E.getOffset()}] = &E;
+
+ return Error::success();
+ }
+
+ Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) const {
+ using namespace riscv;
+ assert((E.getKind() == R_RISCV_PCREL_LO12_I ||
+ E.getKind() == R_RISCV_PCREL_LO12_S) &&
+ "Can only have high relocation for R_RISCV_PCREL_LO12_I or "
+ "R_RISCV_PCREL_LO12_S");
+
+ const Symbol &Sym = E.getTarget();
+ const Block &B = Sym.getBlock();
+ orc::ExecutorAddrDiff Offset = Sym.getOffset();
+
+ auto It = RelHi20.find({&B, Offset});
+ if (It != RelHi20.end())
+ return *It->second;
+
+ return make_error<JITLinkError>("No HI20 PCREL relocation type be found "
+ "for LO12 PCREL relocation type");
+ }
+
Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
using namespace riscv;
using namespace llvm::support;
|