Checklist
How often does this bug occurs?
always
Expected behavior
LLVM shouldn't crash when I write a try/catch block.
Actual behavior (suspected bug)
I've been trying out the xtensa backend in LDC (built against LLVM21), but exceptions cause LLVM to crash when any optimisation level is enabled.
If I add a try/catch block, it compiles, but then I add -O1 and a crash appears.
Error logs or terminal output
It's just an ICE, nothing diagnostic.
Steps to reproduce the behavior
I'm using ldc2, built against LLVM21, this code causes the crash:
ldc2 -mtriple=xtensa-none-elf -mattr=+density,+mul16,+mul32,+div32,+windowed -O1 -c
module xtensa_eh_crash;
void external_call(int delegate(const(char)[], int) dg);
int opApply(int delegate(const(char)[], int) dg)
{
int result;
try
{
external_call(dg);
}
catch (Exception e)
{
result = -1;
}
return result;
}
I tested similar code in C++ using ESP-IDF's Clang, and I noticed that the compiler doesn't crash like this, but there's just no EH material in the output binary at all; as if it just dropped it completely or didn't even try. I guess it would abort instantly on throw?
Project release version
LLVM21
System architecture
Intel/AMD 64-bit (modern PC, older Mac)
Operating system
Linux
Operating system version
Debian
Shell
Bash
Additional context
I got Claude to poke at it for a while testing various combinations and trying to dig out any detail, this is what he came up with:
Any function with an invoke + landingpad will trigger this. The key pattern is: invoke that can throw → landing pad with catch clause → resume path.
MIR Evidence
The landing pad block in the crashing function shows undefined registers:
bb.11 (%ir-block.53, landing-pad):
EH_LABEL <mcsymbol >
%17:ar = COPY %33:ar ← %33 never defined anywhere
BEQI %34:ar, 1, %bb.9 ← %34 never defined anywhere
Compare to working backends (x86, ARM) where %33/%34 would be defined by the ISel lowering of the landingpad instruction's {ptr, i32} result.
Likely Fix Location
The Xtensa ISel lowering likely needs to handle ISD::EH_RETURN / exception handling register setup in XtensaTargetLowering::LowerOperation() or similar, defining the exception pointer and selector registers in the landing pad entry. Most backends do this via getExceptionPointerRegister() / getExceptionSelectorRegister() in their TargetLowering class.
Checklist
How often does this bug occurs?
always
Expected behavior
LLVM shouldn't crash when I write a
try/catchblock.Actual behavior (suspected bug)
I've been trying out the xtensa backend in LDC (built against LLVM21), but exceptions cause LLVM to crash when any optimisation level is enabled.
If I add a try/catch block, it compiles, but then I add -O1 and a crash appears.
Error logs or terminal output
It's just an ICE, nothing diagnostic.
Steps to reproduce the behavior
I'm using ldc2, built against LLVM21, this code causes the crash:
I tested similar code in C++ using ESP-IDF's Clang, and I noticed that the compiler doesn't crash like this, but there's just no EH material in the output binary at all; as if it just dropped it completely or didn't even try. I guess it would abort instantly on throw?
Project release version
LLVM21
System architecture
Intel/AMD 64-bit (modern PC, older Mac)
Operating system
Linux
Operating system version
Debian
Shell
Bash
Additional context
I got Claude to poke at it for a while testing various combinations and trying to dig out any detail, this is what he came up with:
Any function with an invoke + landingpad will trigger this. The key pattern is: invoke that can throw → landing pad with catch clause → resume path.
MIR Evidence
The landing pad block in the crashing function shows undefined registers:
Compare to working backends (x86, ARM) where %33/%34 would be defined by the ISel lowering of the landingpad instruction's {ptr, i32} result.
Likely Fix Location
The Xtensa ISel lowering likely needs to handle ISD::EH_RETURN / exception handling register setup in XtensaTargetLowering::LowerOperation() or similar, defining the exception pointer and selector registers in the landing pad entry. Most backends do this via getExceptionPointerRegister() / getExceptionSelectorRegister() in their TargetLowering class.