| ... | ... | @@ -666,10 +666,11 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 666 | 666 | if (current_maybe_inst) |current_inst| { |
| 667 | 667 | try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst); |
| 668 | 668 | } |
| 669 | | { |
| 669 | blk: { |
| 670 | const inst = target_maybe_inst orelse break :blk; |
| 670 | 671 | const reg = RegisterManager.regAtTrackedIndex(@intCast(index)); |
| 671 | 672 | self.register_manager.freeReg(reg); |
| 672 | | self.register_manager.getRegAssumeFree(reg, target_maybe_inst); |
| 673 | self.register_manager.getRegAssumeFree(reg, inst); |
| 673 | 674 | } |
| 674 | 675 | if (target_maybe_inst) |target_inst| { |
| 675 | 676 | self.inst_tracking.getPtr(target_inst).?.trackMaterialize( |
| ... | ... | @@ -2272,13 +2273,10 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2272 | 2273 | }, |
| 2273 | 2274 | }); |
| 2274 | 2275 | |
| 2275 | | const add_result_frame: FrameAddr = .{ |
| 2276 | | .index = offset.index, |
| 2277 | | .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))), |
| 2278 | | }; |
| 2279 | | try self.genSetStack( |
| 2276 | try self.genSetMem( |
| 2277 | .{ .frame = offset.index }, |
| 2278 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))), |
| 2280 | 2279 | lhs_ty, |
| 2281 | | add_result_frame, |
| 2282 | 2280 | add_result, |
| 2283 | 2281 | ); |
| 2284 | 2282 | |
| ... | ... | @@ -2289,14 +2287,10 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2289 | 2287 | .{ .register = add_result_reg }, |
| 2290 | 2288 | lhs_ty, |
| 2291 | 2289 | ); |
| 2292 | | |
| 2293 | | const overflow_frame: FrameAddr = .{ |
| 2294 | | .index = offset.index, |
| 2295 | | .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), |
| 2296 | | }; |
| 2297 | | try self.genSetStack( |
| 2290 | try self.genSetMem( |
| 2291 | .{ .frame = offset.index }, |
| 2292 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), |
| 2298 | 2293 | Type.u1, |
| 2299 | | overflow_frame, |
| 2300 | 2294 | overflow_mcv, |
| 2301 | 2295 | ); |
| 2302 | 2296 | |
| ... | ... | @@ -2340,14 +2334,16 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2340 | 2334 | |
| 2341 | 2335 | const tuple_ty = self.typeOfIndex(inst); |
| 2342 | 2336 | |
| 2343 | | // TODO: optimization, set this to true. needs the other struct access stuff to support |
| 2344 | | // accessing registers. |
| 2345 | | const result_mcv = try self.allocRegOrMem(inst, false); |
| 2337 | const result_mcv = try self.allocRegOrMem(inst, true); |
| 2346 | 2338 | |
| 2347 | 2339 | const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu)); |
| 2348 | 2340 | const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu)); |
| 2349 | 2341 | |
| 2350 | | try self.genSetStack(lhs_ty, result_mcv.offset(result_off).load_frame, dest); |
| 2342 | try self.genCopy( |
| 2343 | lhs_ty, |
| 2344 | result_mcv.offset(result_off), |
| 2345 | dest, |
| 2346 | ); |
| 2351 | 2347 | |
| 2352 | 2348 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 2353 | 2349 | if (int_info.signedness == .unsigned) { |
| ... | ... | @@ -2385,9 +2381,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2385 | 2381 | lhs_ty, |
| 2386 | 2382 | ); |
| 2387 | 2383 | |
| 2388 | | try self.genSetStack( |
| 2384 | try self.genCopy( |
| 2389 | 2385 | lhs_ty, |
| 2390 | | result_mcv.offset(overflow_off).load_frame, |
| 2386 | result_mcv.offset(overflow_off), |
| 2391 | 2387 | overflow_mcv, |
| 2392 | 2388 | ); |
| 2393 | 2389 | |
| ... | ... | @@ -2668,9 +2664,9 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2668 | 2664 | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu)); |
| 2669 | 2665 | const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); |
| 2670 | 2666 | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); |
| 2671 | | try self.genSetStack(pl_ty, .{ .index = frame_index, .off = pl_off }, .undef); |
| 2667 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef); |
| 2672 | 2668 | const operand = try self.resolveInst(ty_op.operand); |
| 2673 | | try self.genSetStack(err_ty, .{ .index = frame_index, .off = err_off }, operand); |
| 2669 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand); |
| 2674 | 2670 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2675 | 2671 | }; |
| 2676 | 2672 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -2854,7 +2850,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2854 | 2850 | switch (array_mcv) { |
| 2855 | 2851 | .register => { |
| 2856 | 2852 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, zcu)); |
| 2857 | | try self.genSetStack(array_ty, .{ .index = frame_index }, array_mcv); |
| 2853 | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv); |
| 2858 | 2854 | try self.genSetReg(Type.usize, addr_reg, .{ .lea_frame = .{ .index = frame_index } }); |
| 2859 | 2855 | }, |
| 2860 | 2856 | .load_frame => |frame_addr| { |
| ... | ... | @@ -2891,9 +2887,48 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2891 | 2887 | } |
| 2892 | 2888 | |
| 2893 | 2889 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2890 | const zcu = self.bin_file.comp.module.?; |
| 2894 | 2891 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2895 | 2892 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2896 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}); |
| 2893 | |
| 2894 | const result = result: { |
| 2895 | const elem_ptr_ty = self.typeOfIndex(inst); |
| 2896 | const base_ptr_ty = self.typeOf(extra.lhs); |
| 2897 | |
| 2898 | const base_ptr_mcv = try self.resolveInst(extra.lhs); |
| 2899 | const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) { |
| 2900 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2901 | else => null, |
| 2902 | }; |
| 2903 | defer if (base_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2904 | |
| 2905 | if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) { |
| 2906 | break :result if (self.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv)) |
| 2907 | base_ptr_mcv |
| 2908 | else |
| 2909 | try self.copyToNewRegister(inst, base_ptr_mcv); |
| 2910 | } |
| 2911 | |
| 2912 | const elem_ty = base_ptr_ty.elemType2(zcu); |
| 2913 | const elem_abi_size = elem_ty.abiSize(zcu); |
| 2914 | const index_ty = self.typeOf(extra.rhs); |
| 2915 | const index_mcv = try self.resolveInst(extra.rhs); |
| 2916 | const index_lock: ?RegisterLock = switch (index_mcv) { |
| 2917 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2918 | else => null, |
| 2919 | }; |
| 2920 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 2921 | |
| 2922 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size); |
| 2923 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2924 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2925 | |
| 2926 | if (true) return self.fail("TODO: airPtrElemPtr", .{}); |
| 2927 | |
| 2928 | // TODO: something is breaking here dunno |
| 2929 | |
| 2930 | break :result try self.binOp(.ptr_add, base_ptr_mcv, base_ptr_ty, .{ .register = offset_reg }, base_ptr_ty); |
| 2931 | }; |
| 2897 | 2932 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 2898 | 2933 | } |
| 2899 | 2934 | |
| ... | ... | @@ -4563,22 +4598,18 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 4563 | 4598 | .off = -dst_reg_off.off, |
| 4564 | 4599 | } }, |
| 4565 | 4600 | }), |
| 4566 | | .indirect => |ro| { |
| 4567 | | const src_reg = try self.copyToTmpRegister(ty, src_mcv); |
| 4568 | | |
| 4569 | | _ = try self.addInst(.{ |
| 4570 | | .tag = .pseudo, |
| 4571 | | .ops = .pseudo_store_rm, |
| 4572 | | .data = .{ .rm = .{ |
| 4573 | | .r = src_reg, |
| 4574 | | .m = .{ |
| 4575 | | .base = .{ .reg = ro.reg }, |
| 4576 | | .mod = .{ .rm = .{ .disp = ro.off, .size = self.memSize(ty) } }, |
| 4577 | | }, |
| 4578 | | } }, |
| 4579 | | }); |
| 4580 | | }, |
| 4581 | | .load_frame => |frame| return self.genSetStack(ty, frame, src_mcv), |
| 4601 | .indirect => |reg_off| try self.genSetMem( |
| 4602 | .{ .reg = reg_off.reg }, |
| 4603 | reg_off.off, |
| 4604 | ty, |
| 4605 | src_mcv, |
| 4606 | ), |
| 4607 | .load_frame => |frame_addr| try self.genSetMem( |
| 4608 | .{ .frame = frame_addr.index }, |
| 4609 | frame_addr.off, |
| 4610 | ty, |
| 4611 | src_mcv, |
| 4612 | ), |
| 4582 | 4613 | .memory => return self.fail("TODO: genCopy memory", .{}), |
| 4583 | 4614 | .register_pair => |dst_regs| { |
| 4584 | 4615 | const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) { |
| ... | ... | @@ -4617,88 +4648,6 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 4617 | 4648 | } |
| 4618 | 4649 | } |
| 4619 | 4650 | |
| 4620 | | fn genSetStack( |
| 4621 | | self: *Self, |
| 4622 | | ty: Type, |
| 4623 | | frame: FrameAddr, |
| 4624 | | src_mcv: MCValue, |
| 4625 | | ) InnerError!void { |
| 4626 | | const zcu = self.bin_file.comp.module.?; |
| 4627 | | const abi_size: u32 = @intCast(ty.abiSize(zcu)); |
| 4628 | | |
| 4629 | | switch (src_mcv) { |
| 4630 | | .none => return, |
| 4631 | | .dead => unreachable, |
| 4632 | | .undef => { |
| 4633 | | if (!self.wantSafety()) return; |
| 4634 | | try self.genSetStack(ty, frame, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); |
| 4635 | | }, |
| 4636 | | .immediate, |
| 4637 | | .lea_frame, |
| 4638 | | => { |
| 4639 | | // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with |
| 4640 | | // a register allocation. |
| 4641 | | const reg, const reg_lock = try self.allocReg(); |
| 4642 | | defer self.register_manager.unlockReg(reg_lock); |
| 4643 | | |
| 4644 | | try self.genSetReg(ty, reg, src_mcv); |
| 4645 | | |
| 4646 | | return self.genSetStack(ty, frame, .{ .register = reg }); |
| 4647 | | }, |
| 4648 | | .register => |reg| { |
| 4649 | | switch (abi_size) { |
| 4650 | | 1, 2, 4, 8 => { |
| 4651 | | _ = try self.addInst(.{ |
| 4652 | | .tag = .pseudo, |
| 4653 | | .ops = .pseudo_store_rm, |
| 4654 | | .data = .{ .rm = .{ |
| 4655 | | .r = reg, |
| 4656 | | .m = .{ |
| 4657 | | .base = .{ .frame = frame.index }, |
| 4658 | | .mod = .{ |
| 4659 | | .rm = .{ |
| 4660 | | .size = self.memSize(ty), |
| 4661 | | .disp = frame.off, |
| 4662 | | }, |
| 4663 | | }, |
| 4664 | | }, |
| 4665 | | } }, |
| 4666 | | }); |
| 4667 | | }, |
| 4668 | | else => unreachable, // register can hold a max of 8 bytes |
| 4669 | | } |
| 4670 | | }, |
| 4671 | | .register_pair => |pair| { |
| 4672 | | var part_disp: i32 = frame.off; |
| 4673 | | for (try self.splitType(ty), pair) |src_ty, src_reg| { |
| 4674 | | try self.genSetStack( |
| 4675 | | src_ty, |
| 4676 | | .{ .index = frame.index, .off = part_disp }, |
| 4677 | | .{ .register = src_reg }, |
| 4678 | | ); |
| 4679 | | part_disp += @intCast(src_ty.abiSize(zcu)); |
| 4680 | | } |
| 4681 | | }, |
| 4682 | | .load_frame, |
| 4683 | | .indirect, |
| 4684 | | .load_symbol, |
| 4685 | | => { |
| 4686 | | if (abi_size <= 8) { |
| 4687 | | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 4688 | | return self.genSetStack(ty, frame, .{ .register = reg }); |
| 4689 | | } |
| 4690 | | |
| 4691 | | try self.genInlineMemcpy( |
| 4692 | | .{ .lea_frame = frame }, |
| 4693 | | src_mcv.address(), |
| 4694 | | .{ .immediate = abi_size }, |
| 4695 | | ); |
| 4696 | | }, |
| 4697 | | .air_ref => |ref| try self.genSetStack(ty, frame, try self.resolveInst(ref)), |
| 4698 | | else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_mcv)}), |
| 4699 | | } |
| 4700 | | } |
| 4701 | | |
| 4702 | 4651 | fn genInlineMemcpy( |
| 4703 | 4652 | self: *Self, |
| 4704 | 4653 | dst_ptr: MCValue, |
| ... | ... | @@ -4805,6 +4754,86 @@ fn genInlineMemcpy( |
| 4805 | 4754 | }); |
| 4806 | 4755 | } |
| 4807 | 4756 | |
| 4757 | fn genInlineMemset( |
| 4758 | self: *Self, |
| 4759 | dst_ptr: MCValue, |
| 4760 | src_value: MCValue, |
| 4761 | len: MCValue, |
| 4762 | ) !void { |
| 4763 | const regs = try self.register_manager.allocRegs(3, .{null} ** 3, tp); |
| 4764 | const locks = self.register_manager.lockRegsAssumeUnused(3, regs); |
| 4765 | defer for (locks) |lock| self.register_manager.unlockReg(lock); |
| 4766 | |
| 4767 | const count = regs[0]; |
| 4768 | const src = regs[1]; |
| 4769 | const dst = regs[2]; |
| 4770 | |
| 4771 | try self.genSetReg(Type.usize, count, len); |
| 4772 | try self.genSetReg(Type.usize, src, src_value); |
| 4773 | try self.genSetReg(Type.usize, dst, dst_ptr); |
| 4774 | |
| 4775 | // sb src, 0(dst) |
| 4776 | const first_inst = try self.addInst(.{ |
| 4777 | .tag = .sb, |
| 4778 | .ops = .rri, |
| 4779 | .data = .{ |
| 4780 | .i_type = .{ |
| 4781 | .rd = dst, |
| 4782 | .rs1 = src, |
| 4783 | .imm12 = Immediate.s(0), |
| 4784 | }, |
| 4785 | }, |
| 4786 | }); |
| 4787 | |
| 4788 | // dec count by 1 |
| 4789 | _ = try self.addInst(.{ |
| 4790 | .tag = .addi, |
| 4791 | .ops = .rri, |
| 4792 | .data = .{ |
| 4793 | .i_type = .{ |
| 4794 | .rd = count, |
| 4795 | .rs1 = count, |
| 4796 | .imm12 = Immediate.s(-1), |
| 4797 | }, |
| 4798 | }, |
| 4799 | }); |
| 4800 | |
| 4801 | // branch if count is 0 |
| 4802 | _ = try self.addInst(.{ |
| 4803 | .tag = .beq, |
| 4804 | .ops = .rr_inst, |
| 4805 | .data = .{ |
| 4806 | .b_type = .{ |
| 4807 | .inst = @intCast(self.mir_instructions.len + 4), // points after the last inst |
| 4808 | .rs1 = count, |
| 4809 | .rs2 = .zero, |
| 4810 | }, |
| 4811 | }, |
| 4812 | }); |
| 4813 | |
| 4814 | // increment the pointers |
| 4815 | _ = try self.addInst(.{ |
| 4816 | .tag = .addi, |
| 4817 | .ops = .rri, |
| 4818 | .data = .{ |
| 4819 | .i_type = .{ |
| 4820 | .rd = dst, |
| 4821 | .rs1 = dst, |
| 4822 | .imm12 = Immediate.s(1), |
| 4823 | }, |
| 4824 | }, |
| 4825 | }); |
| 4826 | |
| 4827 | // jump back to start of loop |
| 4828 | _ = try self.addInst(.{ |
| 4829 | .tag = .pseudo, |
| 4830 | .ops = .pseudo_j, |
| 4831 | .data = .{ |
| 4832 | .inst = first_inst, |
| 4833 | }, |
| 4834 | }); |
| 4835 | } |
| 4836 | |
| 4808 | 4837 | /// Sets the value of `src_mcv` into `reg`. Assumes you have a lock on it. |
| 4809 | 4838 | fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!void { |
| 4810 | 4839 | const zcu = self.bin_file.comp.module.?; |
| ... | ... | @@ -4965,7 +4994,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 4965 | 4994 | 2 => .lh, |
| 4966 | 4995 | 4 => .lw, |
| 4967 | 4996 | 8 => .ld, |
| 4968 | | else => return self.fail("TODO: genSetReg for size {d}", .{abi_size}), |
| 4997 | else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}), |
| 4969 | 4998 | }; |
| 4970 | 4999 | |
| 4971 | 5000 | _ = try self.addInst(.{ |
| ... | ... | @@ -4998,6 +5027,126 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 4998 | 5027 | } |
| 4999 | 5028 | } |
| 5000 | 5029 | |
| 5030 | fn genSetMem( |
| 5031 | self: *Self, |
| 5032 | base: Memory.Base, |
| 5033 | disp: i32, |
| 5034 | ty: Type, |
| 5035 | src_mcv: MCValue, |
| 5036 | ) InnerError!void { |
| 5037 | const mod = self.bin_file.comp.module.?; |
| 5038 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 5039 | const dst_ptr_mcv: MCValue = switch (base) { |
| 5040 | .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, |
| 5041 | .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } }, |
| 5042 | .reloc => |base_symbol| .{ .lea_symbol = .{ .sym = base_symbol.sym_index, .off = disp } }, |
| 5043 | }; |
| 5044 | switch (src_mcv) { |
| 5045 | .none, |
| 5046 | .unreach, |
| 5047 | .dead, |
| 5048 | .reserved_frame, |
| 5049 | => unreachable, |
| 5050 | .undef => try self.genInlineMemset( |
| 5051 | dst_ptr_mcv, |
| 5052 | src_mcv, |
| 5053 | .{ .immediate = abi_size }, |
| 5054 | ), |
| 5055 | |
| 5056 | .register_offset, |
| 5057 | .memory, |
| 5058 | .indirect, |
| 5059 | .load_frame, |
| 5060 | .lea_frame, |
| 5061 | .load_symbol, |
| 5062 | .lea_symbol, |
| 5063 | => switch (abi_size) { |
| 5064 | 0 => {}, |
| 5065 | 1, 2, 4, 8 => { |
| 5066 | const src_reg = try self.copyToTmpRegister(ty, src_mcv); |
| 5067 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 5068 | defer self.register_manager.unlockReg(src_lock); |
| 5069 | |
| 5070 | try self.genSetMem(base, disp, ty, .{ .register = src_reg }); |
| 5071 | }, |
| 5072 | else => try self.genInlineMemcpy( |
| 5073 | dst_ptr_mcv, |
| 5074 | src_mcv.address(), |
| 5075 | .{ .immediate = abi_size }, |
| 5076 | ), |
| 5077 | }, |
| 5078 | .register => |reg| { |
| 5079 | const mem_size = switch (base) { |
| 5080 | .frame => |base_fi| mem_size: { |
| 5081 | assert(disp >= 0); |
| 5082 | const frame_abi_size = self.frame_allocs.items(.abi_size)[@intFromEnum(base_fi)]; |
| 5083 | const frame_spill_pad = self.frame_allocs.items(.spill_pad)[@intFromEnum(base_fi)]; |
| 5084 | assert(frame_abi_size - frame_spill_pad - disp >= abi_size); |
| 5085 | break :mem_size if (frame_abi_size - frame_spill_pad - disp == abi_size) |
| 5086 | frame_abi_size |
| 5087 | else |
| 5088 | abi_size; |
| 5089 | }, |
| 5090 | else => abi_size, |
| 5091 | }; |
| 5092 | const src_size = math.ceilPowerOfTwoAssert(u32, abi_size); |
| 5093 | const src_align = Alignment.fromNonzeroByteUnits(math.ceilPowerOfTwoAssert(u32, src_size)); |
| 5094 | if (src_size > mem_size) { |
| 5095 | const frame_index = try self.allocFrameIndex(FrameAlloc.init(.{ |
| 5096 | .size = src_size, |
| 5097 | .alignment = src_align, |
| 5098 | })); |
| 5099 | const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } }; |
| 5100 | _ = try self.addInst(.{ |
| 5101 | .tag = .pseudo, |
| 5102 | .ops = .pseudo_store_rm, |
| 5103 | .data = .{ |
| 5104 | .rm = .{ .r = reg, .m = .{ |
| 5105 | .base = .{ .frame = frame_index }, |
| 5106 | .mod = .{ .rm = .{ |
| 5107 | .size = Memory.Size.fromByteSize(src_size), |
| 5108 | } }, |
| 5109 | } }, |
| 5110 | }, |
| 5111 | }); |
| 5112 | try self.genSetMem(base, disp, ty, frame_mcv); |
| 5113 | try self.freeValue(frame_mcv); |
| 5114 | } else _ = try self.addInst(.{ |
| 5115 | .tag = .pseudo, |
| 5116 | .ops = .pseudo_store_rm, |
| 5117 | .data = .{ .rm = .{ |
| 5118 | .r = reg, |
| 5119 | .m = .{ |
| 5120 | .base = base, |
| 5121 | .mod = .{ .rm = .{ |
| 5122 | .size = self.memSize(ty), |
| 5123 | .disp = disp, |
| 5124 | } }, |
| 5125 | }, |
| 5126 | } }, |
| 5127 | }); |
| 5128 | }, |
| 5129 | .register_pair => |src_regs| { |
| 5130 | var part_disp: i32 = disp; |
| 5131 | for (try self.splitType(ty), src_regs) |src_ty, src_reg| { |
| 5132 | try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }); |
| 5133 | part_disp += @intCast(src_ty.abiSize(mod)); |
| 5134 | } |
| 5135 | }, |
| 5136 | .immediate => { |
| 5137 | // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with |
| 5138 | // a register allocation. |
| 5139 | const reg, const reg_lock = try self.allocReg(); |
| 5140 | defer self.register_manager.unlockReg(reg_lock); |
| 5141 | |
| 5142 | try self.genSetReg(ty, reg, src_mcv); |
| 5143 | |
| 5144 | return self.genSetMem(base, disp, ty, .{ .register = reg }); |
| 5145 | }, |
| 5146 | .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref)), |
| 5147 | } |
| 5148 | } |
| 5149 | |
| 5001 | 5150 | fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5002 | 5151 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 5003 | 5152 | const result = result: { |
| ... | ... | @@ -5099,13 +5248,83 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr |
| 5099 | 5248 | } |
| 5100 | 5249 | |
| 5101 | 5250 | fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 5102 | | _ = inst; |
| 5103 | | if (safety) { |
| 5104 | | // TODO if the value is undef, write 0xaa bytes to dest |
| 5105 | | } else { |
| 5106 | | // TODO if the value is undef, don't lower this instruction |
| 5251 | const zcu = self.bin_file.comp.module.?; |
| 5252 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 5253 | |
| 5254 | result: { |
| 5255 | if (!safety and (try self.resolveInst(bin_op.rhs)) == .undef) break :result; |
| 5256 | |
| 5257 | const dst_ptr = try self.resolveInst(bin_op.lhs); |
| 5258 | const dst_ptr_ty = self.typeOf(bin_op.lhs); |
| 5259 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 5260 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5261 | else => null, |
| 5262 | }; |
| 5263 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 5264 | |
| 5265 | const src_val = try self.resolveInst(bin_op.rhs); |
| 5266 | const elem_ty = self.typeOf(bin_op.rhs); |
| 5267 | const src_val_lock: ?RegisterLock = switch (src_val) { |
| 5268 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5269 | else => null, |
| 5270 | }; |
| 5271 | defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock); |
| 5272 | |
| 5273 | const elem_abi_size: u31 = @intCast(elem_ty.abiSize(zcu)); |
| 5274 | |
| 5275 | if (elem_abi_size == 1) { |
| 5276 | const ptr: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) { |
| 5277 | // TODO: this only handles slices stored in the stack |
| 5278 | .Slice => dst_ptr, |
| 5279 | .One => dst_ptr, |
| 5280 | .C, .Many => unreachable, |
| 5281 | }; |
| 5282 | const len: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) { |
| 5283 | // TODO: this only handles slices stored in the stack |
| 5284 | .Slice => dst_ptr.address().offset(8).deref(), |
| 5285 | .One => .{ .immediate = dst_ptr_ty.childType(zcu).arrayLen(zcu) }, |
| 5286 | .C, .Many => unreachable, |
| 5287 | }; |
| 5288 | const len_lock: ?RegisterLock = switch (len) { |
| 5289 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5290 | else => null, |
| 5291 | }; |
| 5292 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 5293 | |
| 5294 | try self.genInlineMemset(ptr, src_val, len); |
| 5295 | break :result; |
| 5296 | } |
| 5297 | |
| 5298 | // Store the first element, and then rely on memcpy copying forwards. |
| 5299 | // Length zero requires a runtime check - so we handle arrays specially |
| 5300 | // here to elide it. |
| 5301 | switch (dst_ptr_ty.ptrSize(zcu)) { |
| 5302 | .Slice => return self.fail("TODO: airMemset Slices", .{}), |
| 5303 | .One => { |
| 5304 | const elem_ptr_ty = try zcu.singleMutPtrType(elem_ty); |
| 5305 | |
| 5306 | const len = dst_ptr_ty.childType(zcu).arrayLen(zcu); |
| 5307 | |
| 5308 | assert(len != 0); // prevented by Sema |
| 5309 | try self.store(dst_ptr, src_val, elem_ptr_ty, elem_ty); |
| 5310 | |
| 5311 | const second_elem_ptr_reg, const second_elem_ptr_lock = try self.allocReg(); |
| 5312 | defer self.register_manager.unlockReg(second_elem_ptr_lock); |
| 5313 | |
| 5314 | const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg }; |
| 5315 | |
| 5316 | try self.genSetReg(Type.usize, second_elem_ptr_reg, .{ .register_offset = .{ |
| 5317 | .reg = try self.copyToTmpRegister(Type.usize, dst_ptr), |
| 5318 | .off = elem_abi_size, |
| 5319 | } }); |
| 5320 | |
| 5321 | const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) }; |
| 5322 | try self.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, bytes_to_copy); |
| 5323 | }, |
| 5324 | .C, .Many => unreachable, |
| 5325 | } |
| 5107 | 5326 | } |
| 5108 | | return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch}); |
| 5327 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5109 | 5328 | } |
| 5110 | 5329 | |
| 5111 | 5330 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -5190,32 +5409,66 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 5190 | 5409 | const len: usize = @intCast(result_ty.arrayLen(zcu)); |
| 5191 | 5410 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 5192 | 5411 | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); |
| 5412 | |
| 5193 | 5413 | const result: MCValue = result: { |
| 5194 | 5414 | switch (result_ty.zigTypeTag(zcu)) { |
| 5195 | 5415 | .Struct => { |
| 5196 | 5416 | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu)); |
| 5417 | if (result_ty.containerLayout(zcu) == .@"packed") { |
| 5418 | const struct_obj = zcu.typeToStruct(result_ty).?; |
| 5419 | try self.genInlineMemset( |
| 5420 | .{ .lea_frame = .{ .index = frame_index } }, |
| 5421 | .{ .immediate = 0 }, |
| 5422 | .{ .immediate = result_ty.abiSize(zcu) }, |
| 5423 | ); |
| 5424 | |
| 5425 | for (elements, 0..) |elem, elem_i_usize| { |
| 5426 | const elem_i: u32 = @intCast(elem_i_usize); |
| 5427 | if ((try result_ty.structFieldValueComptime(zcu, elem_i)) != null) continue; |
| 5428 | |
| 5429 | const elem_ty = result_ty.structFieldType(elem_i, zcu); |
| 5430 | const elem_bit_size: u32 = @intCast(elem_ty.bitSize(zcu)); |
| 5431 | if (elem_bit_size > 64) { |
| 5432 | return self.fail( |
| 5433 | "TODO airAggregateInit implement packed structs with large fields", |
| 5434 | .{}, |
| 5435 | ); |
| 5436 | } |
| 5197 | 5437 | |
| 5198 | | if (result_ty.containerLayout(zcu) == .@"packed") {} else for (elements, 0..) |elem, elem_i| { |
| 5438 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 5439 | const elem_abi_bits = elem_abi_size * 8; |
| 5440 | const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i); |
| 5441 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 5442 | const elem_bit_off = elem_off % elem_abi_bits; |
| 5443 | const elem_mcv = try self.resolveInst(elem); |
| 5444 | |
| 5445 | _ = elem_byte_off; |
| 5446 | _ = elem_bit_off; |
| 5447 | |
| 5448 | const elem_lock = switch (elem_mcv) { |
| 5449 | .register => |reg| self.register_manager.lockReg(reg), |
| 5450 | .immediate => |imm| lock: { |
| 5451 | if (imm == 0) continue; |
| 5452 | break :lock null; |
| 5453 | }, |
| 5454 | else => null, |
| 5455 | }; |
| 5456 | defer if (elem_lock) |lock| self.register_manager.unlockReg(lock); |
| 5457 | |
| 5458 | return self.fail("TODO: airAggregateInit packed structs", .{}); |
| 5459 | } |
| 5460 | } else for (elements, 0..) |elem, elem_i| { |
| 5199 | 5461 | if ((try result_ty.structFieldValueComptime(zcu, elem_i)) != null) continue; |
| 5200 | 5462 | |
| 5201 | 5463 | const elem_ty = result_ty.structFieldType(elem_i, zcu); |
| 5202 | 5464 | const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu)); |
| 5203 | 5465 | const elem_mcv = try self.resolveInst(elem); |
| 5204 | | |
| 5205 | | const elem_frame: FrameAddr = .{ |
| 5206 | | .index = frame_index, |
| 5207 | | .off = elem_off, |
| 5208 | | }; |
| 5209 | | try self.genSetStack( |
| 5210 | | elem_ty, |
| 5211 | | elem_frame, |
| 5212 | | elem_mcv, |
| 5213 | | ); |
| 5466 | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, elem_mcv); |
| 5214 | 5467 | } |
| 5468 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 5215 | 5469 | }, |
| 5216 | | else => return self.fail("TODO: airAggregateInit {}", .{result_ty.fmt(zcu)}), |
| 5470 | else => return self.fail("TODO: airAggregate {}", .{result_ty.fmt(zcu)}), |
| 5217 | 5471 | } |
| 5218 | | break :result .{ .register = .zero }; |
| 5219 | 5472 | }; |
| 5220 | 5473 | |
| 5221 | 5474 | if (elements.len <= Liveness.bpi - 1) { |