| ... | ... | @@ -409,13 +409,11 @@ fn gen(self: *Self) InnerError!void { |
| 409 | 409 | // The address where to store the return value for the caller is in `.rdi` |
| 410 | 410 | // register which the callee is free to clobber. Therefore, we purposely |
| 411 | 411 | // spill it to stack immediately. |
| 412 | | const ptr_ty = Type.usize; |
| 413 | | const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*)); |
| 414 | | const abi_align = ptr_ty.abiAlignment(self.target.*); |
| 415 | | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); |
| 412 | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset + 8, 8); |
| 416 | 413 | self.next_stack_offset = stack_offset; |
| 417 | 414 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 418 | | try self.genSetStack(ptr_ty, @intCast(i32, stack_offset), MCValue{ .register = .rdi }, .{}); |
| 415 | |
| 416 | try self.genSetStack(Type.usize, @intCast(i32, stack_offset), MCValue{ .register = .rdi }, .{}); |
| 419 | 417 | self.ret_mcv = MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 420 | 418 | log.debug("gen: spilling .rdi to stack at offset {}", .{stack_offset}); |
| 421 | 419 | } |
| ... | ... | @@ -426,11 +424,11 @@ fn gen(self: *Self) InnerError!void { |
| 426 | 424 | .data = undefined, |
| 427 | 425 | }); |
| 428 | 426 | |
| 429 | | // push the callee_preserved_regs that were used |
| 430 | | const backpatch_push_callee_preserved_regs_i = try self.addInst(.{ |
| 431 | | .tag = .push_regs_from_callee_preserved_regs, |
| 432 | | .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), |
| 433 | | .data = .{ .payload = undefined }, // to be backpatched |
| 427 | // Push callee-preserved regs that were used actually in use. |
| 428 | const backpatch_push_callee_preserved_regs = try self.addInst(.{ |
| 429 | .tag = .nop, |
| 430 | .ops = undefined, |
| 431 | .data = undefined, |
| 434 | 432 | }); |
| 435 | 433 | |
| 436 | 434 | try self.genBody(self.air.getMainBody()); |
| ... | ... | @@ -446,31 +444,21 @@ fn gen(self: *Self) InnerError!void { |
| 446 | 444 | self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len); |
| 447 | 445 | } |
| 448 | 446 | |
| 449 | | // calculate the data for callee_preserved_regs to be pushed and popped |
| 450 | | const callee_preserved_regs_payload = blk: { |
| 451 | | var data = Mir.RegsToPushOrPop{ |
| 452 | | .regs = 0, |
| 453 | | .disp = mem.alignForwardGeneric(u32, self.next_stack_offset, 8), |
| 454 | | }; |
| 455 | | var disp = data.disp + 8; |
| 456 | | inline for (callee_preserved_regs) |reg, i| { |
| 457 | | if (self.register_manager.isRegAllocated(reg)) { |
| 458 | | data.regs |= 1 << @intCast(u5, i); |
| 459 | | self.max_end_stack += 8; |
| 460 | | disp += 8; |
| 461 | | } |
| 447 | // Create list of registers to save in the prologue. |
| 448 | // TODO handle register classes |
| 449 | var reg_list: Mir.RegisterList(Register, &callee_preserved_regs) = .{}; |
| 450 | inline for (callee_preserved_regs) |reg| { |
| 451 | if (self.register_manager.isRegAllocated(reg)) { |
| 452 | reg_list.push(reg); |
| 462 | 453 | } |
| 463 | | break :blk try self.addExtra(data); |
| 464 | | }; |
| 454 | } |
| 455 | const saved_regs_stack_space: u32 = reg_list.count() * 8; |
| 465 | 456 | |
| 466 | | const data = self.mir_instructions.items(.data); |
| 467 | | // backpatch the push instruction |
| 468 | | data[backpatch_push_callee_preserved_regs_i].payload = callee_preserved_regs_payload; |
| 469 | | // pop the callee_preserved_regs |
| 470 | | _ = try self.addInst(.{ |
| 471 | | .tag = .pop_regs_from_callee_preserved_regs, |
| 472 | | .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), |
| 473 | | .data = .{ .payload = callee_preserved_regs_payload }, |
| 457 | // Pop saved callee-preserved regs. |
| 458 | const backpatch_pop_callee_preserved_regs = try self.addInst(.{ |
| 459 | .tag = .nop, |
| 460 | .ops = undefined, |
| 461 | .data = undefined, |
| 474 | 462 | }); |
| 475 | 463 | |
| 476 | 464 | _ = try self.addInst(.{ |
| ... | ... | @@ -502,9 +490,11 @@ fn gen(self: *Self) InnerError!void { |
| 502 | 490 | if (self.max_end_stack > math.maxInt(i32)) { |
| 503 | 491 | return self.failSymbol("too much stack used in call parameters", .{}); |
| 504 | 492 | } |
| 505 | | // TODO we should reuse this mechanism to align the stack when calling any function even if |
| 506 | | // we do not pass any args on the stack BUT we still push regs to stack with `push` inst. |
| 507 | | const aligned_stack_end = @intCast(u32, mem.alignForward(self.max_end_stack, self.stack_align)); |
| 493 | |
| 494 | const aligned_stack_end = @intCast( |
| 495 | u32, |
| 496 | mem.alignForward(self.max_end_stack + saved_regs_stack_space, self.stack_align), |
| 497 | ); |
| 508 | 498 | if (aligned_stack_end > 0) { |
| 509 | 499 | self.mir_instructions.set(backpatch_stack_sub, .{ |
| 510 | 500 | .tag = .sub, |
| ... | ... | @@ -516,6 +506,21 @@ fn gen(self: *Self) InnerError!void { |
| 516 | 506 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }), |
| 517 | 507 | .data = .{ .imm = aligned_stack_end }, |
| 518 | 508 | }); |
| 509 | |
| 510 | const save_reg_list = try self.addExtra(Mir.SaveRegisterList{ |
| 511 | .register_list = reg_list.asInt(), |
| 512 | .stack_end = aligned_stack_end, |
| 513 | }); |
| 514 | self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{ |
| 515 | .tag = .push_regs, |
| 516 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), |
| 517 | .data = .{ .payload = save_reg_list }, |
| 518 | }); |
| 519 | self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{ |
| 520 | .tag = .pop_regs, |
| 521 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), |
| 522 | .data = .{ .payload = save_reg_list }, |
| 523 | }); |
| 519 | 524 | } |
| 520 | 525 | } else { |
| 521 | 526 | _ = try self.addInst(.{ |
| ... | ... | @@ -907,6 +912,39 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 907 | 912 | return MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 908 | 913 | } |
| 909 | 914 | |
| 915 | const State = struct { |
| 916 | next_stack_offset: u32, |
| 917 | registers: abi.RegisterManager.TrackedRegisters, |
| 918 | free_registers: abi.RegisterManager.RegisterBitSet, |
| 919 | eflags_inst: ?Air.Inst.Index, |
| 920 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation), |
| 921 | |
| 922 | fn deinit(state: *State, gpa: Allocator) void { |
| 923 | state.stack.deinit(gpa); |
| 924 | } |
| 925 | }; |
| 926 | |
| 927 | fn captureState(self: *Self) !State { |
| 928 | return State{ |
| 929 | .next_stack_offset = self.next_stack_offset, |
| 930 | .registers = self.register_manager.registers, |
| 931 | .free_registers = self.register_manager.free_registers, |
| 932 | .eflags_inst = self.eflags_inst, |
| 933 | .stack = try self.stack.clone(self.gpa), |
| 934 | }; |
| 935 | } |
| 936 | |
| 937 | fn revertState(self: *Self, state: State) void { |
| 938 | self.register_manager.registers = state.registers; |
| 939 | self.eflags_inst = state.eflags_inst; |
| 940 | |
| 941 | self.stack.deinit(self.gpa); |
| 942 | self.stack = state.stack; |
| 943 | |
| 944 | self.next_stack_offset = state.next_stack_offset; |
| 945 | self.register_manager.free_registers = state.free_registers; |
| 946 | } |
| 947 | |
| 910 | 948 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 911 | 949 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 912 | 950 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| ... | ... | @@ -2062,8 +2100,22 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2062 | 2100 | } |
| 2063 | 2101 | |
| 2064 | 2102 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 2065 | | const reg = try self.copyToTmpRegister(index_ty, index); |
| 2066 | | try self.genIntMulComplexOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 2103 | const reg: Register = blk: { |
| 2104 | switch (index) { |
| 2105 | .immediate => |imm| { |
| 2106 | // Optimisation: if index MCValue is an immediate, we can multiply in `comptime` |
| 2107 | // and set the register directly to the scaled offset as an immediate. |
| 2108 | const reg = try self.register_manager.allocReg(null, gp); |
| 2109 | try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size }); |
| 2110 | break :blk reg; |
| 2111 | }, |
| 2112 | else => { |
| 2113 | const reg = try self.copyToTmpRegister(index_ty, index); |
| 2114 | try self.genIntMulComplexOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 2115 | break :blk reg; |
| 2116 | }, |
| 2117 | } |
| 2118 | }; |
| 2067 | 2119 | return reg; |
| 2068 | 2120 | } |
| 2069 | 2121 | |
| ... | ... | @@ -2678,15 +2730,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2678 | 2730 | // movabs does not support indirect register addressing |
| 2679 | 2731 | // so we need an extra register and an extra mov. |
| 2680 | 2732 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); |
| 2681 | | _ = try self.addInst(.{ |
| 2682 | | .tag = .mov, |
| 2683 | | .ops = Mir.Inst.Ops.encode(.{ |
| 2684 | | .reg1 = reg.to64(), |
| 2685 | | .reg2 = tmp_reg.to64(), |
| 2686 | | .flags = 0b10, |
| 2687 | | }), |
| 2688 | | .data = .{ .imm = 0 }, |
| 2689 | | }); |
| 2733 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 2690 | 2734 | }, |
| 2691 | 2735 | else => { |
| 2692 | 2736 | return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size}); |
| ... | ... | @@ -2694,15 +2738,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2694 | 2738 | } |
| 2695 | 2739 | }, |
| 2696 | 2740 | .register => |src_reg| { |
| 2697 | | _ = try self.addInst(.{ |
| 2698 | | .tag = .mov, |
| 2699 | | .ops = Mir.Inst.Ops.encode(.{ |
| 2700 | | .reg1 = reg.to64(), |
| 2701 | | .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), |
| 2702 | | .flags = 0b10, |
| 2703 | | }), |
| 2704 | | .data = .{ .imm = 0 }, |
| 2705 | | }); |
| 2741 | try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0); |
| 2706 | 2742 | }, |
| 2707 | 2743 | .got_load, |
| 2708 | 2744 | .direct_load, |
| ... | ... | @@ -2752,6 +2788,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2752 | 2788 | .data = .{ .imm = 0 }, |
| 2753 | 2789 | }); |
| 2754 | 2790 | |
| 2791 | const new_ptr = MCValue{ .register = addr_reg.to64() }; |
| 2792 | |
| 2755 | 2793 | switch (value) { |
| 2756 | 2794 | .immediate => |imm| { |
| 2757 | 2795 | if (abi_size > 8) { |
| ... | ... | @@ -2790,16 +2828,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2790 | 2828 | .data = .{ .payload = payload }, |
| 2791 | 2829 | }); |
| 2792 | 2830 | }, |
| 2793 | | .register => |reg| { |
| 2794 | | _ = try self.addInst(.{ |
| 2795 | | .tag = .mov, |
| 2796 | | .ops = Mir.Inst.Ops.encode(.{ |
| 2797 | | .reg1 = addr_reg.to64(), |
| 2798 | | .reg2 = reg, |
| 2799 | | .flags = 0b10, |
| 2800 | | }), |
| 2801 | | .data = .{ .imm = 0 }, |
| 2802 | | }); |
| 2831 | .register => { |
| 2832 | return self.store(new_ptr, value, ptr_ty, value_ty); |
| 2803 | 2833 | }, |
| 2804 | 2834 | .got_load, |
| 2805 | 2835 | .direct_load, |
| ... | ... | @@ -2821,37 +2851,18 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2821 | 2851 | }), |
| 2822 | 2852 | .data = .{ .imm = 0 }, |
| 2823 | 2853 | }); |
| 2824 | | _ = try self.addInst(.{ |
| 2825 | | .tag = .mov, |
| 2826 | | .ops = Mir.Inst.Ops.encode(.{ |
| 2827 | | .reg1 = addr_reg.to64(), |
| 2828 | | .reg2 = tmp_reg, |
| 2829 | | .flags = 0b10, |
| 2830 | | }), |
| 2831 | | .data = .{ .imm = 0 }, |
| 2832 | | }); |
| 2833 | | return; |
| 2854 | return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 2834 | 2855 | } |
| 2835 | 2856 | |
| 2836 | | try self.genInlineMemcpy(.{ .register = addr_reg.to64() }, value, .{ .immediate = abi_size }, .{}); |
| 2857 | try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{}); |
| 2837 | 2858 | }, |
| 2838 | 2859 | .stack_offset => { |
| 2839 | 2860 | if (abi_size <= 8) { |
| 2840 | | // TODO this should really be a recursive call |
| 2841 | 2861 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); |
| 2842 | | _ = try self.addInst(.{ |
| 2843 | | .tag = .mov, |
| 2844 | | .ops = Mir.Inst.Ops.encode(.{ |
| 2845 | | .reg1 = addr_reg.to64(), |
| 2846 | | .reg2 = tmp_reg, |
| 2847 | | .flags = 0b10, |
| 2848 | | }), |
| 2849 | | .data = .{ .imm = 0 }, |
| 2850 | | }); |
| 2851 | | return; |
| 2862 | return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 2852 | 2863 | } |
| 2853 | 2864 | |
| 2854 | | try self.genInlineMemcpy(.{ .register = addr_reg.to64() }, value, .{ .immediate = abi_size }, .{}); |
| 2865 | try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{}); |
| 2855 | 2866 | }, |
| 2856 | 2867 | else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}), |
| 2857 | 2868 | } |
| ... | ... | @@ -4503,12 +4514,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4503 | 4514 | } |
| 4504 | 4515 | |
| 4505 | 4516 | // Capture the state of register and stack allocation state so that we can revert to it. |
| 4506 | | const parent_next_stack_offset = self.next_stack_offset; |
| 4507 | | const parent_free_registers = self.register_manager.free_registers; |
| 4508 | | const parent_eflags_inst = self.eflags_inst; |
| 4509 | | var parent_stack = try self.stack.clone(self.gpa); |
| 4510 | | defer parent_stack.deinit(self.gpa); |
| 4511 | | const parent_registers = self.register_manager.registers; |
| 4517 | const saved_state = try self.captureState(); |
| 4512 | 4518 | |
| 4513 | 4519 | try self.branch_stack.append(.{}); |
| 4514 | 4520 | errdefer { |
| ... | ... | @@ -4526,17 +4532,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4526 | 4532 | var saved_then_branch = self.branch_stack.pop(); |
| 4527 | 4533 | defer saved_then_branch.deinit(self.gpa); |
| 4528 | 4534 | |
| 4529 | | self.register_manager.registers = parent_registers; |
| 4530 | | self.eflags_inst = parent_eflags_inst; |
| 4531 | | |
| 4532 | | self.stack.deinit(self.gpa); |
| 4533 | | self.stack = parent_stack; |
| 4534 | | parent_stack = .{}; |
| 4535 | | |
| 4536 | | self.next_stack_offset = parent_next_stack_offset; |
| 4537 | | self.register_manager.free_registers = parent_free_registers; |
| 4535 | self.revertState(saved_state); |
| 4538 | 4536 | |
| 4539 | 4537 | try self.performReloc(reloc); |
| 4538 | |
| 4540 | 4539 | const else_branch = self.branch_stack.addOneAssumeCapacity(); |
| 4541 | 4540 | else_branch.* = .{}; |
| 4542 | 4541 | |
| ... | ... | @@ -5021,12 +5020,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5021 | 5020 | } |
| 5022 | 5021 | |
| 5023 | 5022 | // Capture the state of register and stack allocation state so that we can revert to it. |
| 5024 | | const parent_next_stack_offset = self.next_stack_offset; |
| 5025 | | const parent_free_registers = self.register_manager.free_registers; |
| 5026 | | const parent_eflags_inst = self.eflags_inst; |
| 5027 | | var parent_stack = try self.stack.clone(self.gpa); |
| 5028 | | defer parent_stack.deinit(self.gpa); |
| 5029 | | const parent_registers = self.register_manager.registers; |
| 5023 | const saved_state = try self.captureState(); |
| 5030 | 5024 | |
| 5031 | 5025 | try self.branch_stack.append(.{}); |
| 5032 | 5026 | errdefer { |
| ... | ... | @@ -5044,14 +5038,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5044 | 5038 | var saved_case_branch = self.branch_stack.pop(); |
| 5045 | 5039 | defer saved_case_branch.deinit(self.gpa); |
| 5046 | 5040 | |
| 5047 | | self.register_manager.registers = parent_registers; |
| 5048 | | self.eflags_inst = parent_eflags_inst; |
| 5049 | | self.stack.deinit(self.gpa); |
| 5050 | | self.stack = parent_stack; |
| 5051 | | parent_stack = .{}; |
| 5052 | | |
| 5053 | | self.next_stack_offset = parent_next_stack_offset; |
| 5054 | | self.register_manager.free_registers = parent_free_registers; |
| 5041 | self.revertState(saved_state); |
| 5055 | 5042 | |
| 5056 | 5043 | for (relocs) |reloc| { |
| 5057 | 5044 | try self.performReloc(reloc); |
| ... | ... | @@ -5612,45 +5599,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5612 | 5599 | return self.fail("TODO genSetStack for register for type float with no intrinsics", .{}); |
| 5613 | 5600 | }, |
| 5614 | 5601 | else => { |
| 5615 | | if (!math.isPowerOfTwo(abi_size)) { |
| 5616 | | const reg_lock = self.register_manager.lockReg(reg); |
| 5617 | | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5618 | | |
| 5619 | | const tmp_reg = try self.copyToTmpRegister(ty, mcv); |
| 5620 | | |
| 5621 | | var next_offset = stack_offset; |
| 5622 | | var remainder = abi_size; |
| 5623 | | while (remainder > 0) { |
| 5624 | | const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder)); |
| 5625 | | |
| 5626 | | _ = try self.addInst(.{ |
| 5627 | | .tag = .mov, |
| 5628 | | .ops = Mir.Inst.Ops.encode(.{ |
| 5629 | | .reg1 = base_reg, |
| 5630 | | .reg2 = registerAlias(tmp_reg, nearest_power_of_two), |
| 5631 | | .flags = 0b10, |
| 5632 | | }), |
| 5633 | | .data = .{ .imm = @bitCast(u32, -next_offset) }, |
| 5634 | | }); |
| 5635 | | |
| 5636 | | if (nearest_power_of_two > 1) { |
| 5637 | | try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }); |
| 5638 | | } |
| 5639 | | |
| 5640 | | remainder -= nearest_power_of_two; |
| 5641 | | next_offset -= nearest_power_of_two; |
| 5642 | | } |
| 5643 | | } else { |
| 5644 | | _ = try self.addInst(.{ |
| 5645 | | .tag = .mov, |
| 5646 | | .ops = Mir.Inst.Ops.encode(.{ |
| 5647 | | .reg1 = base_reg, |
| 5648 | | .reg2 = registerAlias(reg, @intCast(u32, abi_size)), |
| 5649 | | .flags = 0b10, |
| 5650 | | }), |
| 5651 | | .data = .{ .imm = @bitCast(u32, -stack_offset) }, |
| 5652 | | }); |
| 5653 | | } |
| 5602 | try self.genInlineMemcpyRegisterRegister(ty, base_reg, reg, stack_offset); |
| 5654 | 5603 | }, |
| 5655 | 5604 | } |
| 5656 | 5605 | }, |
| ... | ... | @@ -5685,6 +5634,66 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5685 | 5634 | } |
| 5686 | 5635 | } |
| 5687 | 5636 | |
| 5637 | /// Like `genInlineMemcpy` but copies value from a register to an address via dereferencing |
| 5638 | /// of destination register. |
| 5639 | /// Boils down to MOV r/m64, r64. |
| 5640 | fn genInlineMemcpyRegisterRegister( |
| 5641 | self: *Self, |
| 5642 | ty: Type, |
| 5643 | dst_reg: Register, |
| 5644 | src_reg: Register, |
| 5645 | offset: i32, |
| 5646 | ) InnerError!void { |
| 5647 | assert(dst_reg.size() == 64); |
| 5648 | |
| 5649 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 5650 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5651 | |
| 5652 | const src_reg_lock = self.register_manager.lockReg(src_reg); |
| 5653 | defer if (src_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5654 | |
| 5655 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 5656 | |
| 5657 | if (!math.isPowerOfTwo(abi_size)) { |
| 5658 | const tmp_reg = try self.copyToTmpRegister(ty, .{ .register = src_reg }); |
| 5659 | |
| 5660 | var next_offset = offset; |
| 5661 | var remainder = abi_size; |
| 5662 | while (remainder > 0) { |
| 5663 | const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder)); |
| 5664 | |
| 5665 | _ = try self.addInst(.{ |
| 5666 | .tag = .mov, |
| 5667 | .ops = Mir.Inst.Ops.encode(.{ |
| 5668 | .reg1 = dst_reg, |
| 5669 | .reg2 = registerAlias(tmp_reg, nearest_power_of_two), |
| 5670 | .flags = 0b10, |
| 5671 | }), |
| 5672 | .data = .{ .imm = @bitCast(u32, -next_offset) }, |
| 5673 | }); |
| 5674 | |
| 5675 | if (nearest_power_of_two > 1) { |
| 5676 | try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ |
| 5677 | .immediate = nearest_power_of_two * 8, |
| 5678 | }); |
| 5679 | } |
| 5680 | |
| 5681 | remainder -= nearest_power_of_two; |
| 5682 | next_offset -= nearest_power_of_two; |
| 5683 | } |
| 5684 | } else { |
| 5685 | _ = try self.addInst(.{ |
| 5686 | .tag = .mov, |
| 5687 | .ops = Mir.Inst.Ops.encode(.{ |
| 5688 | .reg1 = dst_reg, |
| 5689 | .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), |
| 5690 | .flags = 0b10, |
| 5691 | }), |
| 5692 | .data = .{ .imm = @bitCast(u32, -offset) }, |
| 5693 | }); |
| 5694 | } |
| 5695 | } |
| 5696 | |
| 5688 | 5697 | const InlineMemcpyOpts = struct { |
| 5689 | 5698 | source_stack_base: ?Register = null, |
| 5690 | 5699 | dest_stack_base: ?Register = null, |