| ... | @@ -247,6 +247,31 @@ const BigTomb = struct { | ... | @@ -247,6 +247,31 @@ const BigTomb = struct { |
| 247 | log.debug("%{d} => {}", .{ bt.inst, result }); | 247 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 248 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; | 248 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 249 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); | 249 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); |
| | 250 | |
| | 251 | switch (result) { |
| | 252 | .register => |reg| { |
| | 253 | // In some cases (such as bitcast), an operand |
| | 254 | // may be the same MCValue as the result. If |
| | 255 | // that operand died and was a register, it |
| | 256 | // was freed by processDeath. We have to |
| | 257 | // "re-allocate" the register. |
| | 258 | if (bt.function.register_manager.isRegFree(reg)) { |
| | 259 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); |
| | 260 | } |
| | 261 | }, |
| | 262 | .register_c_flag, |
| | 263 | .register_v_flag, |
| | 264 | => |reg| { |
| | 265 | if (bt.function.register_manager.isRegFree(reg)) { |
| | 266 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); |
| | 267 | } |
| | 268 | bt.function.cpsr_flags_inst = bt.inst; |
| | 269 | }, |
| | 270 | .cpsr_flags => { |
| | 271 | bt.function.cpsr_flags_inst = bt.inst; |
| | 272 | }, |
| | 273 | else => {}, |
| | 274 | } |
| 250 | } | 275 | } |
| 251 | bt.function.finishAirBookkeeping(); | 276 | bt.function.finishAirBookkeeping(); |
| 252 | } | 277 | } |
| ... | @@ -3524,7 +3549,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3524,7 +3549,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3524 | try self.register_manager.getReg(reg, null); | 3549 | try self.register_manager.getReg(reg, null); |
| 3525 | } | 3550 | } |
| 3526 | | 3551 | |
| 3527 | if (info.return_value == .stack_offset) { | 3552 | // If returning by reference, r0 will contain the address of where |
| | 3553 | // to put the result into. In that case, make sure that r0 remains |
| | 3554 | // untouched by the parameter passing code |
| | 3555 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 3528 | log.debug("airCall: return by reference", .{}); | 3556 | log.debug("airCall: return by reference", .{}); |
| 3529 | const ret_ty = fn_ty.fnReturnType(); | 3557 | const ret_ty = fn_ty.fnReturnType(); |
| 3530 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 3558 | 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. | ... | @@ -3540,7 +3568,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3540 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); | 3568 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); |
| 3541 | | 3569 | |
| 3542 | info.return_value = .{ .stack_offset = stack_offset }; | 3570 | info.return_value = .{ .stack_offset = stack_offset }; |
| 3543 | } | 3571 | |
| | 3572 | break :blk self.register_manager.lockRegAssumeUnused(.r0); |
| | 3573 | } else null; |
| | 3574 | defer if (r0_lock) |reg| self.register_manager.unlockReg(reg); |
| 3544 | | 3575 | |
| 3545 | // Make space for the arguments passed via the stack | 3576 | // Make space for the arguments passed via the stack |
| 3546 | self.max_end_stack += info.stack_byte_count; | 3577 | self.max_end_stack += info.stack_byte_count; |