Commit 91969ad908

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-08-12 20:29:48
stage2 ARM: Fix tracking of function return values
1 parent 4c51565
Changed files (1)
src
arch
src/arch/arm/CodeGen.zig
@@ -247,6 +247,31 @@ const BigTomb = struct {
             log.debug("%{d} => {}", .{ bt.inst, result });
             const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
             branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
+
+            switch (result) {
+                .register => |reg| {
+                    // In some cases (such as bitcast), an operand
+                    // may be the same MCValue as the result. If
+                    // that operand died and was a register, it
+                    // was freed by processDeath. We have to
+                    // "re-allocate" the register.
+                    if (bt.function.register_manager.isRegFree(reg)) {
+                        bt.function.register_manager.getRegAssumeFree(reg, bt.inst);
+                    }
+                },
+                .register_c_flag,
+                .register_v_flag,
+                => |reg| {
+                    if (bt.function.register_manager.isRegFree(reg)) {
+                        bt.function.register_manager.getRegAssumeFree(reg, bt.inst);
+                    }
+                    bt.function.cpsr_flags_inst = bt.inst;
+                },
+                .cpsr_flags => {
+                    bt.function.cpsr_flags_inst = bt.inst;
+                },
+                else => {},
+            }
         }
         bt.function.finishAirBookkeeping();
     }
@@ -3524,7 +3549,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
         try self.register_manager.getReg(reg, null);
     }
 
-    if (info.return_value == .stack_offset) {
+    // If returning by reference, r0 will contain the address of where
+    // to put the result into. In that case, make sure that r0 remains
+    // untouched by the parameter passing code
+    const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {
         log.debug("airCall: return by reference", .{});
         const ret_ty = fn_ty.fnReturnType();
         const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
@@ -3540,7 +3568,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
         try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset });
 
         info.return_value = .{ .stack_offset = stack_offset };
-    }
+
+        break :blk self.register_manager.lockRegAssumeUnused(.r0);
+    } else null;
+    defer if (r0_lock) |reg| self.register_manager.unlockReg(reg);
 
     // Make space for the arguments passed via the stack
     self.max_end_stack += info.stack_byte_count;