Commit 1b657e6e41

joachimschmidt557 <joachim.schmidt557@outlook.com>
2021-03-27 22:23:14
stage2 codegen: Make sure function return value is in a callee preserved register
1 parent e088a17
Changed files (2)
src
test
stage2
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;
         }
 
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;
+            \\}
+        ,
+            "",
+        );
+    }
 }