authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-09-10 13:49:49-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-09-10 21:01:13-04:00
log1a0a9d7d59b78e5d97142d867bece78fc477e9a7
tree7a31920fb8683cf5d6d33c0d4932c9878f60093f
parentbfda12efcf2f6b4bc6803f520108b7ce05636965

x86_64: fix strictness edge cases in `+|`

Closes #25145

2 files changed, 172 insertions(+), 37 deletions(-)

src/arch/x86_64/CodeGen.zig+28-29
......@@ -7263,10 +7263,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
72637263 .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
72647264 .{ ._, .vp_d, .add, .dst0x, .src0x, .src1x, ._ },
72657265 .{ ._, .vp_d, .sra, .tmp2x, .src0x, .ui(31), ._ },
7266 .{ ._, .vp_d, .cmpgt, .tmp3x, .dst0x, .src0x, ._ },
7266 .{ ._, .vp_d, .cmpgt, .tmp3x, .src0x, .dst0x, ._ },
72677267 .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .lea(.tmp0x), ._ },
72687268 .{ ._, .vp_, .xor, .tmp3x, .tmp3x, .src1x, ._ },
7269 .{ ._, .v_ps, .blendv, .dst0x, .tmp2x, .dst0x, .tmp3x },
7269 .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .tmp2x, .tmp3x },
72707270 } },
72717271 }, .{
72727272 .required_features = .{ .sse4_1, null, null, null },
......@@ -7332,10 +7332,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
73327332 .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
73337333 .{ ._, .vp_d, .add, .dst0y, .src0y, .src1y, ._ },
73347334 .{ ._, .vp_d, .sra, .tmp2y, .src0y, .ui(31), ._ },
7335 .{ ._, .vp_d, .cmpgt, .tmp3y, .dst0y, .src0y, ._ },
7335 .{ ._, .vp_d, .cmpgt, .tmp3y, .src0y, .dst0y, ._ },
73367336 .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .lea(.tmp0y), ._ },
73377337 .{ ._, .vp_, .xor, .tmp3y, .tmp3y, .src1y, ._ },
7338 .{ ._, .v_ps, .blendv, .dst0y, .tmp2y, .dst0y, .tmp3y },
7338 .{ ._, .v_ps, .blendv, .dst0y, .dst0y, .tmp2y, .tmp3y },
73397339 } },
73407340 }, .{
73417341 .required_features = .{ .avx, null, null, null },
......@@ -7615,10 +7615,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
76157615 .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ },
76167616 .{ ._, .vp_q, .add, .dst0x, .src0x, .src1x, ._ },
76177617 .{ ._, .vp_q, .cmpgt, .tmp2x, .tmp2x, .src0x, ._ },
7618 .{ ._, .vp_q, .cmpgt, .tmp3x, .dst0x, .src0x, ._ },
7618 .{ ._, .vp_q, .cmpgt, .tmp3x, .src0x, .dst0x, ._ },
76197619 .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .lea(.tmp0x), ._ },
76207620 .{ ._, .vp_, .xor, .tmp3x, .tmp3x, .src1x, ._ },
7621 .{ ._, .v_pd, .blendv, .dst0x, .tmp2x, .dst0x, .tmp3x },
7621 .{ ._, .v_pd, .blendv, .dst0x, .dst0x, .tmp2x, .tmp3x },
76227622 } },
76237623 }, .{
76247624 .required_features = .{ .sse4_2, null, null, null },
......@@ -7685,10 +7685,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
76857685 .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .tmp2y, ._ },
76867686 .{ ._, .vp_q, .add, .dst0y, .src0y, .src1y, ._ },
76877687 .{ ._, .vp_q, .cmpgt, .tmp2y, .tmp2y, .src0y, ._ },
7688 .{ ._, .vp_q, .cmpgt, .tmp3y, .dst0y, .src0y, ._ },
7688 .{ ._, .vp_q, .cmpgt, .tmp3y, .src0y, .dst0y, ._ },
76897689 .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .lea(.tmp0y), ._ },
76907690 .{ ._, .vp_, .xor, .tmp3y, .tmp3y, .src1y, ._ },
7691 .{ ._, .v_pd, .blendv, .dst0y, .tmp2y, .dst0y, .tmp3y },
7691 .{ ._, .v_pd, .blendv, .dst0y, .dst0y, .tmp2y, .tmp3y },
76927692 } },
76937693 }, .{
76947694 .required_features = .{ .avx2, null, null, null },
......@@ -7724,8 +7724,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
77247724 .{ ._, .vp_b, .blendv, .dst0x, .dst0x, .tmp2x, .tmp3x },
77257725 .{ ._, .vp_q, .cmpeq, .tmp3x, .tmp3x, .tmp3x, ._ },
77267726 .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp3x, ._ },
7727 .{ ._, .vp_q, .cmpgt, .tmp3x, .dst0x, .tmp2x, ._ },
7728 .{ ._, .vp_b, .blendv, .dst0x, .dst0x, .tmp2x, .tmp3x },
7727 .{ ._, .vp_q, .cmpgt, .tmp3x, .tmp2x, .dst0x, ._ },
7728 .{ ._, .vp_b, .blendv, .dst0x, .tmp2x, .dst0x, .tmp3x },
77297729 } },
77307730 }, .{
77317731 .required_features = .{ .avx, null, null, null },
......@@ -7761,8 +7761,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
77617761 .{ ._, .vp_b, .blendv, .dst0x, .dst0x, .tmp2x, .tmp3x },
77627762 .{ ._, .vp_q, .cmpeq, .tmp3x, .tmp3x, .tmp3x, ._ },
77637763 .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp3x, ._ },
7764 .{ ._, .vp_q, .cmpgt, .tmp3x, .dst0x, .tmp2x, ._ },
7765 .{ ._, .vp_b, .blendv, .dst0x, .dst0x, .tmp2x, .tmp3x },
7764 .{ ._, .vp_q, .cmpgt, .tmp3x, .tmp2x, .dst0x, ._ },
7765 .{ ._, .vp_b, .blendv, .dst0x, .tmp2x, .dst0x, .tmp3x },
77667766 } },
77677767 }, .{
77687768 .required_features = .{ .sse4_2, null, null, null },
......@@ -7837,8 +7837,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
78377837 .{ ._, .vp_b, .blendv, .dst0y, .dst0y, .tmp2y, .tmp3y },
78387838 .{ ._, .vp_q, .cmpeq, .tmp3y, .tmp3y, .tmp3y, ._ },
78397839 .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .tmp3y, ._ },
7840 .{ ._, .vp_q, .cmpgt, .tmp3y, .dst0y, .tmp2y, ._ },
7841 .{ ._, .vp_b, .blendv, .dst0y, .dst0y, .tmp2y, .tmp3y },
7840 .{ ._, .vp_q, .cmpgt, .tmp3y, .tmp2y, .dst0y, ._ },
7841 .{ ._, .vp_b, .blendv, .dst0y, .tmp2y, .dst0y, .tmp3y },
78427842 } },
78437843 }, .{
78447844 .required_features = .{ .avx2, null, null, null },
......@@ -10714,10 +10714,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1071410714 .{ ._, .v_dqa, .mov, .tmp4y, .memia(.src1y, .tmp0, .add_unaligned_size), ._, ._ },
1071510715 .{ ._, .vp_d, .add, .tmp5y, .tmp3y, .tmp4y, ._ },
1071610716 .{ ._, .vp_d, .sra, .tmp6y, .tmp3y, .ui(31), ._ },
10717 .{ ._, .vp_d, .cmpgt, .tmp3y, .tmp5y, .tmp3y, ._ },
10717 .{ ._, .vp_d, .cmpgt, .tmp3y, .tmp3y, .tmp5y, ._ },
1071810718 .{ ._, .vp_, .xor, .tmp6y, .tmp6y, .tmp2y, ._ },
1071910719 .{ ._, .vp_, .xor, .tmp3y, .tmp3y, .tmp4y, ._ },
10720 .{ ._, .v_ps, .blendv, .tmp3y, .tmp6y, .tmp5y, .tmp3y },
10720 .{ ._, .v_ps, .blendv, .tmp3y, .tmp5y, .tmp6y, .tmp3y },
1072110721 .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_unaligned_size), .tmp3y, ._, ._ },
1072210722 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
1072310723 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
......@@ -10755,10 +10755,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1075510755 .{ ._, .v_dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_unaligned_size), ._, ._ },
1075610756 .{ ._, .vp_d, .add, .tmp5x, .tmp3x, .tmp4x, ._ },
1075710757 .{ ._, .vp_d, .sra, .tmp6x, .tmp3x, .ui(31), ._ },
10758 .{ ._, .vp_d, .cmpgt, .tmp3x, .tmp5x, .tmp3x, ._ },
10758 .{ ._, .vp_d, .cmpgt, .tmp3x, .tmp3x, .tmp5x, ._ },
1075910759 .{ ._, .vp_, .xor, .tmp6x, .tmp6x, .tmp2x, ._ },
1076010760 .{ ._, .vp_, .xor, .tmp3x, .tmp3x, .tmp4x, ._ },
10761 .{ ._, .v_ps, .blendv, .tmp3x, .tmp6x, .tmp5x, .tmp3x },
10761 .{ ._, .v_ps, .blendv, .tmp3x, .tmp5x, .tmp6x, .tmp3x },
1076210762 .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_unaligned_size), .tmp3x, ._, ._ },
1076310763 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
1076410764 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
......@@ -11543,10 +11543,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1154311543 .{ ._, .vp_, .xor, .tmp5y, .tmp5y, .tmp5y, ._ },
1154411544 .{ ._, .vp_q, .add, .tmp6y, .tmp3y, .tmp4y, ._ },
1154511545 .{ ._, .vp_q, .cmpgt, .tmp5y, .tmp5y, .tmp3y, ._ },
11546 .{ ._, .vp_q, .cmpgt, .tmp3y, .tmp6y, .tmp3y, ._ },
11546 .{ ._, .vp_q, .cmpgt, .tmp3y, .tmp3y, .tmp6y, ._ },
1154711547 .{ ._, .vp_, .xor, .tmp5y, .tmp5y, .tmp2y, ._ },
1154811548 .{ ._, .vp_, .xor, .tmp3y, .tmp3y, .tmp4y, ._ },
11549 .{ ._, .v_pd, .blendv, .tmp5y, .tmp5y, .tmp6y, .tmp3y },
11549 .{ ._, .v_pd, .blendv, .tmp5y, .tmp6y, .tmp5y, .tmp3y },
1155011550 .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_unaligned_size), .tmp5y, ._, ._ },
1155111551 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
1155211552 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
......@@ -11585,10 +11585,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1158511585 .{ ._, .vp_, .xor, .tmp5x, .tmp5x, .tmp5x, ._ },
1158611586 .{ ._, .vp_q, .add, .tmp6x, .tmp3x, .tmp4x, ._ },
1158711587 .{ ._, .vp_q, .cmpgt, .tmp5x, .tmp5x, .tmp3x, ._ },
11588 .{ ._, .vp_q, .cmpgt, .tmp3x, .tmp6x, .tmp3x, ._ },
11588 .{ ._, .vp_q, .cmpgt, .tmp3x, .tmp3x, .tmp6x, ._ },
1158911589 .{ ._, .vp_, .xor, .tmp5x, .tmp5x, .tmp2x, ._ },
1159011590 .{ ._, .vp_, .xor, .tmp3x, .tmp3x, .tmp4x, ._ },
11591 .{ ._, .v_pd, .blendv, .tmp5x, .tmp5x, .tmp6x, .tmp3x },
11591 .{ ._, .v_pd, .blendv, .tmp5x, .tmp6x, .tmp5x, .tmp3x },
1159211592 .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_unaligned_size), .tmp5x, ._, ._ },
1159311593 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
1159411594 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
......@@ -11607,11 +11607,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1160711607 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
1160811608 .{ .type = .i64, .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .none } } },
1160911609 .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
11610 .{ .type = .vector_2_i64, .kind = .{ .reg = .xmm0 } },
1161011611 .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
1161111612 .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
1161211613 .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
11613 .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
11614 .{ .type = .vector_2_i64, .kind = .{ .reg = .xmm0 } },
11614 .unused,
1161511615 .unused,
1161611616 .unused,
1161711617 .unused,
......@@ -11628,12 +11628,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1162811628 .{ ._, ._dqa, .mov, .tmp6x, .tmp3x, ._, ._ },
1162911629 .{ ._, .p_q, .add, .tmp6x, .tmp4x, ._, ._ },
1163011630 .{ ._, .p_q, .cmpgt, .tmp5x, .tmp3x, ._, ._ },
11631 .{ ._, ._dqa, .mov, .tmp7x, .tmp6x, ._, ._ },
11632 .{ ._, .p_q, .cmpgt, .tmp7x, .tmp3x, ._, ._ },
11631 .{ ._, .p_q, .cmpgt, .tmp3x, .tmp6x, ._, ._ },
1163311632 .{ ._, .p_, .xor, .tmp5x, .tmp2x, ._, ._ },
11634 .{ ._, .p_, .xor, .tmp7x, .tmp4x, ._, ._ },
11635 .{ ._, ._pd, .blendv, .tmp5x, .tmp6x, .tmp7x, ._ },
11636 .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_unaligned_size), .tmp5x, ._, ._ },
11633 .{ ._, .p_, .xor, .tmp3x, .tmp4x, ._, ._ },
11634 .{ ._, ._pd, .blendv, .tmp6x, .tmp5x, .tmp3x, ._ },
11635 .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_unaligned_size), .tmp6x, ._, ._ },
1163711636 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
1163811637 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
1163911638 } },
test/behavior/vector.zig+144-8
......@@ -970,6 +970,73 @@ test "saturating add" {
970970 const expected = i8x3{ 127, 127, 127 };
971971 try expect(mem.eql(i8, &@as([3]i8, expected), &@as([3]i8, result)));
972972 }
973 try testElemType(i4);
974 try testElemType(u4);
975 try testElemType(i8);
976 try testElemType(u8);
977 try testElemType(i12);
978 try testElemType(u12);
979 try testElemType(i16);
980 try testElemType(u16);
981 try testElemType(i24);
982 try testElemType(u24);
983 try testElemType(i32);
984 try testElemType(u32);
985 try testElemType(i48);
986 try testElemType(u48);
987 try testElemType(i64);
988 try testElemType(u64);
989 }
990 fn testElemType(comptime Elem: type) !void {
991 const min = std.math.minInt(Elem);
992 const max = std.math.maxInt(Elem);
993
994 var v: @Vector(4, Elem) = .{ 0, 1, 0, 1 };
995 v +|= .{ 0, 0, 1, 1 };
996 try expect(v[0] == 0);
997 try expect(v[1] == 1);
998 try expect(v[2] == 1);
999 try expect(v[3] == 2);
1000
1001 v = .{ 0, max, 1, max };
1002 v +|= .{ max, 0, max, 1 };
1003 try expect(v[0] == max);
1004 try expect(v[1] == max);
1005 try expect(v[2] == max);
1006 try expect(v[3] == max);
1007
1008 v = .{ 1, max - 1, max / 2, max };
1009 v +|= .{ max - 1, 1, max / 2, max };
1010 try expect(v[0] == max);
1011 try expect(v[1] == max);
1012 try expect(v[2] == max - 1);
1013 try expect(v[3] == max);
1014
1015 switch (@typeInfo(Elem).int.signedness) {
1016 .signed => {
1017 v = .{ -1, -1, 0, -1 };
1018 v +|= .{ 1, 0, -1, -1 };
1019 try expect(v[0] == 0);
1020 try expect(v[1] == -1);
1021 try expect(v[2] == -1);
1022 try expect(v[3] == -2);
1023
1024 v = .{ 0, min, -1, min };
1025 v +|= .{ min, 0, min, -1 };
1026 try expect(v[0] == min);
1027 try expect(v[1] == min);
1028 try expect(v[2] == min);
1029 try expect(v[3] == min);
1030
1031 v = .{ -1, min + 1, min / 2, min };
1032 v +|= .{ min + 1, -1, min / 2, min };
1033 try expect(v[0] == min);
1034 try expect(v[1] == min);
1035 try expect(v[2] == min);
1036 try expect(v[3] == min);
1037 },
1038 .unsigned => {},
1039 }
9731040 }
9741041 };
9751042 try S.doTheTest();
......@@ -986,14 +1053,83 @@ test "saturating subtraction" {
9861053
9871054 const S = struct {
9881055 fn doTheTest() !void {
989 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
990 const u8x3 = @Vector(3, u8);
991 var lhs = u8x3{ 0, 0, 0 };
992 var rhs = u8x3{ 255, 255, 255 };
993 _ = .{ &lhs, &rhs };
994 const result = lhs -| rhs;
995 const expected = u8x3{ 0, 0, 0 };
996 try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result)));
1056 {
1057 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
1058 const u8x3 = @Vector(3, u8);
1059 var lhs = u8x3{ 0, 0, 0 };
1060 var rhs = u8x3{ 255, 255, 255 };
1061 _ = .{ &lhs, &rhs };
1062 const result = lhs -| rhs;
1063 const expected = u8x3{ 0, 0, 0 };
1064 try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result)));
1065 }
1066 try testElemType(i4);
1067 try testElemType(u4);
1068 try testElemType(i8);
1069 try testElemType(u8);
1070 try testElemType(i12);
1071 try testElemType(u12);
1072 try testElemType(i16);
1073 try testElemType(u16);
1074 try testElemType(i24);
1075 try testElemType(u24);
1076 try testElemType(i32);
1077 try testElemType(u32);
1078 try testElemType(i48);
1079 try testElemType(u48);
1080 try testElemType(i64);
1081 try testElemType(u64);
1082 }
1083 fn testElemType(comptime Elem: type) !void {
1084 const min = std.math.minInt(Elem);
1085 const max = std.math.maxInt(Elem);
1086
1087 var v: @Vector(4, Elem) = .{ 0, 1, 0, 1 };
1088 v -|= .{ 0, 0, 1, 1 };
1089 try expect(v[0] == 0);
1090 try expect(v[1] == 1);
1091 try expect(v[2] == @max(min, -1));
1092 try expect(v[3] == 0);
1093
1094 v = .{ 0, max, 1, max };
1095 v -|= .{ max, 0, max, 1 };
1096 try expect(v[0] == @min(min + 1, 0));
1097 try expect(v[1] == max);
1098 try expect(v[2] == @min(min + 2, 0));
1099 try expect(v[3] == max - 1);
1100
1101 v = .{ 1, max - 1, max / 2, max };
1102 v -|= .{ max - 1, 1, max / 2, max };
1103 try expect(v[0] == @min(min + 3, 0));
1104 try expect(v[1] == max - 2);
1105 try expect(v[2] == 0);
1106 try expect(v[3] == 0);
1107
1108 switch (@typeInfo(Elem).int.signedness) {
1109 .signed => {
1110 v = .{ -1, -1, 0, -1 };
1111 v -|= .{ -1, 0, 1, 1 };
1112 try expect(v[0] == 0);
1113 try expect(v[1] == -1);
1114 try expect(v[2] == -1);
1115 try expect(v[3] == -2);
1116
1117 v = .{ 0, min, -1, min };
1118 v -|= .{ max, 0, max, 1 };
1119 try expect(v[0] == min + 1);
1120 try expect(v[1] == min);
1121 try expect(v[2] == min);
1122 try expect(v[3] == min);
1123
1124 v = .{ -1, min + 1, min / 2, min };
1125 v -|= .{ max, 1, max / 2, max };
1126 try expect(v[0] == min);
1127 try expect(v[1] == min);
1128 try expect(v[2] == min + 1);
1129 try expect(v[3] == min);
1130 },
1131 .unsigned => {},
1132 }
9971133 }
9981134 };
9991135 try S.doTheTest();