| ... | @@ -1271,6 +1271,27 @@ fn asmRegisterRegisterRegister( | ... | @@ -1271,6 +1271,27 @@ fn asmRegisterRegisterRegister( |
| 1271 | }); | 1271 | }); |
| 1272 | } | 1272 | } |
| 1273 | | 1273 | |
| | 1274 | fn asmRegisterRegisterRegisterRegister( |
| | 1275 | self: *Self, |
| | 1276 | tag: Mir.Inst.FixedTag, |
| | 1277 | reg1: Register, |
| | 1278 | reg2: Register, |
| | 1279 | reg3: Register, |
| | 1280 | reg4: Register, |
| | 1281 | ) !void { |
| | 1282 | _ = try self.addInst(.{ |
| | 1283 | .tag = tag[1], |
| | 1284 | .ops = .rrrr, |
| | 1285 | .data = .{ .rrrr = .{ |
| | 1286 | .fixes = tag[0], |
| | 1287 | .r1 = reg1, |
| | 1288 | .r2 = reg2, |
| | 1289 | .r3 = reg3, |
| | 1290 | .r4 = reg4, |
| | 1291 | } }, |
| | 1292 | }); |
| | 1293 | } |
| | 1294 | |
| 1274 | fn asmRegisterRegisterRegisterImmediate( | 1295 | fn asmRegisterRegisterRegisterImmediate( |
| 1275 | self: *Self, | 1296 | self: *Self, |
| 1276 | tag: Mir.Inst.FixedTag, | 1297 | tag: Mir.Inst.FixedTag, |
| ... | @@ -2203,6 +2224,10 @@ fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 { | ... | @@ -2203,6 +2224,10 @@ fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 { |
| 2203 | return @min(alloc_align, @bitCast(u32, frame_addr.off) & (alloc_align - 1)); | 2224 | return @min(alloc_align, @bitCast(u32, frame_addr.off) & (alloc_align - 1)); |
| 2204 | } | 2225 | } |
| 2205 | | 2226 | |
| | 2227 | fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { |
| | 2228 | return self.frame_allocs.get(@enumToInt(frame_addr.index)).abi_size - @intCast(u31, frame_addr.off); |
| | 2229 | } |
| | 2230 | |
| 2206 | fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { | 2231 | fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2207 | const frame_allocs_slice = self.frame_allocs.slice(); | 2232 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 2208 | const frame_size = frame_allocs_slice.items(.abi_size); | 2233 | const frame_size = frame_allocs_slice.items(.abi_size); |
| ... | @@ -2594,115 +2619,202 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2594,115 +2619,202 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2594 | | 2619 | |
| 2595 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 2620 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2596 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2621 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 2622 | const result: MCValue = result: { |
| | 2623 | const src_ty = self.air.typeOf(ty_op.operand); |
| | 2624 | const src_int_info = src_ty.intInfo(self.target.*); |
| 2597 | | 2625 | |
| 2598 | const src_ty = self.air.typeOf(ty_op.operand); | 2626 | const dst_ty = self.air.typeOfIndex(inst); |
| 2599 | const src_int_info = src_ty.intInfo(self.target.*); | 2627 | const dst_int_info = dst_ty.intInfo(self.target.*); |
| 2600 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 2628 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2601 | const src_mcv = try self.resolveInst(ty_op.operand); | | |
| 2602 | const src_lock = switch (src_mcv) { | | |
| 2603 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2604 | else => null, | | |
| 2605 | }; | | |
| 2606 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 2607 | | 2629 | |
| 2608 | const dst_ty = self.air.typeOfIndex(inst); | 2630 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 2609 | const dst_int_info = dst_ty.intInfo(self.target.*); | 2631 | const extend = switch (src_int_info.signedness) { |
| 2610 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 2632 | .signed => dst_int_info, |
| 2611 | const dst_mcv = if (dst_abi_size <= src_abi_size and | 2633 | .unsigned => src_int_info, |
| 2612 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 2634 | }.signedness; |
| 2613 | src_mcv | | |
| 2614 | else | | |
| 2615 | try self.allocRegOrMem(inst, true); | | |
| 2616 | | 2635 | |
| 2617 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; | 2636 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2618 | const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and | 2637 | const src_storage_bits = switch (src_mcv) { |
| 2619 | src_int_info.signedness == .signed) .signed else .unsigned; | 2638 | .register, .register_offset => 64, |
| 2620 | switch (dst_mcv) { | 2639 | .load_frame => |frame_addr| self.getFrameAddrSize(frame_addr) * 8, |
| 2621 | .register => |dst_reg| { | 2640 | else => src_int_info.bits, |
| 2622 | const min_abi_size = @min(dst_abi_size, src_abi_size); | 2641 | }; |
| 2623 | const tag: Mir.Inst.FixedTag = switch (signedness) { | 2642 | |
| 2624 | .signed => if (min_abi_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx }, | 2643 | const dst_mcv = if (dst_int_info.bits <= src_storage_bits and |
| 2625 | .unsigned => if (min_abi_size >= 4) .{ ._, .mov } else .{ ._, .movzx }, | 2644 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 2626 | }; | 2645 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 2627 | const dst_alias = switch (tag[1]) { | 2646 | try self.genCopy(min_ty, dst_mcv, src_mcv); |
| 2628 | .movsx => dst_reg.to64(), | 2647 | break :dst dst_mcv; |
| 2629 | .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(), | 2648 | }; |
| 2630 | else => unreachable, | 2649 | |
| | 2650 | if (dst_int_info.bits <= src_int_info.bits) break :result if (dst_mcv.isRegister()) |
| | 2651 | .{ .register = registerAlias(dst_mcv.getReg().?, abi_size) } |
| | 2652 | else |
| | 2653 | dst_mcv; |
| | 2654 | |
| | 2655 | if (dst_mcv.isRegister()) { |
| | 2656 | try self.truncateRegister(src_ty, dst_mcv.getReg().?); |
| | 2657 | break :result .{ .register = registerAlias(dst_mcv.getReg().?, abi_size) }; |
| | 2658 | } |
| | 2659 | |
| | 2660 | const src_limbs_len = std.math.divCeil(u16, src_int_info.bits, 64) catch unreachable; |
| | 2661 | const dst_limbs_len = std.math.divCeil(u16, dst_int_info.bits, 64) catch unreachable; |
| | 2662 | |
| | 2663 | const high_mcv = dst_mcv.address().offset((src_limbs_len - 1) * 8).deref(); |
| | 2664 | const high_reg = try self.copyToTmpRegister(switch (src_int_info.signedness) { |
| | 2665 | .signed => Type.isize, |
| | 2666 | .unsigned => Type.usize, |
| | 2667 | }, high_mcv); |
| | 2668 | const high_lock = self.register_manager.lockRegAssumeUnused(high_reg); |
| | 2669 | defer self.register_manager.unlockReg(high_lock); |
| | 2670 | |
| | 2671 | const high_bits = src_int_info.bits % 64; |
| | 2672 | if (high_bits > 0) { |
| | 2673 | var high_pl = Type.Payload.Bits{ |
| | 2674 | .base = .{ .tag = switch (extend) { |
| | 2675 | .signed => .int_signed, |
| | 2676 | .unsigned => .int_unsigned, |
| | 2677 | } }, |
| | 2678 | .data = high_bits, |
| 2631 | }; | 2679 | }; |
| 2632 | switch (src_mcv) { | 2680 | const high_ty = Type.initPayload(&high_pl.base); |
| 2633 | .register => |src_reg| { | 2681 | try self.truncateRegister(high_ty, high_reg); |
| 2634 | try self.asmRegisterRegister( | 2682 | try self.genCopy(Type.usize, high_mcv, .{ .register = high_reg }); |
| 2635 | tag, | 2683 | } |
| 2636 | dst_alias, | 2684 | |
| 2637 | registerAlias(src_reg, min_abi_size), | 2685 | if (dst_limbs_len > src_limbs_len) try self.genInlineMemset( |
| | 2686 | dst_mcv.address().offset(src_limbs_len * 8), |
| | 2687 | switch (extend) { |
| | 2688 | .signed => extend: { |
| | 2689 | const extend_mcv = MCValue{ .register = high_reg }; |
| | 2690 | try self.genShiftBinOpMir( |
| | 2691 | .{ ._r, .sa }, |
| | 2692 | Type.isize, |
| | 2693 | extend_mcv, |
| | 2694 | .{ .immediate = 63 }, |
| 2638 | ); | 2695 | ); |
| | 2696 | break :extend extend_mcv; |
| 2639 | }, | 2697 | }, |
| 2640 | .memory, .indirect, .load_frame => try self.asmRegisterMemory( | 2698 | .unsigned => .{ .immediate = 0 }, |
| 2641 | tag, | 2699 | }, |
| 2642 | dst_alias, | 2700 | .{ .immediate = (dst_limbs_len - src_limbs_len) * 8 }, |
| 2643 | src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)), | 2701 | ); |
| 2644 | ), | 2702 | |
| 2645 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ | 2703 | break :result dst_mcv; |
| 2646 | @tagName(src_mcv), | 2704 | }; |
| 2647 | @tagName(dst_mcv), | 2705 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2648 | }), | | |
| 2649 | } | | |
| 2650 | if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg); | | |
| 2651 | }, | | |
| 2652 | else => { | | |
| 2653 | try self.genCopy(min_ty, dst_mcv, src_mcv); | | |
| 2654 | const extra = dst_abi_size * 8 - dst_int_info.bits; | | |
| 2655 | if (extra > 0) { | | |
| 2656 | try self.genShiftBinOpMir( | | |
| 2657 | switch (signedness) { | | |
| 2658 | .signed => .{ ._l, .sa }, | | |
| 2659 | .unsigned => .{ ._l, .sh }, | | |
| 2660 | }, | | |
| 2661 | dst_ty, | | |
| 2662 | dst_mcv, | | |
| 2663 | .{ .immediate = extra }, | | |
| 2664 | ); | | |
| 2665 | try self.genShiftBinOpMir( | | |
| 2666 | switch (signedness) { | | |
| 2667 | .signed => .{ ._r, .sa }, | | |
| 2668 | .unsigned => .{ ._r, .sh }, | | |
| 2669 | }, | | |
| 2670 | dst_ty, | | |
| 2671 | dst_mcv, | | |
| 2672 | .{ .immediate = extra }, | | |
| 2673 | ); | | |
| 2674 | } | | |
| 2675 | }, | | |
| 2676 | } | | |
| 2677 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); | | |
| 2678 | } | 2706 | } |
| 2679 | | 2707 | |
| 2680 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 2708 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2681 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2709 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2682 | | 2710 | |
| 2683 | const dst_ty = self.air.typeOfIndex(inst); | 2711 | const dst_ty = self.air.typeOfIndex(inst); |
| 2684 | const dst_abi_size = dst_ty.abiSize(self.target.*); | 2712 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2685 | if (dst_abi_size > 8) { | 2713 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2686 | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); | 2714 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 2687 | } | | |
| 2688 | | 2715 | |
| 2689 | const src_mcv = try self.resolveInst(ty_op.operand); | 2716 | const result = result: { |
| 2690 | const src_lock = switch (src_mcv) { | 2717 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2691 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2718 | const src_lock = |
| 2692 | else => null, | 2719 | if (src_mcv.getReg()) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 2693 | }; | 2720 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 2694 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 2695 | | 2721 | |
| 2696 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 2722 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2697 | src_mcv | 2723 | src_mcv |
| 2698 | else | 2724 | else |
| 2699 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); | 2725 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| | 2726 | |
| | 2727 | if (dst_ty.zigTypeTag() == .Vector) { |
| | 2728 | assert(src_ty.zigTypeTag() == .Vector and dst_ty.vectorLen() == src_ty.vectorLen()); |
| | 2729 | const dst_info = dst_ty.childType().intInfo(self.target.*); |
| | 2730 | const src_info = src_ty.childType().intInfo(self.target.*); |
| | 2731 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_info.bits) { |
| | 2732 | 8 => switch (src_info.bits) { |
| | 2733 | 16 => switch (dst_ty.vectorLen()) { |
| | 2734 | 1...8 => if (self.hasFeature(.avx)) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw }, |
| | 2735 | 9...16 => if (self.hasFeature(.avx2)) .{ .vp_b, .ackusw } else null, |
| | 2736 | else => null, |
| | 2737 | }, |
| | 2738 | else => null, |
| | 2739 | }, |
| | 2740 | 16 => switch (src_info.bits) { |
| | 2741 | 32 => switch (dst_ty.vectorLen()) { |
| | 2742 | 1...4 => if (self.hasFeature(.avx)) |
| | 2743 | .{ .vp_w, .ackusd } |
| | 2744 | else if (self.hasFeature(.sse4_1)) |
| | 2745 | .{ .p_w, .ackusd } |
| | 2746 | else |
| | 2747 | null, |
| | 2748 | 5...8 => if (self.hasFeature(.avx2)) .{ .vp_w, .ackusd } else null, |
| | 2749 | else => null, |
| | 2750 | }, |
| | 2751 | else => null, |
| | 2752 | }, |
| | 2753 | else => null, |
| | 2754 | })) |tag| tag else return self.fail("TODO implement airTrunc for {}", .{ |
| | 2755 | dst_ty.fmt(self.bin_file.options.module.?), |
| | 2756 | }); |
| 2700 | | 2757 | |
| 2701 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result | 2758 | var mask_pl = Value.Payload.U64{ |
| 2702 | // have to be removed. this only happens if the dst if not a power-of-two size. | 2759 | .base = .{ .tag = .int_u64 }, |
| 2703 | if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64()); | 2760 | .data = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits), |
| | 2761 | }; |
| | 2762 | const mask_val = Value.initPayload(&mask_pl.base); |
| 2704 | | 2763 | |
| 2705 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); | 2764 | var splat_pl = Value.Payload.SubValue{ |
| | 2765 | .base = .{ .tag = .repeated }, |
| | 2766 | .data = mask_val, |
| | 2767 | }; |
| | 2768 | const splat_val = Value.initPayload(&splat_pl.base); |
| | 2769 | |
| | 2770 | var full_pl = Type.Payload.Array{ |
| | 2771 | .base = .{ .tag = .vector }, |
| | 2772 | .data = .{ |
| | 2773 | .len = @divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits), |
| | 2774 | .elem_type = src_ty.childType(), |
| | 2775 | }, |
| | 2776 | }; |
| | 2777 | const full_ty = Type.initPayload(&full_pl.base); |
| | 2778 | const full_abi_size = @intCast(u32, full_ty.abiSize(self.target.*)); |
| | 2779 | |
| | 2780 | const splat_mcv = try self.genTypedValue(.{ .ty = full_ty, .val = splat_val }); |
| | 2781 | const splat_addr_mcv: MCValue = switch (splat_mcv) { |
| | 2782 | .memory, .indirect, .load_frame => splat_mcv.address(), |
| | 2783 | else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, |
| | 2784 | }; |
| | 2785 | |
| | 2786 | const dst_reg = registerAlias(dst_mcv.getReg().?, src_abi_size); |
| | 2787 | if (self.hasFeature(.avx)) { |
| | 2788 | try self.asmRegisterRegisterMemory( |
| | 2789 | .{ .vp_, .@"and" }, |
| | 2790 | dst_reg, |
| | 2791 | dst_reg, |
| | 2792 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(full_abi_size)), |
| | 2793 | ); |
| | 2794 | try self.asmRegisterRegisterRegister(mir_tag, dst_reg, dst_reg, dst_reg); |
| | 2795 | } else { |
| | 2796 | try self.asmRegisterMemory( |
| | 2797 | .{ .p_, .@"and" }, |
| | 2798 | dst_reg, |
| | 2799 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(full_abi_size)), |
| | 2800 | ); |
| | 2801 | try self.asmRegisterRegister(mir_tag, dst_reg, dst_reg); |
| | 2802 | } |
| | 2803 | break :result dst_mcv; |
| | 2804 | } |
| | 2805 | |
| | 2806 | if (dst_abi_size > 8) { |
| | 2807 | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); |
| | 2808 | } |
| | 2809 | |
| | 2810 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result |
| | 2811 | // have to be removed. this only happens if the dst if not a power-of-two size. |
| | 2812 | if (self.regExtraBits(dst_ty) > 0) |
| | 2813 | try self.truncateRegister(dst_ty, dst_mcv.register.to64()); |
| | 2814 | |
| | 2815 | break :result dst_mcv; |
| | 2816 | }; |
| | 2817 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2706 | } | 2818 | } |
| 2707 | | 2819 | |
| 2708 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 2820 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2855,20 +2967,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2855,20 +2967,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2855 | defer self.register_manager.unlockReg(limit_lock); | 2967 | defer self.register_manager.unlockReg(limit_lock); |
| 2856 | | 2968 | |
| 2857 | const reg_bits = self.regBitSize(ty); | 2969 | const reg_bits = self.regBitSize(ty); |
| | 2970 | const reg_extra_bits = self.regExtraBits(ty); |
| 2858 | const cc: Condition = if (ty.isSignedInt()) cc: { | 2971 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 2972 | if (reg_extra_bits > 0) { |
| | 2973 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| | 2974 | } |
| 2859 | try self.genSetReg(limit_reg, ty, dst_mcv); | 2975 | try self.genSetReg(limit_reg, ty, dst_mcv); |
| 2860 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); | 2976 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 2861 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ | 2977 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 2862 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, | 2978 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 2863 | }); | 2979 | }); |
| | 2980 | if (reg_extra_bits > 0) { |
| | 2981 | const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv); |
| | 2982 | const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg }; |
| | 2983 | const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg); |
| | 2984 | defer self.register_manager.unlockReg(shifted_rhs_lock); |
| | 2985 | |
| | 2986 | try self.genShiftBinOpMir( |
| | 2987 | .{ ._l, .sa }, |
| | 2988 | ty, |
| | 2989 | shifted_rhs_mcv, |
| | 2990 | .{ .immediate = reg_extra_bits }, |
| | 2991 | ); |
| | 2992 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv); |
| | 2993 | } else try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); |
| 2864 | break :cc .o; | 2994 | break :cc .o; |
| 2865 | } else cc: { | 2995 | } else cc: { |
| 2866 | try self.genSetReg(limit_reg, ty, .{ | 2996 | try self.genSetReg(limit_reg, ty, .{ |
| 2867 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), | 2997 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - ty.bitSize(self.target.*)), |
| 2868 | }); | 2998 | }); |
| | 2999 | |
| | 3000 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); |
| | 3001 | if (reg_extra_bits > 0) { |
| | 3002 | try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, limit_mcv); |
| | 3003 | break :cc .a; |
| | 3004 | } |
| 2869 | break :cc .c; | 3005 | break :cc .c; |
| 2870 | }; | 3006 | }; |
| 2871 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); | | |
| 2872 | | 3007 | |
| 2873 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 3008 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 2874 | try self.asmCmovccRegisterRegister( | 3009 | try self.asmCmovccRegisterRegister( |
| ... | @@ -2877,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2877,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2877 | cc, | 3012 | cc, |
| 2878 | ); | 3013 | ); |
| 2879 | | 3014 | |
| | 3015 | if (reg_extra_bits > 0 and ty.isSignedInt()) { |
| | 3016 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| | 3017 | } |
| | 3018 | |
| 2880 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); | 3019 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2881 | } | 3020 | } |
| 2882 | | 3021 | |
| ... | @@ -2906,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2906,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2906 | defer self.register_manager.unlockReg(limit_lock); | 3045 | defer self.register_manager.unlockReg(limit_lock); |
| 2907 | | 3046 | |
| 2908 | const reg_bits = self.regBitSize(ty); | 3047 | const reg_bits = self.regBitSize(ty); |
| | 3048 | const reg_extra_bits = self.regExtraBits(ty); |
| 2909 | const cc: Condition = if (ty.isSignedInt()) cc: { | 3049 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 3050 | if (reg_extra_bits > 0) { |
| | 3051 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| | 3052 | } |
| 2910 | try self.genSetReg(limit_reg, ty, dst_mcv); | 3053 | try self.genSetReg(limit_reg, ty, dst_mcv); |
| 2911 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); | 3054 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 2912 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ | 3055 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 2913 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, | 3056 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 2914 | }); | 3057 | }); |
| | 3058 | if (reg_extra_bits > 0) { |
| | 3059 | const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv); |
| | 3060 | const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg }; |
| | 3061 | const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg); |
| | 3062 | defer self.register_manager.unlockReg(shifted_rhs_lock); |
| | 3063 | |
| | 3064 | try self.genShiftBinOpMir( |
| | 3065 | .{ ._l, .sa }, |
| | 3066 | ty, |
| | 3067 | shifted_rhs_mcv, |
| | 3068 | .{ .immediate = reg_extra_bits }, |
| | 3069 | ); |
| | 3070 | try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv); |
| | 3071 | } else try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv); |
| 2915 | break :cc .o; | 3072 | break :cc .o; |
| 2916 | } else cc: { | 3073 | } else cc: { |
| 2917 | try self.genSetReg(limit_reg, ty, .{ .immediate = 0 }); | 3074 | try self.genSetReg(limit_reg, ty, .{ .immediate = 0 }); |
| | 3075 | try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv); |
| 2918 | break :cc .c; | 3076 | break :cc .c; |
| 2919 | }; | 3077 | }; |
| 2920 | try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv); | | |
| 2921 | | 3078 | |
| 2922 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 3079 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 2923 | try self.asmCmovccRegisterRegister( | 3080 | try self.asmCmovccRegisterRegister( |
| ... | @@ -2926,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2926,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2926 | cc, | 3083 | cc, |
| 2927 | ); | 3084 | ); |
| 2928 | | 3085 | |
| | 3086 | if (reg_extra_bits > 0 and ty.isSignedInt()) { |
| | 3087 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| | 3088 | } |
| | 3089 | |
| 2929 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); | 3090 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2930 | } | 3091 | } |
| 2931 | | 3092 | |
| ... | @@ -3222,34 +3383,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3222,34 +3383,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3222 | self.regExtraBits(dst_ty) | 3383 | self.regExtraBits(dst_ty) |
| 3223 | else | 3384 | else |
| 3224 | dst_info.bits % 64; | 3385 | dst_info.bits % 64; |
| 3225 | const partial_mcv = if (dst_info.signedness == .signed and extra_bits > 0) dst: { | 3386 | const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); |
| 3226 | const rhs_lock: ?RegisterLock = switch (rhs) { | | |
| 3227 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 3228 | else => null, | | |
| 3229 | }; | | |
| 3230 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 3231 | | | |
| 3232 | const dst_reg: Register = blk: { | | |
| 3233 | if (lhs.isRegister()) break :blk lhs.register; | | |
| 3234 | break :blk try self.copyToTmpRegister(dst_ty, lhs); | | |
| 3235 | }; | | |
| 3236 | const dst_mcv = MCValue{ .register = dst_reg }; | | |
| 3237 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | | |
| 3238 | defer self.register_manager.unlockReg(dst_reg_lock); | | |
| 3239 | | | |
| 3240 | const rhs_mcv: MCValue = blk: { | | |
| 3241 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; | | |
| 3242 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; | | |
| 3243 | }; | | |
| 3244 | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { | | |
| 3245 | .register => |reg| self.register_manager.lockReg(reg), | | |
| 3246 | else => null, | | |
| 3247 | }; | | |
| 3248 | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 3249 | | | |
| 3250 | try self.genIntMulComplexOpMir(Type.isize, dst_mcv, rhs_mcv); | | |
| 3251 | break :dst dst_mcv; | | |
| 3252 | } else try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); | | |
| 3253 | | 3387 | |
| 3254 | switch (partial_mcv) { | 3388 | switch (partial_mcv) { |
| 3255 | .register => |reg| if (extra_bits == 0) { | 3389 | .register => |reg| if (extra_bits == 0) { |
| ... | @@ -3262,9 +3396,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3262,9 +3396,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3262 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3396 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3263 | }, | 3397 | }, |
| 3264 | else => { | 3398 | else => { |
| 3265 | // For now, this is the only supported multiply that doesn't fit in a register, | 3399 | // For now, this is the only supported multiply that doesn't fit in a register. |
| 3266 | // so cc being set is impossible. | | |
| 3267 | | | |
| 3268 | assert(dst_info.bits <= 128 and src_pl.data == 64); | 3400 | assert(dst_info.bits <= 128 and src_pl.data == 64); |
| 3269 | | 3401 | |
| 3270 | const frame_index = | 3402 | const frame_index = |
| ... | @@ -3280,7 +3412,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3280,7 +3412,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3280 | .{ .frame = frame_index }, | 3412 | .{ .frame = frame_index }, |
| 3281 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | 3413 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), |
| 3282 | tuple_ty.structFieldType(1), | 3414 | tuple_ty.structFieldType(1), |
| 3283 | .{ .immediate = 0 }, | 3415 | .{ .immediate = 0 }, // cc being set is impossible |
| 3284 | ); | 3416 | ); |
| 3285 | } else try self.genSetFrameTruncatedOverflowCompare( | 3417 | } else try self.genSetFrameTruncatedOverflowCompare( |
| 3286 | tuple_ty, | 3418 | tuple_ty, |
| ... | @@ -5558,31 +5690,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5558,31 +5690,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5558 | const dst_lock = self.register_manager.lockReg(dst_reg); | 5690 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 5559 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 5691 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5560 | | 5692 | |
| 5561 | // Shift by struct_field_offset. | | |
| 5562 | try self.genShiftBinOpMir( | 5693 | try self.genShiftBinOpMir( |
| 5563 | .{ ._r, .sh }, | 5694 | .{ ._r, .sh }, |
| 5564 | Type.usize, | 5695 | Type.usize, |
| 5565 | dst_mcv, | 5696 | dst_mcv, |
| 5566 | .{ .immediate = field_off }, | 5697 | .{ .immediate = field_off }, |
| 5567 | ); | 5698 | ); |
| 5568 | | 5699 | if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg); |
| 5569 | // Mask to field_bit_size bits | | |
| 5570 | const field_bit_size = field_ty.bitSize(self.target.*); | | |
| 5571 | const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size); | | |
| 5572 | | | |
| 5573 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | | |
| 5574 | try self.genBinOpMir(.{ ._, .@"and" }, Type.usize, dst_mcv, .{ .register = tmp_reg }); | | |
| 5575 | | | |
| 5576 | const signedness = | | |
| 5577 | if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned; | | |
| 5578 | const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*)); | | |
| 5579 | if (signedness == .signed and field_byte_size < 8) { | | |
| 5580 | try self.asmRegisterRegister( | | |
| 5581 | if (field_byte_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx }, | | |
| 5582 | dst_mcv.register, | | |
| 5583 | registerAlias(dst_mcv.register, field_byte_size), | | |
| 5584 | ); | | |
| 5585 | } | | |
| 5586 | | 5700 | |
| 5587 | break :result if (field_rc.supersetOf(gp)) | 5701 | break :result if (field_rc.supersetOf(gp)) |
| 5588 | dst_mcv | 5702 | dst_mcv |
| ... | @@ -6224,12 +6338,26 @@ fn genBinOp( | ... | @@ -6224,12 +6338,26 @@ fn genBinOp( |
| 6224 | lhs_air: Air.Inst.Ref, | 6338 | lhs_air: Air.Inst.Ref, |
| 6225 | rhs_air: Air.Inst.Ref, | 6339 | rhs_air: Air.Inst.Ref, |
| 6226 | ) !MCValue { | 6340 | ) !MCValue { |
| 6227 | const lhs_mcv = try self.resolveInst(lhs_air); | | |
| 6228 | const rhs_mcv = try self.resolveInst(rhs_air); | | |
| 6229 | const lhs_ty = self.air.typeOf(lhs_air); | 6341 | const lhs_ty = self.air.typeOf(lhs_air); |
| 6230 | const rhs_ty = self.air.typeOf(rhs_air); | 6342 | const rhs_ty = self.air.typeOf(rhs_air); |
| 6231 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); | 6343 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); |
| 6232 | | 6344 | |
| | 6345 | const maybe_mask_reg = switch (air_tag) { |
| | 6346 | else => null, |
| | 6347 | .max, .min => if (lhs_ty.scalarType().isRuntimeFloat()) registerAlias( |
| | 6348 | if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: { |
| | 6349 | try self.register_manager.getReg(.xmm0, null); |
| | 6350 | break :mask .xmm0; |
| | 6351 | } else try self.register_manager.allocReg(null, sse), |
| | 6352 | abi_size, |
| | 6353 | ) else null, |
| | 6354 | }; |
| | 6355 | const mask_lock = |
| | 6356 | if (maybe_mask_reg) |mask_reg| self.register_manager.lockRegAssumeUnused(mask_reg) else null; |
| | 6357 | defer if (mask_lock) |lock| self.register_manager.unlockReg(lock); |
| | 6358 | |
| | 6359 | const lhs_mcv = try self.resolveInst(lhs_air); |
| | 6360 | const rhs_mcv = try self.resolveInst(rhs_air); |
| 6233 | switch (lhs_mcv) { | 6361 | switch (lhs_mcv) { |
| 6234 | .immediate => |imm| switch (imm) { | 6362 | .immediate => |imm| switch (imm) { |
| 6235 | 0 => switch (air_tag) { | 6363 | 0 => switch (air_tag) { |
| ... | @@ -6300,7 +6428,16 @@ fn genBinOp( | ... | @@ -6300,7 +6428,16 @@ fn genBinOp( |
| 6300 | }; | 6428 | }; |
| 6301 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 6429 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 6302 | | 6430 | |
| 6303 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; | 6431 | const unmat_src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| | 6432 | const src_mcv: MCValue = if (maybe_mask_reg) |mask_reg| |
| | 6433 | if (self.hasFeature(.avx) and unmat_src_mcv.isRegister() and maybe_inst != null and |
| | 6434 | self.liveness.operandDies(maybe_inst.?, if (flipped) 0 else 1)) unmat_src_mcv else src: { |
| | 6435 | try self.genSetReg(mask_reg, rhs_ty, unmat_src_mcv); |
| | 6436 | break :src .{ .register = mask_reg }; |
| | 6437 | } |
| | 6438 | else |
| | 6439 | unmat_src_mcv; |
| | 6440 | |
| 6304 | if (!vec_op) { | 6441 | if (!vec_op) { |
| 6305 | switch (air_tag) { | 6442 | switch (air_tag) { |
| 6306 | .add, | 6443 | .add, |
| ... | @@ -7009,18 +7146,26 @@ fn genBinOp( | ... | @@ -7009,18 +7146,26 @@ fn genBinOp( |
| 7009 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ | 7146 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7010 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7147 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 7011 | }); | 7148 | }); |
| | 7149 | |
| | 7150 | const lhs_copy_reg = if (maybe_mask_reg) |_| registerAlias( |
| | 7151 | if (copied_to_dst) try self.copyToTmpRegister(lhs_ty, dst_mcv) else lhs_mcv.getReg().?, |
| | 7152 | abi_size, |
| | 7153 | ) else null; |
| | 7154 | const lhs_copy_lock = if (lhs_copy_reg) |reg| self.register_manager.lockReg(reg) else null; |
| | 7155 | defer if (lhs_copy_lock) |lock| self.register_manager.unlockReg(lock); |
| | 7156 | |
| 7012 | if (self.hasFeature(.avx)) { | 7157 | if (self.hasFeature(.avx)) { |
| 7013 | const src1_alias = | 7158 | const lhs_reg = |
| 7014 | if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); | 7159 | if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); |
| 7015 | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( | 7160 | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 7016 | mir_tag, | 7161 | mir_tag, |
| 7017 | dst_reg, | 7162 | dst_reg, |
| 7018 | src1_alias, | 7163 | lhs_reg, |
| 7019 | src_mcv.mem(Memory.PtrSize.fromSize(abi_size)), | 7164 | src_mcv.mem(Memory.PtrSize.fromSize(abi_size)), |
| 7020 | ) else try self.asmRegisterRegisterRegister( | 7165 | ) else try self.asmRegisterRegisterRegister( |
| 7021 | mir_tag, | 7166 | mir_tag, |
| 7022 | dst_reg, | 7167 | dst_reg, |
| 7023 | src1_alias, | 7168 | lhs_reg, |
| 7024 | registerAlias(if (src_mcv.isRegister()) | 7169 | registerAlias(if (src_mcv.isRegister()) |
| 7025 | src_mcv.getReg().? | 7170 | src_mcv.getReg().? |
| 7026 | else | 7171 | else |
| ... | @@ -7041,9 +7186,10 @@ fn genBinOp( | ... | @@ -7041,9 +7186,10 @@ fn genBinOp( |
| 7041 | try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size), | 7186 | try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size), |
| 7042 | ); | 7187 | ); |
| 7043 | } | 7188 | } |
| | 7189 | |
| 7044 | switch (air_tag) { | 7190 | switch (air_tag) { |
| 7045 | .add, .addwrap, .sub, .subwrap, .mul, .mulwrap, .div_float, .div_exact => {}, | 7191 | .add, .addwrap, .sub, .subwrap, .mul, .mulwrap, .div_float, .div_exact => {}, |
| 7046 | .div_trunc, .div_floor => try self.genRound( | 7192 | .div_trunc, .div_floor => if (self.hasFeature(.sse4_1)) try self.genRound( |
| 7047 | lhs_ty, | 7193 | lhs_ty, |
| 7048 | dst_reg, | 7194 | dst_reg, |
| 7049 | .{ .register = dst_reg }, | 7195 | .{ .register = dst_reg }, |
| ... | @@ -7052,11 +7198,240 @@ fn genBinOp( | ... | @@ -7052,11 +7198,240 @@ fn genBinOp( |
| 7052 | .div_floor => 0b1_0_01, | 7198 | .div_floor => 0b1_0_01, |
| 7053 | else => unreachable, | 7199 | else => unreachable, |
| 7054 | }, | 7200 | }, |
| 7055 | ), | 7201 | ) else return self.fail("TODO implement genBinOp for {s} {} without sse4_1 feature", .{ |
| | 7202 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7203 | }), |
| 7056 | .bit_and, .bit_or, .xor => {}, | 7204 | .bit_and, .bit_or, .xor => {}, |
| 7057 | .max, .min => {}, // TODO: unordered select | 7205 | .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) { |
| | 7206 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); |
| | 7207 | |
| | 7208 | try self.asmRegisterRegisterRegisterImmediate( |
| | 7209 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7210 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7211 | 32 => .{ .v_ss, .cmp }, |
| | 7212 | 64 => .{ .v_sd, .cmp }, |
| | 7213 | 16, 80, 128 => null, |
| | 7214 | else => unreachable, |
| | 7215 | }, |
| | 7216 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7217 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7218 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7219 | 1 => .{ .v_ss, .cmp }, |
| | 7220 | 2...8 => .{ .v_ps, .cmp }, |
| | 7221 | else => null, |
| | 7222 | }, |
| | 7223 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7224 | 1 => .{ .v_sd, .cmp }, |
| | 7225 | 2...4 => .{ .v_pd, .cmp }, |
| | 7226 | else => null, |
| | 7227 | }, |
| | 7228 | 16, 80, 128 => null, |
| | 7229 | else => unreachable, |
| | 7230 | }, |
| | 7231 | else => unreachable, |
| | 7232 | }, |
| | 7233 | else => unreachable, |
| | 7234 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7235 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7236 | }), |
| | 7237 | mask_reg, |
| | 7238 | rhs_copy_reg, |
| | 7239 | rhs_copy_reg, |
| | 7240 | Immediate.u(3), // unord |
| | 7241 | ); |
| | 7242 | try self.asmRegisterRegisterRegisterRegister( |
| | 7243 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7244 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7245 | 32 => .{ .v_ps, .blendv }, |
| | 7246 | 64 => .{ .v_pd, .blendv }, |
| | 7247 | 16, 80, 128 => null, |
| | 7248 | else => unreachable, |
| | 7249 | }, |
| | 7250 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7251 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7252 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7253 | 1...8 => .{ .v_ps, .blendv }, |
| | 7254 | else => null, |
| | 7255 | }, |
| | 7256 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7257 | 1...4 => .{ .v_pd, .blendv }, |
| | 7258 | else => null, |
| | 7259 | }, |
| | 7260 | 16, 80, 128 => null, |
| | 7261 | else => unreachable, |
| | 7262 | }, |
| | 7263 | else => unreachable, |
| | 7264 | }, |
| | 7265 | else => unreachable, |
| | 7266 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7267 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7268 | }), |
| | 7269 | dst_reg, |
| | 7270 | dst_reg, |
| | 7271 | lhs_copy_reg.?, |
| | 7272 | mask_reg, |
| | 7273 | ); |
| | 7274 | } else { |
| | 7275 | const has_blend = self.hasFeature(.sse4_1); |
| | 7276 | try self.asmRegisterRegisterImmediate( |
| | 7277 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7278 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7279 | 32 => .{ ._ss, .cmp }, |
| | 7280 | 64 => .{ ._sd, .cmp }, |
| | 7281 | 16, 80, 128 => null, |
| | 7282 | else => unreachable, |
| | 7283 | }, |
| | 7284 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7285 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7286 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7287 | 1 => .{ ._ss, .cmp }, |
| | 7288 | 2...4 => .{ ._ps, .cmp }, |
| | 7289 | else => null, |
| | 7290 | }, |
| | 7291 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7292 | 1 => .{ ._sd, .cmp }, |
| | 7293 | 2 => .{ ._pd, .cmp }, |
| | 7294 | else => null, |
| | 7295 | }, |
| | 7296 | 16, 80, 128 => null, |
| | 7297 | else => unreachable, |
| | 7298 | }, |
| | 7299 | else => unreachable, |
| | 7300 | }, |
| | 7301 | else => unreachable, |
| | 7302 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7303 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7304 | }), |
| | 7305 | mask_reg, |
| | 7306 | mask_reg, |
| | 7307 | Immediate.u(if (has_blend) 3 else 7), // unord, ord |
| | 7308 | ); |
| | 7309 | if (has_blend) try self.asmRegisterRegisterRegister( |
| | 7310 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7311 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7312 | 32 => .{ ._ps, .blendv }, |
| | 7313 | 64 => .{ ._pd, .blendv }, |
| | 7314 | 16, 80, 128 => null, |
| | 7315 | else => unreachable, |
| | 7316 | }, |
| | 7317 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7318 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7319 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7320 | 1...4 => .{ ._ps, .blendv }, |
| | 7321 | else => null, |
| | 7322 | }, |
| | 7323 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7324 | 1...2 => .{ ._pd, .blendv }, |
| | 7325 | else => null, |
| | 7326 | }, |
| | 7327 | 16, 80, 128 => null, |
| | 7328 | else => unreachable, |
| | 7329 | }, |
| | 7330 | else => unreachable, |
| | 7331 | }, |
| | 7332 | else => unreachable, |
| | 7333 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7334 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7335 | }), |
| | 7336 | dst_reg, |
| | 7337 | lhs_copy_reg.?, |
| | 7338 | mask_reg, |
| | 7339 | ) else { |
| | 7340 | try self.asmRegisterRegister( |
| | 7341 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7342 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7343 | 32 => .{ ._ps, .@"and" }, |
| | 7344 | 64 => .{ ._pd, .@"and" }, |
| | 7345 | 16, 80, 128 => null, |
| | 7346 | else => unreachable, |
| | 7347 | }, |
| | 7348 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7349 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7350 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7351 | 1...4 => .{ ._ps, .@"and" }, |
| | 7352 | else => null, |
| | 7353 | }, |
| | 7354 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7355 | 1...2 => .{ ._pd, .@"and" }, |
| | 7356 | else => null, |
| | 7357 | }, |
| | 7358 | 16, 80, 128 => null, |
| | 7359 | else => unreachable, |
| | 7360 | }, |
| | 7361 | else => unreachable, |
| | 7362 | }, |
| | 7363 | else => unreachable, |
| | 7364 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7365 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7366 | }), |
| | 7367 | dst_reg, |
| | 7368 | mask_reg, |
| | 7369 | ); |
| | 7370 | try self.asmRegisterRegister( |
| | 7371 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7372 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7373 | 32 => .{ ._ps, .andn }, |
| | 7374 | 64 => .{ ._pd, .andn }, |
| | 7375 | 16, 80, 128 => null, |
| | 7376 | else => unreachable, |
| | 7377 | }, |
| | 7378 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7379 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7380 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7381 | 1...4 => .{ ._ps, .andn }, |
| | 7382 | else => null, |
| | 7383 | }, |
| | 7384 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7385 | 1...2 => .{ ._pd, .andn }, |
| | 7386 | else => null, |
| | 7387 | }, |
| | 7388 | 16, 80, 128 => null, |
| | 7389 | else => unreachable, |
| | 7390 | }, |
| | 7391 | else => unreachable, |
| | 7392 | }, |
| | 7393 | else => unreachable, |
| | 7394 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7395 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7396 | }), |
| | 7397 | mask_reg, |
| | 7398 | lhs_copy_reg.?, |
| | 7399 | ); |
| | 7400 | try self.asmRegisterRegister( |
| | 7401 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { |
| | 7402 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| | 7403 | 32 => .{ ._ps, .@"or" }, |
| | 7404 | 64 => .{ ._pd, .@"or" }, |
| | 7405 | 16, 80, 128 => null, |
| | 7406 | else => unreachable, |
| | 7407 | }, |
| | 7408 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { |
| | 7409 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { |
| | 7410 | 32 => switch (lhs_ty.vectorLen()) { |
| | 7411 | 1...4 => .{ ._ps, .@"or" }, |
| | 7412 | else => null, |
| | 7413 | }, |
| | 7414 | 64 => switch (lhs_ty.vectorLen()) { |
| | 7415 | 1...2 => .{ ._pd, .@"or" }, |
| | 7416 | else => null, |
| | 7417 | }, |
| | 7418 | 16, 80, 128 => null, |
| | 7419 | else => unreachable, |
| | 7420 | }, |
| | 7421 | else => unreachable, |
| | 7422 | }, |
| | 7423 | else => unreachable, |
| | 7424 | })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{ |
| | 7425 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| | 7426 | }), |
| | 7427 | dst_reg, |
| | 7428 | mask_reg, |
| | 7429 | ); |
| | 7430 | } |
| | 7431 | }, |
| 7058 | else => unreachable, | 7432 | else => unreachable, |
| 7059 | } | 7433 | } |
| | 7434 | |
| 7060 | return dst_mcv; | 7435 | return dst_mcv; |
| 7061 | } | 7436 | } |
| 7062 | | 7437 | |
| ... | @@ -7882,24 +8257,105 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -7882,24 +8257,105 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 7882 | const result = MCValue{ | 8257 | const result = MCValue{ |
| 7883 | .eflags = switch (ty.zigTypeTag()) { | 8258 | .eflags = switch (ty.zigTypeTag()) { |
| 7884 | else => result: { | 8259 | else => result: { |
| 7885 | var flipped = false; | 8260 | const abi_size = @intCast(u16, ty.abiSize(self.target.*)); |
| 7886 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() or lhs_mcv.isMemory()) | 8261 | const may_flip: enum { |
| 7887 | lhs_mcv | 8262 | may_flip, |
| 7888 | else if (rhs_mcv.isRegister() or rhs_mcv.isMemory()) dst: { | 8263 | must_flip, |
| 7889 | flipped = true; | 8264 | must_not_flip, |
| 7890 | break :dst rhs_mcv; | 8265 | } = if (abi_size > 8) switch (op) { |
| 7891 | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; | 8266 | .lt, .gte => .must_not_flip, |
| 7892 | const dst_lock = switch (dst_mcv) { | 8267 | .lte, .gt => .must_flip, |
| 7893 | .register => |reg| self.register_manager.lockReg(reg), | 8268 | .eq, .neq => .may_flip, |
| 7894 | else => null, | 8269 | } else .may_flip; |
| | 8270 | |
| | 8271 | const flipped = switch (may_flip) { |
| | 8272 | .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isMemory(), |
| | 8273 | .must_flip => true, |
| | 8274 | .must_not_flip => false, |
| | 8275 | }; |
| | 8276 | const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv; |
| | 8277 | const dst_mcv = if (unmat_dst_mcv.isRegister() or |
| | 8278 | (abi_size <= 8 and unmat_dst_mcv.isMemory())) unmat_dst_mcv else dst: { |
| | 8279 | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| | 8280 | try self.genCopy(ty, dst_mcv, unmat_dst_mcv); |
| | 8281 | break :dst dst_mcv; |
| 7895 | }; | 8282 | }; |
| | 8283 | const dst_lock = |
| | 8284 | if (dst_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 7896 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 8285 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| | 8286 | |
| 7897 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; | 8287 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| | 8288 | const src_lock = |
| | 8289 | if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| | 8290 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 7898 | | 8291 | |
| 7899 | try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv); | | |
| 7900 | break :result Condition.fromCompareOperator( | 8292 | break :result Condition.fromCompareOperator( |
| 7901 | if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned, | 8293 | if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned, |
| 7902 | if (flipped) op.reverse() else op, | 8294 | result_op: { |
| | 8295 | const flipped_op = if (flipped) op.reverse() else op; |
| | 8296 | if (abi_size > 8) switch (flipped_op) { |
| | 8297 | .lt, .gte => {}, |
| | 8298 | .lte, .gt => unreachable, |
| | 8299 | .eq, .neq => { |
| | 8300 | const dst_addr_mcv: MCValue = switch (dst_mcv) { |
| | 8301 | .memory, .indirect, .load_frame => dst_mcv.address(), |
| | 8302 | else => .{ .register = try self.copyToTmpRegister( |
| | 8303 | Type.usize, |
| | 8304 | dst_mcv.address(), |
| | 8305 | ) }, |
| | 8306 | }; |
| | 8307 | const dst_addr_lock = if (dst_addr_mcv.getReg()) |reg| |
| | 8308 | self.register_manager.lockReg(reg) |
| | 8309 | else |
| | 8310 | null; |
| | 8311 | defer if (dst_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| | 8312 | |
| | 8313 | const src_addr_mcv: MCValue = switch (src_mcv) { |
| | 8314 | .memory, .indirect, .load_frame => src_mcv.address(), |
| | 8315 | else => .{ .register = try self.copyToTmpRegister( |
| | 8316 | Type.usize, |
| | 8317 | src_mcv.address(), |
| | 8318 | ) }, |
| | 8319 | }; |
| | 8320 | const src_addr_lock = if (src_addr_mcv.getReg()) |reg| |
| | 8321 | self.register_manager.lockReg(reg) |
| | 8322 | else |
| | 8323 | null; |
| | 8324 | defer if (src_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| | 8325 | |
| | 8326 | const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp); |
| | 8327 | const acc_reg = regs[0].to64(); |
| | 8328 | const locks = self.register_manager.lockRegsAssumeUnused(2, regs); |
| | 8329 | defer for (locks) |lock| self.register_manager.unlockReg(lock); |
| | 8330 | |
| | 8331 | const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable; |
| | 8332 | var limb_i: u16 = 0; |
| | 8333 | while (limb_i < limbs_len) : (limb_i += 1) { |
| | 8334 | const tmp_reg = regs[@min(limb_i, 1)].to64(); |
| | 8335 | try self.genSetReg( |
| | 8336 | tmp_reg, |
| | 8337 | Type.usize, |
| | 8338 | dst_addr_mcv.offset(limb_i * 8).deref(), |
| | 8339 | ); |
| | 8340 | try self.genBinOpMir( |
| | 8341 | .{ ._, .xor }, |
| | 8342 | Type.usize, |
| | 8343 | .{ .register = tmp_reg }, |
| | 8344 | src_addr_mcv.offset(limb_i * 8).deref(), |
| | 8345 | ); |
| | 8346 | if (limb_i > 0) try self.asmRegisterRegister( |
| | 8347 | .{ ._, .@"or" }, |
| | 8348 | acc_reg, |
| | 8349 | tmp_reg, |
| | 8350 | ); |
| | 8351 | } |
| | 8352 | try self.asmRegisterRegister(.{ ._, .@"test" }, acc_reg, acc_reg); |
| | 8353 | break :result_op flipped_op; |
| | 8354 | }, |
| | 8355 | }; |
| | 8356 | try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv); |
| | 8357 | break :result_op flipped_op; |
| | 8358 | }, |
| 7903 | ); | 8359 | ); |
| 7904 | }, | 8360 | }, |
| 7905 | .Float => result: { | 8361 | .Float => result: { |
| ... | @@ -9282,7 +9738,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9282,7 +9738,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9282 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, | 9738 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, |
| 9283 | else => null, | 9739 | else => null, |
| 9284 | }, | 9740 | }, |
| 9285 | .Float => switch (ty.floatBits(self.target.*)) { | 9741 | .Float => switch (ty.scalarType().floatBits(self.target.*)) { |
| 9286 | 16, 128 => switch (abi_size) { | 9742 | 16, 128 => switch (abi_size) { |
| 9287 | 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, | 9743 | 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| 9288 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, | 9744 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, |
| ... | @@ -9597,63 +10053,6 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -9597,63 +10053,6 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 9597 | } | 10053 | } |
| 9598 | } | 10054 | } |
| 9599 | | 10055 | |
| 9600 | /// Like `genInlineMemcpy` but copies value from a register to an address via dereferencing | | |
| 9601 | /// of destination register. | | |
| 9602 | /// Boils down to MOV r/m64, r64. | | |
| 9603 | fn genInlineMemcpyRegisterRegister( | | |
| 9604 | self: *Self, | | |
| 9605 | ty: Type, | | |
| 9606 | dst_reg: Register, | | |
| 9607 | src_reg: Register, | | |
| 9608 | offset: i32, | | |
| 9609 | ) InnerError!void { | | |
| 9610 | assert(dst_reg.bitSize() == 64); | | |
| 9611 | | | |
| 9612 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | | |
| 9613 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 9614 | | | |
| 9615 | const src_reg_lock = self.register_manager.lockReg(src_reg); | | |
| 9616 | defer if (src_reg_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 9617 | | | |
| 9618 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | | |
| 9619 | | | |
| 9620 | if (!math.isPowerOfTwo(abi_size)) { | | |
| 9621 | const tmp_reg = try self.copyToTmpRegister(ty, .{ .register = src_reg }); | | |
| 9622 | | | |
| 9623 | var next_offset = offset; | | |
| 9624 | var remainder = abi_size; | | |
| 9625 | while (remainder > 0) { | | |
| 9626 | const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder)); | | |
| 9627 | try self.asmMemoryRegister( | | |
| 9628 | .{ ._, .mov }, | | |
| 9629 | Memory.sib(Memory.PtrSize.fromSize(nearest_power_of_two), .{ | | |
| 9630 | .base = dst_reg, | | |
| 9631 | .disp = -next_offset, | | |
| 9632 | }), | | |
| 9633 | registerAlias(tmp_reg, nearest_power_of_two), | | |
| 9634 | ); | | |
| 9635 | | | |
| 9636 | if (nearest_power_of_two > 1) { | | |
| 9637 | try self.genShiftBinOpMir(.{ ._r, .sh }, ty, .{ .register = tmp_reg }, .{ | | |
| 9638 | .immediate = nearest_power_of_two * 8, | | |
| 9639 | }); | | |
| 9640 | } | | |
| 9641 | | | |
| 9642 | remainder -= nearest_power_of_two; | | |
| 9643 | next_offset -= nearest_power_of_two; | | |
| 9644 | } | | |
| 9645 | } else { | | |
| 9646 | try self.asmMemoryRegister( | | |
| 9647 | switch (src_reg.class()) { | | |
| 9648 | .general_purpose, .segment => .{ ._, .mov }, | | |
| 9649 | .sse => .{ ._ss, .mov }, | | |
| 9650 | }, | | |
| 9651 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = dst_reg, .disp = -offset }), | | |
| 9652 | registerAlias(src_reg, abi_size), | | |
| 9653 | ); | | |
| 9654 | } | | |
| 9655 | } | | |
| 9656 | | | |
| 9657 | fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue) InnerError!void { | 10056 | fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue) InnerError!void { |
| 9658 | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); | 10057 | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); |
| 9659 | try self.genSetReg(.rdi, Type.usize, dst_ptr); | 10058 | try self.genSetReg(.rdi, Type.usize, dst_ptr); |
| ... | @@ -9754,20 +10153,60 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9754,20 +10153,60 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 9754 | const result = result: { | 10153 | const result = result: { |
| 9755 | const dst_rc = regClassForType(dst_ty); | 10154 | const dst_rc = regClassForType(dst_ty); |
| 9756 | const src_rc = regClassForType(src_ty); | 10155 | const src_rc = regClassForType(src_ty); |
| 9757 | const operand = try self.resolveInst(ty_op.operand); | 10156 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 9758 | if (dst_rc.supersetOf(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) | | |
| 9759 | break :result operand; | | |
| 9760 | | 10157 | |
| 9761 | const operand_lock = switch (operand) { | 10158 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 9762 | .register => |reg| self.register_manager.lockReg(reg), | 10159 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 9763 | .register_overflow => |ro| self.register_manager.lockReg(ro.reg), | 10160 | |
| 9764 | else => null, | 10161 | const dst_mcv = if (dst_rc.supersetOf(src_rc) and |
| | 10162 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| | 10163 | src_mcv |
| | 10164 | else dst: { |
| | 10165 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 10166 | try self.genCopy( |
| | 10167 | if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty, |
| | 10168 | dst_mcv, |
| | 10169 | src_mcv, |
| | 10170 | ); |
| | 10171 | break :dst dst_mcv; |
| 9765 | }; | 10172 | }; |
| 9766 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 9767 | | 10173 | |
| 9768 | const dest = try self.allocRegOrMem(inst, true); | 10174 | const dst_signedness = |
| 9769 | try self.genCopy(if (!dest.isMemory() or operand.isMemory()) dst_ty else src_ty, dest, operand); | 10175 | if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned; |
| 9770 | break :result dest; | 10176 | const src_signedness = |
| | 10177 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; |
| | 10178 | const abi_size = @intCast(u16, dst_ty.abiSize(self.target.*)); |
| | 10179 | const bit_size = @intCast(u16, dst_ty.bitSize(self.target.*)); |
| | 10180 | const dst_limbs_len = math.divCeil(u16, bit_size, 64) catch unreachable; |
| | 10181 | if (dst_signedness != src_signedness and abi_size * 8 > bit_size) { |
| | 10182 | const high_reg = if (dst_mcv.isRegister()) |
| | 10183 | dst_mcv.getReg().? |
| | 10184 | else |
| | 10185 | try self.copyToTmpRegister( |
| | 10186 | Type.usize, |
| | 10187 | dst_mcv.address().offset((dst_limbs_len - 1) * 8).deref(), |
| | 10188 | ); |
| | 10189 | const high_lock = self.register_manager.lockReg(high_reg); |
| | 10190 | defer if (high_lock) |lock| self.register_manager.unlockReg(lock); |
| | 10191 | |
| | 10192 | var high_pl = Type.Payload.Bits{ |
| | 10193 | .base = .{ .tag = switch (dst_signedness) { |
| | 10194 | .signed => .int_signed, |
| | 10195 | .unsigned => .int_unsigned, |
| | 10196 | } }, |
| | 10197 | .data = bit_size % 64, |
| | 10198 | }; |
| | 10199 | const high_ty = Type.initPayload(&high_pl.base); |
| | 10200 | |
| | 10201 | try self.truncateRegister(high_ty, high_reg); |
| | 10202 | if (!dst_mcv.isRegister()) try self.genCopy( |
| | 10203 | Type.usize, |
| | 10204 | dst_mcv.address().offset((dst_limbs_len - 1) * 8).deref(), |
| | 10205 | .{ .register = high_reg }, |
| | 10206 | ); |
| | 10207 | } |
| | 10208 | |
| | 10209 | break :result dst_mcv; |
| 9771 | }; | 10210 | }; |
| 9772 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 10211 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 9773 | } | 10212 | } |
| ... | @@ -9803,7 +10242,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9803,7 +10242,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 9803 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; | 10242 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; |
| 9804 | const dst_ty = self.air.typeOfIndex(inst); | 10243 | const dst_ty = self.air.typeOfIndex(inst); |
| 9805 | | 10244 | |
| 9806 | const src_size = std.math.divCeil(u32, @max(switch (src_signedness) { | 10245 | const src_size = math.divCeil(u32, @max(switch (src_signedness) { |
| 9807 | .signed => src_bits, | 10246 | .signed => src_bits, |
| 9808 | .unsigned => src_bits + 1, | 10247 | .unsigned => src_bits + 1, |
| 9809 | }, 32), 8) catch unreachable; | 10248 | }, 32), 8) catch unreachable; |
| ... | @@ -9856,7 +10295,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9856,7 +10295,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 9856 | const dst_signedness = | 10295 | const dst_signedness = |
| 9857 | if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned; | 10296 | if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned; |
| 9858 | | 10297 | |
| 9859 | const dst_size = std.math.divCeil(u32, @max(switch (dst_signedness) { | 10298 | const dst_size = math.divCeil(u32, @max(switch (dst_signedness) { |
| 9860 | .signed => dst_bits, | 10299 | .signed => dst_bits, |
| 9861 | .unsigned => dst_bits + 1, | 10300 | .unsigned => dst_bits + 1, |
| 9862 | }, 32), 8) catch unreachable; | 10301 | }, 32), 8) catch unreachable; |
| ... | @@ -9912,14 +10351,30 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9912,14 +10351,30 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 9912 | | 10351 | |
| 9913 | const exp_mcv = try self.resolveInst(extra.expected_value); | 10352 | const exp_mcv = try self.resolveInst(extra.expected_value); |
| 9914 | if (val_abi_size > 8) { | 10353 | if (val_abi_size > 8) { |
| 9915 | try self.genSetReg(.rax, Type.usize, exp_mcv); | 10354 | const exp_addr_mcv: MCValue = switch (exp_mcv) { |
| 9916 | try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref()); | 10355 | .memory, .indirect, .load_frame => exp_mcv.address(), |
| | 10356 | else => .{ .register = try self.copyToTmpRegister(Type.usize, exp_mcv.address()) }, |
| | 10357 | }; |
| | 10358 | const exp_addr_lock = |
| | 10359 | if (exp_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| | 10360 | defer if (exp_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| | 10361 | |
| | 10362 | try self.genSetReg(.rax, Type.usize, exp_addr_mcv.deref()); |
| | 10363 | try self.genSetReg(.rdx, Type.usize, exp_addr_mcv.offset(8).deref()); |
| 9917 | } else try self.genSetReg(.rax, val_ty, exp_mcv); | 10364 | } else try self.genSetReg(.rax, val_ty, exp_mcv); |
| 9918 | | 10365 | |
| 9919 | const new_mcv = try self.resolveInst(extra.new_value); | 10366 | const new_mcv = try self.resolveInst(extra.new_value); |
| 9920 | const new_reg = if (val_abi_size > 8) new: { | 10367 | const new_reg = if (val_abi_size > 8) new: { |
| 9921 | try self.genSetReg(.rbx, Type.usize, new_mcv); | 10368 | const new_addr_mcv: MCValue = switch (new_mcv) { |
| 9922 | try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref()); | 10369 | .memory, .indirect, .load_frame => new_mcv.address(), |
| | 10370 | else => .{ .register = try self.copyToTmpRegister(Type.usize, new_mcv.address()) }, |
| | 10371 | }; |
| | 10372 | const new_addr_lock = |
| | 10373 | if (new_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| | 10374 | defer if (new_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| | 10375 | |
| | 10376 | try self.genSetReg(.rbx, Type.usize, new_addr_mcv.deref()); |
| | 10377 | try self.genSetReg(.rcx, Type.usize, new_addr_mcv.offset(8).deref()); |
| 9923 | break :new null; | 10378 | break :new null; |
| 9924 | } else try self.copyToTmpRegister(val_ty, new_mcv); | 10379 | } else try self.copyToTmpRegister(val_ty, new_mcv); |
| 9925 | const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; | 10380 | const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| ... | @@ -10763,8 +11218,8 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10763,8 +11218,8 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 10763 | } | 11218 | } |
| 10764 | | 11219 | |
| 10765 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 11220 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 10766 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 11221 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 10767 | _ = ty_op; | 11222 | _ = ty_pl; |
| 10768 | return self.fail("TODO implement airShuffle for x86_64", .{}); | 11223 | return self.fail("TODO implement airShuffle for x86_64", .{}); |
| 10769 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 11224 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 10770 | } | 11225 | } |
| ... | @@ -10894,6 +11349,12 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10894,6 +11349,12 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 10894 | const elem_off = @intCast(i32, elem_size * elem_i); | 11349 | const elem_off = @intCast(i32, elem_size * elem_i); |
| 10895 | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv); | 11350 | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv); |
| 10896 | } | 11351 | } |
| | 11352 | if (result_ty.sentinel()) |sentinel| try self.genSetMem( |
| | 11353 | .{ .frame = frame_index }, |
| | 11354 | @intCast(i32, elem_size * elements.len), |
| | 11355 | elem_ty, |
| | 11356 | try self.genTypedValue(.{ .ty = elem_ty, .val = sentinel }), |
| | 11357 | ); |
| 10897 | break :result .{ .load_frame = .{ .index = frame_index } }; | 11358 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 10898 | }, | 11359 | }, |
| 10899 | .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), | 11360 | .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), |