Skip to content

Enable tail call optimization on MIPS32 #21332

@InBetweenNames

Description

@InBetweenNames

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

Hello Zig team!

I noticed that the MIPS backend is having trouble optimizing out tail calls, which is something used a lot in interpreters. Indeed, this is actually an LLVM problem with the MIPS handling of the musttail attribute. However, I was able to enable tail calls for MIPS by passing in -mllvm -mips-tail-calls to the zig cc invocation and this correctly optimized out the tail calls on these call sites (in my case). An example is given below:

test.c:

int (*g)(void);

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

Invocation 1:

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

Invocation 2:

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

Invocation 1 works, while Invocation 2 provides the following error message:

fatal error: error in backend: failed to perform tail call elimination on a call site marked musttail
Exception Code: 0xE0000046
zig: error: clang frontend command failed with exit code 70 (use -v to see invocation)
clang version 18.1.7 (https://github.com/ziglang/zig-bootstrap ec2dca85a340f134d2fcfdc9007e91f9abed6996)
Target: mips-unknown-linux-musl
Thread model: posix
InstalledDir: D:/workspace2/byteboxtest/bytebox
zig: note: diagnostic msg:
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
zig: note: diagnostic msg: C:/Users/looka/AppData/Local/Temp/test-12220b.c
zig: note: diagnostic msg: C:/Users/looka/AppData/Local/Temp/test-12220b.sh
zig: note: diagnostic msg:

********************

Now, my question is how can we pass along this flag to allow Zig to benefit from this?

The relevant LLVM source code is below. The flag is off by default upstream:

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

I'm not sure why it's off by default, as it seems this precedent was set in 2012 in a much earlier version of LLVM.

Where Zig enters the picture here is in the language itself, call sites can be marked .always_tail which internally lowers to this LLVM attribute. Is there a way to pass -mllvm flags along from zig? When using zig cc directly this can be hacked around using the above invocation, but there does not seem to be an equivalent for zig build-* commands. Can you advise on how I should proceed from here?

Thank you very much!

Expected Behavior

Tail calls should optimize out (when possible) for MIPS targets

Metadata

Metadata

Assignees

No one assigned

    Labels

    arch-mips32-bit and 64-bit MIPSbackend-llvmThe LLVM backend outputs an LLVM IR Module.bugObserved behavior contradicts documented or intended behaviorupstreamAn issue with a third party project that Zig uses.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions