authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-19 00:56:59-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-05-19 00:56:59-07:00
logb873ce1e0e527a74fab9e55975ff1503e8f70b53
tree812ebfef4c58ef9ef9e4684b747570db2861256a
parent503302ceef7290027eedcc78c903be32fad90433
parent47405b1a1c29b8a907997af18291eb6eb1cf3e02
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15727 from jacobly0/x86_64-behavior

x86_64: behavior

17 files changed, 861 insertions(+), 293 deletions(-)

src/arch/x86_64/CodeGen.zig+706-245
......@@ -1271,6 +1271,27 @@ fn asmRegisterRegisterRegister(
12711271 });
12721272}
12731273
1274fn 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
12741295fn asmRegisterRegisterRegisterImmediate(
12751296 self: *Self,
12761297 tag: Mir.Inst.FixedTag,
......@@ -2203,6 +2224,10 @@ fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 {
22032224 return @min(alloc_align, @bitCast(u32, frame_addr.off) & (alloc_align - 1));
22042225}
22052226
2227fn 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
22062231fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
22072232 const frame_allocs_slice = self.frame_allocs.slice();
22082233 const frame_size = frame_allocs_slice.items(.abi_size);
......@@ -2594,115 +2619,202 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
25942619
25952620fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
25962621 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.*);
25972625
2598 const src_ty = self.air.typeOf(ty_op.operand);
2599 const src_int_info = src_ty.intInfo(self.target.*);
2600 const src_abi_size = @intCast(u32, src_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);
2626 const dst_ty = self.air.typeOfIndex(inst);
2627 const dst_int_info = dst_ty.intInfo(self.target.*);
2628 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
26072629
2608 const dst_ty = self.air.typeOfIndex(inst);
2609 const dst_int_info = dst_ty.intInfo(self.target.*);
2610 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
2611 const dst_mcv = if (dst_abi_size <= src_abi_size and
2612 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2613 src_mcv
2614 else
2615 try self.allocRegOrMem(inst, true);
2630 const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
2631 const extend = switch (src_int_info.signedness) {
2632 .signed => dst_int_info,
2633 .unsigned => src_int_info,
2634 }.signedness;
26162635
2617 const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
2618 const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and
2619 src_int_info.signedness == .signed) .signed else .unsigned;
2620 switch (dst_mcv) {
2621 .register => |dst_reg| {
2622 const min_abi_size = @min(dst_abi_size, src_abi_size);
2623 const tag: Mir.Inst.FixedTag = switch (signedness) {
2624 .signed => if (min_abi_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx },
2625 .unsigned => if (min_abi_size >= 4) .{ ._, .mov } else .{ ._, .movzx },
2626 };
2627 const dst_alias = switch (tag[1]) {
2628 .movsx => dst_reg.to64(),
2629 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
2630 else => unreachable,
2636 const src_mcv = try self.resolveInst(ty_op.operand);
2637 const src_storage_bits = switch (src_mcv) {
2638 .register, .register_offset => 64,
2639 .load_frame => |frame_addr| self.getFrameAddrSize(frame_addr) * 8,
2640 else => src_int_info.bits,
2641 };
2642
2643 const dst_mcv = if (dst_int_info.bits <= src_storage_bits and
2644 self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
2645 const dst_mcv = try self.allocRegOrMem(inst, true);
2646 try self.genCopy(min_ty, dst_mcv, src_mcv);
2647 break :dst dst_mcv;
2648 };
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,
26312679 };
2632 switch (src_mcv) {
2633 .register => |src_reg| {
2634 try self.asmRegisterRegister(
2635 tag,
2636 dst_alias,
2637 registerAlias(src_reg, min_abi_size),
2680 const high_ty = Type.initPayload(&high_pl.base);
2681 try self.truncateRegister(high_ty, high_reg);
2682 try self.genCopy(Type.usize, high_mcv, .{ .register = high_reg });
2683 }
2684
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 },
26382695 );
2696 break :extend extend_mcv;
26392697 },
2640 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
2641 tag,
2642 dst_alias,
2643 src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)),
2644 ),
2645 else => return self.fail("TODO airIntCast from {s} to {s}", .{
2646 @tagName(src_mcv),
2647 @tagName(dst_mcv),
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 });
2698 .unsigned => .{ .immediate = 0 },
2699 },
2700 .{ .immediate = (dst_limbs_len - src_limbs_len) * 8 },
2701 );
2702
2703 break :result dst_mcv;
2704 };
2705 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26782706}
26792707
26802708fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
26812709 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
26822710
26832711 const dst_ty = self.air.typeOfIndex(inst);
2684 const dst_abi_size = dst_ty.abiSize(self.target.*);
2685 if (dst_abi_size > 8) {
2686 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});
2687 }
2712 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
2713 const src_ty = self.air.typeOf(ty_op.operand);
2714 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
26882715
2689 const src_mcv = try self.resolveInst(ty_op.operand);
2690 const src_lock = switch (src_mcv) {
2691 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2692 else => null,
2693 };
2694 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
2716 const result = result: {
2717 const src_mcv = try self.resolveInst(ty_op.operand);
2718 const src_lock =
2719 if (src_mcv.getReg()) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
2720 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
26952721
2696 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2697 src_mcv
2698 else
2699 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
2722 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2723 src_mcv
2724 else
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 });
27002757
2701 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
2702 // have to be removed. this only happens if the dst if not a power-of-two size.
2703 if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64());
2758 var mask_pl = Value.Payload.U64{
2759 .base = .{ .tag = .int_u64 },
2760 .data = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits),
2761 };
2762 const mask_val = Value.initPayload(&mask_pl.base);
27042763
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 });
27062818}
27072819
27082820fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2855,20 +2967,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
28552967 defer self.register_manager.unlockReg(limit_lock);
28562968
28572969 const reg_bits = self.regBitSize(ty);
2970 const reg_extra_bits = self.regExtraBits(ty);
28582971 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 }
28592975 try self.genSetReg(limit_reg, ty, dst_mcv);
28602976 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
28612977 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
28622978 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
28632979 });
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);
28642994 break :cc .o;
28652995 } else cc: {
28662996 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.*)),
28682998 });
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 }
28693005 break :cc .c;
28703006 };
2871 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
28723007
28733008 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
28743009 try self.asmCmovccRegisterRegister(
......@@ -2877,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
28773012 cc,
28783013 );
28793014
3015 if (reg_extra_bits > 0 and ty.isSignedInt()) {
3016 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3017 }
3018
28803019 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
28813020}
28823021
......@@ -2906,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
29063045 defer self.register_manager.unlockReg(limit_lock);
29073046
29083047 const reg_bits = self.regBitSize(ty);
3048 const reg_extra_bits = self.regExtraBits(ty);
29093049 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 }
29103053 try self.genSetReg(limit_reg, ty, dst_mcv);
29113054 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
29123055 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
29133056 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
29143057 });
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);
29153072 break :cc .o;
29163073 } else cc: {
29173074 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });
3075 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
29183076 break :cc .c;
29193077 };
2920 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
29213078
29223079 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
29233080 try self.asmCmovccRegisterRegister(
......@@ -2926,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
29263083 cc,
29273084 );
29283085
3086 if (reg_extra_bits > 0 and ty.isSignedInt()) {
3087 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3088 }
3089
29293090 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
29303091}
29313092
......@@ -3222,34 +3383,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
32223383 self.regExtraBits(dst_ty)
32233384 else
32243385 dst_info.bits % 64;
3225 const partial_mcv = if (dst_info.signedness == .signed and extra_bits > 0) dst: {
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);
3386 const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
32533387
32543388 switch (partial_mcv) {
32553389 .register => |reg| if (extra_bits == 0) {
......@@ -3262,9 +3396,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
32623396 break :result .{ .load_frame = .{ .index = frame_index } };
32633397 },
32643398 else => {
3265 // For now, this is the only supported multiply that doesn't fit in a register,
3266 // so cc being set is impossible.
3267
3399 // For now, this is the only supported multiply that doesn't fit in a register.
32683400 assert(dst_info.bits <= 128 and src_pl.data == 64);
32693401
32703402 const frame_index =
......@@ -3280,7 +3412,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
32803412 .{ .frame = frame_index },
32813413 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
32823414 tuple_ty.structFieldType(1),
3283 .{ .immediate = 0 },
3415 .{ .immediate = 0 }, // cc being set is impossible
32843416 );
32853417 } else try self.genSetFrameTruncatedOverflowCompare(
32863418 tuple_ty,
......@@ -5558,31 +5690,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
55585690 const dst_lock = self.register_manager.lockReg(dst_reg);
55595691 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
55605692
5561 // Shift by struct_field_offset.
55625693 try self.genShiftBinOpMir(
55635694 .{ ._r, .sh },
55645695 Type.usize,
55655696 dst_mcv,
55665697 .{ .immediate = field_off },
55675698 );
5568
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 }
5699 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
55865700
55875701 break :result if (field_rc.supersetOf(gp))
55885702 dst_mcv
......@@ -6224,12 +6338,26 @@ fn genBinOp(
62246338 lhs_air: Air.Inst.Ref,
62256339 rhs_air: Air.Inst.Ref,
62266340) !MCValue {
6227 const lhs_mcv = try self.resolveInst(lhs_air);
6228 const rhs_mcv = try self.resolveInst(rhs_air);
62296341 const lhs_ty = self.air.typeOf(lhs_air);
62306342 const rhs_ty = self.air.typeOf(rhs_air);
62316343 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
62326344
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);
62336361 switch (lhs_mcv) {
62346362 .immediate => |imm| switch (imm) {
62356363 0 => switch (air_tag) {
......@@ -6300,7 +6428,16 @@ fn genBinOp(
63006428 };
63016429 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
63026430
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
63046441 if (!vec_op) {
63056442 switch (air_tag) {
63066443 .add,
......@@ -7009,18 +7146,26 @@ fn genBinOp(
70097146 })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{
70107147 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),
70117148 });
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
70127157 if (self.hasFeature(.avx)) {
7013 const src1_alias =
7158 const lhs_reg =
70147159 if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
70157160 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
70167161 mir_tag,
70177162 dst_reg,
7018 src1_alias,
7163 lhs_reg,
70197164 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
70207165 ) else try self.asmRegisterRegisterRegister(
70217166 mir_tag,
70227167 dst_reg,
7023 src1_alias,
7168 lhs_reg,
70247169 registerAlias(if (src_mcv.isRegister())
70257170 src_mcv.getReg().?
70267171 else
......@@ -7041,9 +7186,10 @@ fn genBinOp(
70417186 try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
70427187 );
70437188 }
7189
70447190 switch (air_tag) {
70457191 .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(
70477193 lhs_ty,
70487194 dst_reg,
70497195 .{ .register = dst_reg },
......@@ -7052,11 +7198,240 @@ fn genBinOp(
70527198 .div_floor => 0b1_0_01,
70537199 else => unreachable,
70547200 },
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 }),
70567204 .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 },
70587432 else => unreachable,
70597433 }
7434
70607435 return dst_mcv;
70617436}
70627437
......@@ -7882,24 +8257,105 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
78828257 const result = MCValue{
78838258 .eflags = switch (ty.zigTypeTag()) {
78848259 else => result: {
7885 var flipped = false;
7886 const dst_mcv: MCValue = if (lhs_mcv.isRegister() or lhs_mcv.isMemory())
7887 lhs_mcv
7888 else if (rhs_mcv.isRegister() or rhs_mcv.isMemory()) dst: {
7889 flipped = true;
7890 break :dst rhs_mcv;
7891 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
7892 const dst_lock = switch (dst_mcv) {
7893 .register => |reg| self.register_manager.lockReg(reg),
7894 else => null,
8260 const abi_size = @intCast(u16, ty.abiSize(self.target.*));
8261 const may_flip: enum {
8262 may_flip,
8263 must_flip,
8264 must_not_flip,
8265 } = if (abi_size > 8) switch (op) {
8266 .lt, .gte => .must_not_flip,
8267 .lte, .gt => .must_flip,
8268 .eq, .neq => .may_flip,
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;
78958282 };
8283 const dst_lock =
8284 if (dst_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
78968285 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
8286
78978287 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);
78988291
7899 try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv);
79008292 break :result Condition.fromCompareOperator(
79018293 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 },
79038359 );
79048360 },
79058361 .Float => result: {
......@@ -9282,7 +9738,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
92829738 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null,
92839739 else => null,
92849740 },
9285 .Float => switch (ty.floatBits(self.target.*)) {
9741 .Float => switch (ty.scalarType().floatBits(self.target.*)) {
92869742 16, 128 => switch (abi_size) {
92879743 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
92889744 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
959710053 }
959810054}
959910055
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.
9603fn 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
965710056fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue) InnerError!void {
965810057 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
965910058 try self.genSetReg(.rdi, Type.usize, dst_ptr);
......@@ -9754,20 +10153,60 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
975410153 const result = result: {
975510154 const dst_rc = regClassForType(dst_ty);
975610155 const src_rc = regClassForType(src_ty);
9757 const operand = 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;
10156 const src_mcv = try self.resolveInst(ty_op.operand);
976010157
9761 const operand_lock = switch (operand) {
9762 .register => |reg| self.register_manager.lockReg(reg),
9763 .register_overflow => |ro| self.register_manager.lockReg(ro.reg),
9764 else => null,
10158 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
10159 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
10160
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;
976510172 };
9766 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
976710173
9768 const dest = try self.allocRegOrMem(inst, true);
9769 try self.genCopy(if (!dest.isMemory() or operand.isMemory()) dst_ty else src_ty, dest, operand);
9770 break :result dest;
10174 const dst_signedness =
10175 if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned;
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;
977110210 };
977210211 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
977310212}
......@@ -9803,7 +10242,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
980310242 if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned;
980410243 const dst_ty = self.air.typeOfIndex(inst);
980510244
9806 const src_size = std.math.divCeil(u32, @max(switch (src_signedness) {
10245 const src_size = math.divCeil(u32, @max(switch (src_signedness) {
980710246 .signed => src_bits,
980810247 .unsigned => src_bits + 1,
980910248 }, 32), 8) catch unreachable;
......@@ -9856,7 +10295,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
985610295 const dst_signedness =
985710296 if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned;
985810297
9859 const dst_size = std.math.divCeil(u32, @max(switch (dst_signedness) {
10298 const dst_size = math.divCeil(u32, @max(switch (dst_signedness) {
986010299 .signed => dst_bits,
986110300 .unsigned => dst_bits + 1,
986210301 }, 32), 8) catch unreachable;
......@@ -9912,14 +10351,30 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
991210351
991310352 const exp_mcv = try self.resolveInst(extra.expected_value);
991410353 if (val_abi_size > 8) {
9915 try self.genSetReg(.rax, Type.usize, exp_mcv);
9916 try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref());
10354 const exp_addr_mcv: MCValue = switch (exp_mcv) {
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());
991710364 } else try self.genSetReg(.rax, val_ty, exp_mcv);
991810365
991910366 const new_mcv = try self.resolveInst(extra.new_value);
992010367 const new_reg = if (val_abi_size > 8) new: {
9921 try self.genSetReg(.rbx, Type.usize, new_mcv);
9922 try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref());
10368 const new_addr_mcv: MCValue = switch (new_mcv) {
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());
992310378 break :new null;
992410379 } else try self.copyToTmpRegister(val_ty, new_mcv);
992510380 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 {
1076311218}
1076411219
1076511220fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
10766 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
10767 _ = ty_op;
11221 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
11222 _ = ty_pl;
1076811223 return self.fail("TODO implement airShuffle for x86_64", .{});
1076911224 //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1077011225}
......@@ -10894,6 +11349,12 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1089411349 const elem_off = @intCast(i32, elem_size * elem_i);
1089511350 try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv);
1089611351 }
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 );
1089711358 break :result .{ .load_frame = .{ .index = frame_index } };
1089811359 },
1089911360 .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}),
src/arch/x86_64/Encoding.zig+23-13
......@@ -178,7 +178,7 @@ pub fn format(
178178 try writer.print("+{s} ", .{tag});
179179 },
180180 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
181 .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi, .mvr => try writer.writeAll("/r "),
181 .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr => try writer.writeAll("/r "),
182182 }
183183
184184 switch (encoding.data.op_en) {
......@@ -202,7 +202,8 @@ pub fn format(
202202 };
203203 try writer.print("{s} ", .{tag});
204204 },
205 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm, .mvr => {},
205 .rvmr => try writer.writeAll("/is4 "),
206 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr => {},
206207 }
207208
208209 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
......@@ -262,6 +263,7 @@ pub const Mnemonic = enum {
262263 fisttp, fld,
263264 // MMX
264265 movd, movq,
266 packssdw, packsswb, packuswb,
265267 paddb, paddd, paddq, paddsb, paddsw, paddusb, paddusw, paddw,
266268 pand, pandn, por, pxor,
267269 pmulhw, pmullw,
......@@ -270,7 +272,7 @@ pub const Mnemonic = enum {
270272 addps, addss,
271273 andps,
272274 andnps,
273 cmpss,
275 cmpps, cmpss,
274276 cvtpi2ps, cvtps2pi, cvtsi2ss, cvtss2si, cvttps2pi, cvttss2si,
275277 divps, divss,
276278 maxps, maxss,
......@@ -290,7 +292,7 @@ pub const Mnemonic = enum {
290292 addpd, addsd,
291293 andpd,
292294 andnpd,
293 //cmpsd,
295 cmppd, //cmpsd,
294296 cvtdq2pd, cvtdq2ps, cvtpd2dq, cvtpd2pi, cvtpd2ps, cvtpi2pd,
295297 cvtps2dq, cvtps2pd, cvtsd2si, cvtsd2ss, cvtsi2sd, cvtss2sd,
296298 cvttpd2dq, cvttpd2pi, cvttps2dq, cvttsd2si,
......@@ -315,8 +317,10 @@ pub const Mnemonic = enum {
315317 // SSE3
316318 movddup, movshdup, movsldup,
317319 // SSE4.1
320 blendpd, blendps, blendvpd, blendvps,
318321 extractps,
319322 insertps,
323 packusdw,
320324 pextrb, pextrd, pextrq,
321325 pinsrb, pinsrd, pinsrq,
322326 pmaxsb, pmaxsd, pmaxud, pmaxuw, pminsb, pminsd, pminud, pminuw,
......@@ -325,7 +329,9 @@ pub const Mnemonic = enum {
325329 // AVX
326330 vaddpd, vaddps, vaddsd, vaddss,
327331 vandnpd, vandnps, vandpd, vandps,
332 vblendpd, vblendps, vblendvpd, vblendvps,
328333 vbroadcastf128, vbroadcastsd, vbroadcastss,
334 vcmppd, vcmpps, vcmpsd, vcmpss,
329335 vcvtdq2pd, vcvtdq2ps, vcvtpd2dq, vcvtpd2ps,
330336 vcvtps2dq, vcvtps2pd, vcvtsd2si, vcvtsd2ss,
331337 vcvtsi2sd, vcvtsi2ss, vcvtss2sd, vcvtss2si,
......@@ -347,6 +353,7 @@ pub const Mnemonic = enum {
347353 vmovupd, vmovups,
348354 vmulpd, vmulps, vmulsd, vmulss,
349355 vorpd, vorps,
356 vpackssdw, vpacksswb, vpackusdw, vpackuswb,
350357 vpaddb, vpaddd, vpaddq, vpaddsb, vpaddsw, vpaddusb, vpaddusw, vpaddw,
351358 vpand, vpandn,
352359 vpextrb, vpextrd, vpextrq, vpextrw,
......@@ -385,7 +392,7 @@ pub const OpEn = enum {
385392 fd, td,
386393 m1, mc, mi, mr, rm,
387394 rmi, mri, mrc,
388 vmi, rvm, rvmi, mvr,
395 rm0, vmi, rvm, rvmr, rvmi, mvr,
389396 // zig fmt: on
390397};
391398
......@@ -407,7 +414,7 @@ pub const Op = enum {
407414 moffs,
408415 sreg,
409416 st, mm, mm_m64,
410 xmm, xmm_m32, xmm_m64, xmm_m128,
417 xmm0, xmm, xmm_m32, xmm_m64, xmm_m128,
411418 ymm, ymm_m256,
412419 // zig fmt: on
413420
......@@ -436,7 +443,9 @@ pub const Op = enum {
436443 .segment => .sreg,
437444 .x87 => .st,
438445 .mmx => .mm,
439 .sse => switch (reg.bitSize()) {
446 .sse => if (reg == .xmm0)
447 .xmm0
448 else switch (reg.bitSize()) {
440449 128 => .xmm,
441450 256 => .ymm,
442451 else => unreachable,
......@@ -494,7 +503,7 @@ pub const Op = enum {
494503 .eax, .r32, .rm32, .r32_m16 => unreachable,
495504 .rax, .r64, .rm64, .r64_m16 => unreachable,
496505 .st, .mm, .mm_m64 => unreachable,
497 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
506 .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
498507 .ymm, .ymm_m256 => unreachable,
499508 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
500509 .unity => 1,
......@@ -516,7 +525,7 @@ pub const Op = enum {
516525 .eax, .r32, .rm32, .r32_m8, .r32_m16 => 32,
517526 .rax, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
518527 .st => 80,
519 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
528 .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
520529 .ymm, .ymm_m256 => 256,
521530 };
522531 }
......@@ -526,7 +535,8 @@ pub const Op = enum {
526535 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
527536 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
528537 .rel8, .rel16, .rel32 => unreachable,
529 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .st, .mm, .xmm, .ymm => unreachable,
538 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64 => unreachable,
539 .st, .mm, .xmm0, .xmm, .ymm => unreachable,
530540 .m8, .rm8, .r32_m8 => 8,
531541 .m16, .rm16, .r32_m16, .r64_m16 => 16,
532542 .m32, .rm32, .xmm_m32 => 32,
......@@ -558,7 +568,7 @@ pub const Op = enum {
558568 .rm8, .rm16, .rm32, .rm64,
559569 .r32_m8, .r32_m16, .r64_m16,
560570 .st, .mm, .mm_m64,
561 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
571 .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
562572 .ymm, .ymm_m256,
563573 => true,
564574 else => false,
......@@ -612,7 +622,7 @@ pub const Op = enum {
612622 .sreg => .segment,
613623 .st => .x87,
614624 .mm, .mm_m64 => .mmx,
615 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
625 .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
616626 .ymm, .ymm_m256 => .sse,
617627 };
618628 }
......@@ -629,7 +639,7 @@ pub const Op = enum {
629639 else => {
630640 if (op.isRegister() and target.isRegister()) {
631641 return switch (target) {
632 .cl, .al, .ax, .eax, .rax => op == target,
642 .cl, .al, .ax, .eax, .rax, .xmm0 => op == target,
633643 else => op.class() == target.class() and op.regBitSize() == target.regBitSize(),
634644 };
635645 }
src/arch/x86_64/Lower.zig+7
......@@ -377,6 +377,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
377377 .r => inst.data.r.fixes,
378378 .rr => inst.data.rr.fixes,
379379 .rrr => inst.data.rrr.fixes,
380 .rrrr => inst.data.rrrr.fixes,
380381 .rrri => inst.data.rrri.fixes,
381382 .rri_s, .rri_u => inst.data.rri.fixes,
382383 .ri_s, .ri_u => inst.data.ri.fixes,
......@@ -430,6 +431,12 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
430431 .{ .reg = inst.data.rrr.r2 },
431432 .{ .reg = inst.data.rrr.r3 },
432433 },
434 .rrrr => &.{
435 .{ .reg = inst.data.rrrr.r1 },
436 .{ .reg = inst.data.rrrr.r2 },
437 .{ .reg = inst.data.rrrr.r3 },
438 .{ .reg = inst.data.rrrr.r4 },
439 },
433440 .rrri => &.{
434441 .{ .reg = inst.data.rrri.r1 },
435442 .{ .reg = inst.data.rrri.r2 },
src/arch/x86_64/Mir.zig+28
......@@ -446,6 +446,12 @@ pub const Inst = struct {
446446 /// Bitwise logical xor of packed double-precision floating-point values
447447 xor,
448448
449 /// Pack with signed saturation
450 ackssw,
451 /// Pack with signed saturation
452 ackssd,
453 /// Pack with unsigned saturation
454 ackusw,
449455 /// Add packed signed integers with signed saturation
450456 adds,
451457 /// Add packed unsigned integers with unsigned saturation
......@@ -596,6 +602,18 @@ pub const Inst = struct {
596602 /// Replicate single floating-point values
597603 movsldup,
598604
605 /// Pack with unsigned saturation
606 ackusd,
607 /// Blend packed single-precision floating-point values
608 /// Blend scalar single-precision floating-point values
609 /// Blend packed double-precision floating-point values
610 /// Blend scalar double-precision floating-point values
611 blend,
612 /// Variable blend packed single-precision floating-point values
613 /// Variable blend scalar single-precision floating-point values
614 /// Variable blend packed double-precision floating-point values
615 /// Variable blend scalar double-precision floating-point values
616 blendv,
599617 /// Extract packed floating-point values
600618 extract,
601619 /// Insert scalar single-precision floating-point value
......@@ -651,6 +669,9 @@ pub const Inst = struct {
651669 /// Register, register, register operands.
652670 /// Uses `rrr` payload.
653671 rrr,
672 /// Register, register, register, register operands.
673 /// Uses `rrrr` payload.
674 rrrr,
654675 /// Register, register, register, immediate (byte) operands.
655676 /// Uses `rrri` payload.
656677 rrri,
......@@ -870,6 +891,13 @@ pub const Inst = struct {
870891 r2: Register,
871892 r3: Register,
872893 },
894 rrrr: struct {
895 fixes: Fixes = ._,
896 r1: Register,
897 r2: Register,
898 r3: Register,
899 r4: Register,
900 },
873901 rrri: struct {
874902 fixes: Fixes = ._,
875903 r1: Register,
src/arch/x86_64/encoder.zig+16-15
......@@ -226,8 +226,8 @@ pub const Instruction = struct {
226226 else => {
227227 const mem_op = switch (data.op_en) {
228228 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
229 .rm, .rmi, .vmi => inst.ops[1],
230 .rvm, .rvmi => inst.ops[2],
229 .rm, .rmi, .rm0, .vmi => inst.ops[1],
230 .rvm, .rvmr, .rvmi => inst.ops[2],
231231 else => unreachable,
232232 };
233233 switch (mem_op) {
......@@ -235,7 +235,7 @@ pub const Instruction = struct {
235235 const rm = switch (data.op_en) {
236236 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
237237 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
238 .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(),
238 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0].reg.lowEnc(),
239239 .mvr => inst.ops[2].reg.lowEnc(),
240240 else => unreachable,
241241 };
......@@ -245,7 +245,7 @@ pub const Instruction = struct {
245245 const op = switch (data.op_en) {
246246 .m, .mi, .m1, .mc, .vmi => .none,
247247 .mr, .mri, .mrc => inst.ops[1],
248 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
248 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0],
249249 .mvr => inst.ops[2],
250250 else => unreachable,
251251 };
......@@ -257,6 +257,7 @@ pub const Instruction = struct {
257257 switch (data.op_en) {
258258 .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
259259 .rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
260 .rvmr => try encoder.imm8(@as(u8, inst.ops[3].reg.enc()) << 4),
260261 .rvmi => try encodeImm(inst.ops[3].imm, data.ops[3], encoder),
261262 else => {},
262263 }
......@@ -298,7 +299,7 @@ pub const Instruction = struct {
298299 .i, .zi, .o, .oi, .d, .np => null,
299300 .fd => inst.ops[1].mem.base().reg,
300301 .td => inst.ops[0].mem.base().reg,
301 .rm, .rmi => if (inst.ops[1].isSegmentRegister())
302 .rm, .rmi, .rm0 => if (inst.ops[1].isSegmentRegister())
302303 switch (inst.ops[1]) {
303304 .reg => |reg| reg,
304305 .mem => |mem| mem.base().reg,
......@@ -314,7 +315,7 @@ pub const Instruction = struct {
314315 }
315316 else
316317 null,
317 .vmi, .rvm, .rvmi, .mvr => unreachable,
318 .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
318319 };
319320 if (segment_override) |seg| {
320321 legacy.setSegmentOverride(seg);
......@@ -333,23 +334,23 @@ pub const Instruction = struct {
333334 switch (op_en) {
334335 .np, .i, .zi, .fd, .td, .d => {},
335336 .o, .oi => rex.b = inst.ops[0].reg.isExtended(),
336 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {
337 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0 => {
337338 const r_op = switch (op_en) {
338 .rm, .rmi => inst.ops[0],
339 .rm, .rmi, .rm0 => inst.ops[0],
339340 .mr, .mri, .mrc => inst.ops[1],
340341 else => .none,
341342 };
342343 rex.r = r_op.isBaseExtended();
343344
344345 const b_x_op = switch (op_en) {
345 .rm, .rmi => inst.ops[1],
346 .rm, .rmi, .rm0 => inst.ops[1],
346347 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
347348 else => unreachable,
348349 };
349350 rex.b = b_x_op.isBaseExtended();
350351 rex.x = b_x_op.isIndexExtended();
351352 },
352 .vmi, .rvm, .rvmi, .mvr => unreachable,
353 .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
353354 }
354355
355356 try encoder.rex(rex);
......@@ -367,9 +368,9 @@ pub const Instruction = struct {
367368 switch (op_en) {
368369 .np, .i, .zi, .fd, .td, .d => {},
369370 .o, .oi => vex.b = inst.ops[0].reg.isExtended(),
370 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi, .mvr => {
371 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => {
371372 const r_op = switch (op_en) {
372 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
373 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0],
373374 .mr, .mri, .mrc => inst.ops[1],
374375 .mvr => inst.ops[2],
375376 .m, .mi, .m1, .mc, .vmi => .none,
......@@ -378,9 +379,9 @@ pub const Instruction = struct {
378379 vex.r = r_op.isBaseExtended();
379380
380381 const b_x_op = switch (op_en) {
381 .rm, .rmi, .vmi => inst.ops[1],
382 .rm, .rmi, .rm0, .vmi => inst.ops[1],
382383 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
383 .rvm, .rvmi => inst.ops[2],
384 .rvm, .rvmr, .rvmi => inst.ops[2],
384385 else => unreachable,
385386 };
386387 vex.b = b_x_op.isBaseExtended();
......@@ -408,7 +409,7 @@ pub const Instruction = struct {
408409 switch (op_en) {
409410 else => {},
410411 .vmi => vex.v = inst.ops[0].reg,
411 .rvm, .rvmi => vex.v = inst.ops[1].reg,
412 .rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,
412413 }
413414
414415 try encoder.vex(vex);
src/arch/x86_64/encodings.zig+55
......@@ -846,6 +846,8 @@ pub const table = [_]Entry{
846846
847847 .{ .andps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x54 }, 0, .none, .sse },
848848
849 .{ .cmpps, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x0f, 0xc2 }, 0, .none, .sse },
850
849851 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .none, .sse },
850852
851853 .{ .cvtpi2ps, .rm, &.{ .xmm, .mm_m64 }, &.{ 0x0f, 0x2a }, 0, .none, .sse },
......@@ -917,6 +919,8 @@ pub const table = [_]Entry{
917919
918920 .{ .andpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x54 }, 0, .none, .sse2 },
919921
922 .{ .cmppd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0xc2 }, 0, .none, .sse2 },
923
920924 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .none, .sse2 },
921925
922926 .{ .cvtdq2pd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0xe6 }, 0, .none, .sse2 },
......@@ -992,6 +996,11 @@ pub const table = [_]Entry{
992996
993997 .{ .orpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x56 }, 0, .none, .sse2 },
994998
999 .{ .packsswb, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x63 }, 0, .none, .sse2 },
1000 .{ .packssdw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6b }, 0, .none, .sse2 },
1001
1002 .{ .packuswb, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x67 }, 0, .none, .sse2 },
1003
9951004 .{ .paddb, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xfc }, 0, .none, .sse2 },
9961005 .{ .paddw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xfd }, 0, .none, .sse2 },
9971006 .{ .paddd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xfe }, 0, .none, .sse2 },
......@@ -1085,10 +1094,20 @@ pub const table = [_]Entry{
10851094 .{ .movsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .none, .sse3 },
10861095
10871096 // SSE4.1
1097 .{ .blendpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0d }, 0, .none, .sse4_1 },
1098
1099 .{ .blendps, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0c }, 0, .none, .sse4_1 },
1100
1101 .{ .blendvpd, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x66, 0x0f, 0x38, 0x15 }, 0, .none, .sse4_1 },
1102
1103 .{ .blendvps, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x66, 0x0f, 0x38, 0x14 }, 0, .none, .sse4_1 },
1104
10881105 .{ .extractps, .mri, &.{ .rm32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x17 }, 0, .none, .sse4_1 },
10891106
10901107 .{ .insertps, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x21 }, 0, .none, .sse4_1 },
10911108
1109 .{ .packusdw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x2b }, 0, .none, .sse4_1 },
1110
10921111 .{ .pextrb, .mri, &.{ .r32_m8, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x14 }, 0, .none, .sse4_1 },
10931112 .{ .pextrd, .mri, &.{ .rm32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .none, .sse4_1 },
10941113 .{ .pextrq, .mri, &.{ .rm64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .long, .sse4_1 },
......@@ -1146,11 +1165,33 @@ pub const table = [_]Entry{
11461165 .{ .vandps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x54 }, 0, .vex_128_wig, .avx },
11471166 .{ .vandps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x54 }, 0, .vex_256_wig, .avx },
11481167
1168 .{ .vblendpd, .rvmi, &.{ .xmm, .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0d }, 0, .vex_128_wig, .avx },
1169 .{ .vblendpd, .rvmi, &.{ .ymm, .ymm, .ymm_m256, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0d }, 0, .vex_256_wig, .avx },
1170
1171 .{ .vblendps, .rvmi, &.{ .xmm, .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0c }, 0, .vex_128_wig, .avx },
1172 .{ .vblendps, .rvmi, &.{ .ymm, .ymm, .ymm_m256, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0c }, 0, .vex_256_wig, .avx },
1173
1174 .{ .vblendvpd, .rvmr, &.{ .xmm, .xmm, .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x3a, 0x4b }, 0, .vex_128_w0, .avx },
1175 .{ .vblendvpd, .rvmr, &.{ .ymm, .ymm, .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x3a, 0x4b }, 0, .vex_256_w0, .avx },
1176
1177 .{ .vblendvps, .rvmr, &.{ .xmm, .xmm, .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x3a, 0x4a }, 0, .vex_128_w0, .avx },
1178 .{ .vblendvps, .rvmr, &.{ .ymm, .ymm, .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x3a, 0x4a }, 0, .vex_256_w0, .avx },
1179
11491180 .{ .vbroadcastss, .rm, &.{ .xmm, .m32 }, &.{ 0x66, 0x0f, 0x38, 0x18 }, 0, .vex_128_w0, .avx },
11501181 .{ .vbroadcastss, .rm, &.{ .ymm, .m32 }, &.{ 0x66, 0x0f, 0x38, 0x18 }, 0, .vex_256_w0, .avx },
11511182 .{ .vbroadcastsd, .rm, &.{ .ymm, .m64 }, &.{ 0x66, 0x0f, 0x38, 0x19 }, 0, .vex_256_w0, .avx },
11521183 .{ .vbroadcastf128, .rm, &.{ .ymm, .m128 }, &.{ 0x66, 0x0f, 0x38, 0x1a }, 0, .vex_256_w0, .avx },
11531184
1185 .{ .vcmppd, .rvmi, &.{ .xmm, .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0xc2 }, 0, .vex_128_wig, .avx },
1186 .{ .vcmppd, .rvmi, &.{ .ymm, .ymm, .ymm_m256, .imm8 }, &.{ 0x66, 0x0f, 0xc2 }, 0, .vex_256_wig, .avx },
1187
1188 .{ .vcmpps, .rvmi, &.{ .xmm, .xmm, .xmm_m128, .imm8 }, &.{ 0x0f, 0xc2 }, 0, .vex_128_wig, .avx },
1189 .{ .vcmpps, .rvmi, &.{ .ymm, .ymm, .ymm_m256, .imm8 }, &.{ 0x0f, 0xc2 }, 0, .vex_256_wig, .avx },
1190
1191 .{ .vcmpsd, .rvmi, &.{ .xmm, .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .vex_lig_wig, .avx },
1192
1193 .{ .vcmpss, .rvmi, &.{ .xmm, .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .vex_lig_wig, .avx },
1194
11541195 .{ .vcvtdq2pd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0xe6 }, 0, .vex_128_wig, .avx },
11551196 .{ .vcvtdq2pd, .rm, &.{ .ymm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0xe6 }, 0, .vex_256_wig, .avx },
11561197
......@@ -1312,6 +1353,13 @@ pub const table = [_]Entry{
13121353 .{ .vorps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x56 }, 0, .vex_128_wig, .avx },
13131354 .{ .vorps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x56 }, 0, .vex_256_wig, .avx },
13141355
1356 .{ .vpacksswb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x63 }, 0, .vex_128_wig, .avx },
1357 .{ .vpackssdw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6b }, 0, .vex_128_wig, .avx },
1358
1359 .{ .vpackusdw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x2b }, 0, .vex_128_wig, .avx },
1360
1361 .{ .vpackuswb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x67 }, 0, .vex_128_wig, .avx },
1362
13151363 .{ .vpaddb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xfc }, 0, .vex_128_wig, .avx },
13161364 .{ .vpaddw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xfd }, 0, .vex_128_wig, .avx },
13171365 .{ .vpaddd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xfe }, 0, .vex_128_wig, .avx },
......@@ -1474,6 +1522,13 @@ pub const table = [_]Entry{
14741522 .{ .vbroadcastss, .rm, &.{ .ymm, .xmm }, &.{ 0x66, 0x0f, 0x38, 0x18 }, 0, .vex_256_w0, .avx2 },
14751523 .{ .vbroadcastsd, .rm, &.{ .ymm, .xmm }, &.{ 0x66, 0x0f, 0x38, 0x19 }, 0, .vex_256_w0, .avx2 },
14761524
1525 .{ .vpacksswb, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x63 }, 0, .vex_256_wig, .avx2 },
1526 .{ .vpackssdw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x6b }, 0, .vex_256_wig, .avx2 },
1527
1528 .{ .vpackusdw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x2b }, 0, .vex_256_wig, .avx2 },
1529
1530 .{ .vpackuswb, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x67 }, 0, .vex_256_wig, .avx2 },
1531
14771532 .{ .vpaddb, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0xfc }, 0, .vex_256_wig, .avx2 },
14781533 .{ .vpaddw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0xfd }, 0, .vex_256_wig, .avx2 },
14791534 .{ .vpaddd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0xfe }, 0, .vex_256_wig, .avx2 },
src/codegen.zig+22-5
......@@ -747,15 +747,23 @@ pub fn generateSymbol(
747747 .Vector => switch (typed_value.val.tag()) {
748748 .bytes => {
749749 const bytes = typed_value.val.castTag(.bytes).?.data;
750 const len = @intCast(usize, typed_value.ty.arrayLen());
751 try code.ensureUnusedCapacity(len);
750 const len = math.cast(usize, typed_value.ty.arrayLen()) orelse return error.Overflow;
751 const padding = math.cast(usize, typed_value.ty.abiSize(target) - len) orelse
752 return error.Overflow;
753 try code.ensureUnusedCapacity(len + padding);
752754 code.appendSliceAssumeCapacity(bytes[0..len]);
755 if (padding > 0) try code.writer().writeByteNTimes(0, padding);
753756 return Result.ok;
754757 },
755758 .aggregate => {
756759 const elem_vals = typed_value.val.castTag(.aggregate).?.data;
757760 const elem_ty = typed_value.ty.elemType();
758 const len = @intCast(usize, typed_value.ty.arrayLen());
761 const len = math.cast(usize, typed_value.ty.arrayLen()) orelse return error.Overflow;
762 const padding = math.cast(usize, typed_value.ty.abiSize(target) -
763 (math.divCeil(u64, elem_ty.bitSize(target) * len, 8) catch |err| switch (err) {
764 error.DivisionByZero => unreachable,
765 else => |e| return e,
766 })) orelse return error.Overflow;
759767 for (elem_vals[0..len]) |elem_val| {
760768 switch (try generateSymbol(bin_file, src_loc, .{
761769 .ty = elem_ty,
......@@ -765,13 +773,18 @@ pub fn generateSymbol(
765773 .fail => |em| return Result{ .fail = em },
766774 }
767775 }
776 if (padding > 0) try code.writer().writeByteNTimes(0, padding);
768777 return Result.ok;
769778 },
770779 .repeated => {
771780 const array = typed_value.val.castTag(.repeated).?.data;
772781 const elem_ty = typed_value.ty.childType();
773782 const len = typed_value.ty.arrayLen();
774
783 const padding = math.cast(usize, typed_value.ty.abiSize(target) -
784 (math.divCeil(u64, elem_ty.bitSize(target) * len, 8) catch |err| switch (err) {
785 error.DivisionByZero => unreachable,
786 else => |e| return e,
787 })) orelse return error.Overflow;
775788 var index: u64 = 0;
776789 while (index < len) : (index += 1) {
777790 switch (try generateSymbol(bin_file, src_loc, .{
......@@ -782,13 +795,17 @@ pub fn generateSymbol(
782795 .fail => |em| return Result{ .fail = em },
783796 }
784797 }
798 if (padding > 0) try code.writer().writeByteNTimes(0, padding);
785799 return Result.ok;
786800 },
787801 .str_lit => {
788802 const str_lit = typed_value.val.castTag(.str_lit).?.data;
789803 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
790 try code.ensureUnusedCapacity(str_lit.len);
804 const padding = math.cast(usize, typed_value.ty.abiSize(target) - str_lit.len) orelse
805 return error.Overflow;
806 try code.ensureUnusedCapacity(str_lit.len + padding);
791807 code.appendSliceAssumeCapacity(bytes);
808 if (padding > 0) try code.writer().writeByteNTimes(0, padding);
792809 return Result.ok;
793810 },
794811 else => unreachable,
test/behavior/bitcast.zig-2
......@@ -35,7 +35,6 @@ test "@bitCast iX -> uX (8, 16, 128)" {
3535
3636test "@bitCast iX -> uX exotic integers" {
3737 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3938 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -82,7 +81,6 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe
8281
8382test "bitcast uX to bytes" {
8483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
85 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8684 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8785 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8886 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/bugs/13128.zig-1
......@@ -14,7 +14,6 @@ fn foo(val: U) !void {
1414test "runtime union init, most-aligned field != largest" {
1515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1918 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
test/behavior/eval.zig-2
......@@ -816,7 +816,6 @@ test "array concatenation peer resolves element types - pointer" {
816816
817817test "array concatenation sets the sentinel - value" {
818818 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
819 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
820819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
821820 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
822821 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -855,7 +854,6 @@ test "array concatenation sets the sentinel - pointer" {
855854
856855test "array multiplication sets the sentinel - value" {
857856 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
858 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
859857 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
860858 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
861859 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/floatop.zig-1
......@@ -1145,7 +1145,6 @@ test "nan negation f64" {
11451145
11461146test "nan negation f128" {
11471147 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1148 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11491148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11501149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11511150 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/math.zig-2
......@@ -783,7 +783,6 @@ test "basic @mulWithOverflow" {
783783test "extensive @mulWithOverflow" {
784784 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
785785 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
787786 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
788787
789788 {
......@@ -1055,7 +1054,6 @@ test "@subWithOverflow" {
10551054test "@shlWithOverflow" {
10561055 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10571056 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1058 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10591057 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10601058
10611059 {
test/behavior/maximum_minimum.zig+4-2
......@@ -24,7 +24,8 @@ test "@max" {
2424
2525test "@max on vectors" {
2626 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_x86_64 and
28 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
2829 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2930 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3031 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -72,7 +73,8 @@ test "@min" {
7273
7374test "@min for vectors" {
7475 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_x86_64 and
77 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
7678 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7779 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7880 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/saturating_arithmetic.zig-2
......@@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;
55const expect = std.testing.expect;
66
77test "saturating add" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -79,7 +78,6 @@ test "saturating add 128bit" {
7978}
8079
8180test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
8381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/truncate.zig-1
......@@ -61,7 +61,6 @@ test "truncate on comptime integer" {
6161
6262test "truncate on vectors" {
6363 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
6564 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6766 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/vector.zig-1
......@@ -1142,7 +1142,6 @@ test "loading the second vector from a slice of vectors" {
11421142
11431143test "array of vectors is copied" {
11441144 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1145 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11461145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11471146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11481147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/widening.zig-1
......@@ -5,7 +5,6 @@ const builtin = @import("builtin");
55const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
66
77test "integer widening" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO