Use a trampoline if musttail not available

For the previous approach to work, we would have had to lock in the
generated code for every function that needs to make tail calls in
assembly.
This commit is contained in:
2024-10-10 17:30:16 -07:00
parent 1faeb220d5
commit 2018fa277c
+20 -19
View File
@@ -3260,35 +3260,28 @@ struct CheckContext {
ConflictSet::Result *results;
int64_t started;
ReadContext *tls;
#if !__has_attribute(musttail)
CheckJob *job;
bool done;
#endif
};
#if __has_attribute(musttail)
FLATTEN PRESERVE_NONE void keepGoing(CheckJob *job, CheckContext *context) {
#if __has_attribute(musttail)
job = job->next;
MUSTTAIL return job->continuation(job, context);
#else
context->job = job->next;
return;
#endif
}
#else
static_assert(offsetof(CheckJob, next) == 0x38);
static_assert(offsetof(CheckJob, continuation) == 0x28);
extern "C" void keepGoing(CheckJob *, CheckContext *);
#if defined(__x86_64__)
asm("keepGoing:\n"
" mov 0x38(%rdi),%rdi\n"
" jmp *0x28(%rdi)\n");
#elif defined(__aarch64__)
asm("keepGoing:\n"
" ldr x0, [x0, #0x38]\n"
" ldr x16, [x0, #0x28]\n"
" br x16\n");
#else
#error "Only x64 and aarch64 are supported"
#endif
#endif
FLATTEN PRESERVE_NONE void complete(CheckJob *job, CheckContext *context) {
if (context->started == context->count) {
if (job->prev == job) {
#if !__has_attribute(musttail)
context->done = true;
#endif
return;
}
job->prev->next = job->next;
@@ -3495,9 +3488,17 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
inProgress[0].prev = inProgress + started - 1;
inProgress[started - 1].next = inProgress;
#if __has_attribute(musttail)
// Kick off the sequence of tail calls that finally returns once all jobs
// are done
inProgress->continuation(inProgress, &context);
#else
context.job = inProgress;
context.done = false;
while (!context.done) {
context.job->continuation(context.job, &context);
}
#endif
for (int i = 0; i < count; ++i) {
assert(reads[i].readVersion >= 0);