[PATCH] D109516: [JITLink] Factor out forEachRelocation() function from addRelocations() in ELF Aarch64 backend (NFC)
Lang Hames via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 12 00:57:26 PDT 2021
lhames accepted this revision.
lhames added a comment.
This revision is now accepted and ready to land.
In D109516#2996242 <https://reviews.llvm.org/D109516#2996242>, @sgraenitz wrote:
> Thinking again now: Assuming we skip most sections immediately, this probably adds unreasonable overhead. Because now there's 2 function calls before checking the type against `ELF::SHT_REL(A)`. And there's not much hope for inlining even with the templated parameter, right? Would be really bad with `-ffunction-sections`.
>
> So, yes for performance reasons I'd change that and put the loop back inside. @lhames What do you think?
Thanks for making these changes Stefan. I'm happy with that approach. I think we would need to do some profiling to determine the practical performance impacts of these decisions before we bothered tuning further.
Now for a fun digression (only tangentially related to this, so you can skip it if you're busy): My motivation for asking you to remove the std::function was my intuition was that it would block inlining of the call to the per-relocation handling method. I didn't have any hard evidence to back that intuition up though, so for fun I thought I would write a quick test. In this test I let 'ints' stand in for relocation objects, since they should make things as easy as possible for the inliner:
#include <functional>
void doSomethingWith(int);
class MyLinker {
public:
void handleRelocation(int X) { doSomethingWith(X); }
};
template <typename Func>
void functionObjectWalk(const int *V, Func F) {
while (*V != 0)
F(*V++);
}
template <typename ClassT, typename MethT>
void methodWalk(const int *V, ClassT *Instance, MethT Method) {
functionObjectWalk(V,
[Instance, Method](int X) {
(Instance->*Method)(X);
});
}
void stdfunctionWalk(const int *V,
std::function<void(int)> F) {
while (*V != 0)
F(*V++);
}
void testFunctionObjectWalk() {
MyLinker ML;
int V[] = { 1, 2, 3, 0 };
functionObjectWalk(V, [&](int X) { ML.handleRelocation(X); });
}
void testMethodWalk() {
MyLinker ML;
int V[] = { 1, 2, 3, 0 };
methodWalk(V, &ML, &MyLinker::handleRelocation);
}
void testStdFunctionWalk() {
MyLinker ML;
int V[] = { 1, 2, 3, 0 };
stdfunctionWalk(V, [&](int X) { ML.handleRelocation(X); });
}
I compiled this with a released Xcode clang with: `clang++ -std=c++17 -fno-exceptions -fno-rtti -fno-asynchronous-unwind-tables -O3 -S -o testcase.s testcase.cpp` (the options helped to keep the assembly readable). As expected: `functionObjectWalk` and `methodWalk` produce equivalent results with neatly inlined calls to `doSomethingWith`, whereas `stdfunctionWalk` produces a longer loop with an indirect call. I'm going to call my intuition "tentatively confirmed". I'm not quite motivated enough to dig into the assembly for a release build of LLVM at the moment. ;)
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D109516/new/
https://reviews.llvm.org/D109516
More information about the llvm-commits
mailing list