zig icon indicating copy to clipboard operation
zig copied to clipboard

noreturn functions save registers

Open Uthedris opened this issue 7 months ago • 4 comments

Zig Version

0.15.0-dev.558+9279ff888

Steps to Reproduce and Observed Behavior

Compile a function with a return type of noreturn. The generated code saves various registers.

Tested on compiler for rp2350 arm and riscv.

Expected Behavior

noreturn functions should not save registers.

Since the function cannot return, there is no reason to save existing registers, so doing so just wastes stack space. This is especially a problem when writing code for small embedded processors or other situation where stack space is at a premium.

Uthedris avatar May 21 '25 20:05 Uthedris

Please include an example of what you mean in the issue description.

alexrp avatar May 28 '25 12:05 alexrp

When compiling the function:

fn taskA() noreturn {
    while (true) {
        std.log.debug("{s}TaskA -- Top of loop -- waiting for event", .{scheduler.platform.debugCore()});
        scheduler.waitForEvent(0x01, true);
        std.log.debug("{s}TaskA -- Send Event to charlie", .{scheduler.platform.debugCore()});
        scheduler.signalEvent(.charlie, 0x01);
    }
}

We get:

420011c4 <main_esp32_c3.taskA>:
420011c4:	7139                	addi	sp,sp,-64
420011c6:	de06                	sw	ra,60(sp)
420011c8:	dc22                	sw	s0,56(sp)
420011ca:	da26                	sw	s1,52(sp)
420011cc:	d84a                	sw	s2,48(sp)
420011ce:	d64e                	sw	s3,44(sp)
420011d0:	d452                	sw	s4,40(sp)
420011d2:	d256                	sw	s5,36(sp)
420011d4:	d05a                	sw	s6,32(sp)
420011d6:	ce5e                	sw	s7,28(sp)
420011d8:	cc62                	sw	s8,24(sp)
420011da:	ca66                	sw	s9,20(sp)
420011dc:	c86a                	sw	s10,16(sp)
420011de:	c66e                	sw	s11,12(sp)
420011e0:	0080                	addi	s0,sp,64
420011e2:	4d01                	li	s10,0
420011e4:	6ac1                	lui	s5,0x10
420011e6:	1afd                	addi	s5,s5,-1 # ffff <.Lline_table_start0+0xadfc>
420011e8:	3fc80537          	lui	a0,0x3fc80
420011ec:	52452903          	lw	s2,1316(a0) # 3fc80524 <.L__unnamed_1+0x4>
420011f0:	52052d83          	lw	s11,1312(a0)
420011f4:	3fc80b37          	lui	s6,0x3fc80
420011f8:	25ab0b13          	addi	s6,s6,602 # 3fc8025a <__anon_6056>
.
.
.

All those saved registers are unnecessary. The function is "noreturn" so what are the registers saved for. Normally they would be restored on return, but that will never happen.

Uthedris avatar May 28 '25 13:05 Uthedris

Well, we set the noreturn LLVM IR attribute on functions that return noreturn in Zig, so this one's on LLVM.

alexrp avatar May 28 '25 14:05 alexrp

That seems to be it.

Just for everyones reference, this issue is addressed in llvm's bug report 55317

Uthedris avatar May 28 '25 14:05 Uthedris