zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 1b657e6e41bcaf362d1cc9455c17e06e57973554 (tree)
parent e088a17f56a154ecc43c36e8308833d657e6f43e
Author: joachimschmidt557 <joachim.schmidt557@outlook.com>
Date:   Sat, 27 Mar 2021 22:23:14 +0100

stage2 codegen: Make sure function return value is in a callee
preserved register

Diffstat:
Msrc/codegen.zig | 10++++++++++
Mtest/stage2/arm.zig | 41+++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/src/codegen.zig b/src/codegen.zig @@ -2194,6 +2194,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { unreachable; } + switch (info.return_value) { + .register => |reg| { + if (Register.allocIndex(reg) == null) { + // Save function return value in a callee saved register + return try self.copyToNewRegister(&inst.base, info.return_value); + } + }, + else => {}, + } + return info.return_value; } diff --git a/test/stage2/arm.zig b/test/stage2/arm.zig @@ -378,4 +378,45 @@ pub fn addCases(ctx: *TestContext) !void { "", ); } + + { + var case = ctx.exe("save function return values in callee preserved register", linux_arm); + // Here, it is necessary to save the result of bar() into a + // callee preserved register, otherwise it will be overwritten + // by the first parameter to baz. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(foo() == 43); + \\ exit(); + \\} + \\ + \\fn foo() u32 { + \\ return bar() + baz(42); + \\} + \\ + \\fn bar() u32 { + \\ return 1; + \\} + \\ + \\fn baz(x: u32) u32 { + \\ return x; + \\} + \\ + \\fn assert(ok: bool) void { + \\ if (!ok) unreachable; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("svc #0" + \\ : + \\ : [number] "{r7}" (1), + \\ [arg1] "{r0}" (0) + \\ : "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } }