rdunnington / bytebox

Standalone WebAssembly VM.
MIT License
95 stars 4 forks source link

MIPS32 support #57

Open InBetweenNames opened 1 month ago

InBetweenNames commented 1 month ago

Unfortunately, the LLVM MIPS32 backend doesn't support the always_tail call attribute and therefore the build fails on this platform. It's unclear to me if this is just the MIPS backend not being sophisticated enough to understand this attribute or if there are performance implications.

rdunnington commented 1 month ago

Hey thanks for your interest! Unfortunately the always_tail attribute is a really important performance optimization for interpreters like this one. The other option would be a type of computed goto , but that doesn't exist in zig yet. It seems the ideal path here would be to file a bug on the zig compiler, which would ideally end up in an llvm upstream patch, fixing the issue.

The other potential path would be adding a secondary mode of execution that is a switch statement for platforms that don't support always_tail. I would be open to this path, though it will involve a lot of code reshuffling and I'm pretty busy atm with the register backend.

InBetweenNames commented 3 weeks ago

Hi rdunnington,

I did a lot of reading and it seems you're right. However, I have good news to share: https://github.com/ziglang/zig/commit/3929cac154d71a3e19fd028fc67c1d1d15823ca2

That feature you linked seems to have just landed on nightly! Pretty exciting stuff. What do you think about porting over the TCO-based code over to this when it lands in stable?

rdunnington commented 3 weeks ago

Oh yeah that's awesome! I happened to see that today too. 😁 I think I would want to experiment with it anyway to see what the perf is like so I'm definitely interested in trying it out.

I will also say that I am a bit surprised that tail-calls don't work on MIPS in general. I'm only familiar with x86 but assuming MIPS still keeps track of the stack in a similar way using stack pointers, I would think the same mechanism could be implemented there as well. It might still be worth making an isolated repro and submitting a bug on the zig compiler if you are interested in advancing MIPS support in general.

InBetweenNames commented 3 weeks ago

Yeah I'll poke around LLVM and see what's the root cause in there. What's happening is Zig is lowering .always_tail call sites into the LLVM musttail attribute which is handled solely by the backend. Even ARM 32-bit is actively being worked on in this area to bring its TCO up to par with the more used LLVM backends. There's nothing special going on with MIPS here I don't think.

InBetweenNames commented 3 weeks ago

Hah, imagine if it's this simple:

https://github.com/llvm/llvm-project/blob/056a1676cbe43ce22b65a500a2dc9916fd575563/llvm/lib/Target/Mips/MipsSEISelLowering.cpp#L1145

It looks like the MIPS backend disables tail calls by default, even if they would otherwise be possible to perform

InBetweenNames commented 3 weeks ago

Sorry for the spam, but enabling this did indeed work on a C test program:

test.c:

int (*g)(void);

int __attribute__((noinline)) f(void) {
  ++g;
  __attribute__((musttail)) return (*g)();
}

zig cc -target mips-linux-musl -O3 -mllvm -mips-tail-calls test.c -shared

The above command line works while removing the -mllvm -mips-tail-calls causes the tail call to not be optimized out.

InBetweenNames commented 3 weeks ago

Made a ticket here: https://github.com/ziglang/zig/issues/21332

rdunnington commented 3 weeks ago

Nice investigation and thanks for the followup 👍.