authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-23 15:02:40+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-26 18:05:27+02:00
log72fa8d4880613d88f9f29dd78012b7253729bac7
treed9a84bce86501001b27cb5d31f0a596a3362f7b8
parent5b9d0a446af4e74c9f915a34b39de83d9b2335f9

Sema: fix overflow arithmetic with runtime vectors

It should return a a vector of bools for compatibility with scalar operands and stage1 until #10248 can be implemented. Closes #13201

2 files changed, 34 insertions(+), 25 deletions(-)

src/Sema.zig+1-9
...@@ -13468,7 +13468,6 @@ fn zirOverflowArithmetic(...@@ -13468,7 +13468,6 @@ fn zirOverflowArithmetic(
13468 const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);13468 const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);
1346913469
13470 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);13470 const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
13471 const ov_ty = tuple_ty.tupleFields().types[1];
13472 // TODO: Remove and use `ov_ty` instead.13471 // TODO: Remove and use `ov_ty` instead.
13473 // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`.13472 // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`.
13474 const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.bool) else Type.bool;13473 const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.bool) else Type.bool;
...@@ -13619,14 +13618,7 @@ fn zirOverflowArithmetic(...@@ -13619,14 +13618,7 @@ fn zirOverflowArithmetic(
13619 try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store);13618 try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store);
1362013619
13621 const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty);13620 const overflow_bit = try sema.tupleFieldValByIndex(block, src, tuple, 1, tuple_ty);
13622 const zero_ov_val = if (dest_ty.zigTypeTag() == .Vector) try Value.Tag.repeated.create(sema.arena, Value.zero) else Value.zero;13621 return block.addBitCast(overflowed_ty, overflow_bit);
13623 const zero_ov = try sema.addConstant(ov_ty, zero_ov_val);
13624
13625 const overflowed_inst = if (dest_ty.zigTypeTag() == .Vector)
13626 block.addCmpVector(overflow_bit, .zero, .neq, try sema.addType(ov_ty))
13627 else
13628 block.addBinOp(.cmp_neq, overflow_bit, zero_ov);
13629 return overflowed_inst;
13630 };13622 };
1363113623
13632 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);13624 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);
test/behavior/vector.zig+33-16
...@@ -977,27 +977,35 @@ test "@addWithOverflow" {...@@ -977,27 +977,35 @@ test "@addWithOverflow" {
977 fn doTheTest() !void {977 fn doTheTest() !void {
978 {978 {
979 var result: @Vector(4, u8) = undefined;979 var result: @Vector(4, u8) = undefined;
980 var overflow = @addWithOverflow(@Vector(4, u8), @Vector(4, u8){ 250, 250, 250, 250 }, @Vector(4, u8){ 0, 5, 6, 10 }, &result);980 var lhs = @Vector(4, u8){ 250, 250, 250, 250 };
981 var rhs = @Vector(4, u8){ 0, 5, 6, 10 };
982 var overflow = @addWithOverflow(@Vector(4, u8), lhs, rhs, &result);
981 var expected: @Vector(4, bool) = .{ false, false, true, true };983 var expected: @Vector(4, bool) = .{ false, false, true, true };
982 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));984 try expectEqual(expected, overflow);
983 }985 }
984 {986 {
985 var result: @Vector(4, i8) = undefined;987 var result: @Vector(4, i8) = undefined;
986 var overflow = @addWithOverflow(@Vector(4, i8), @Vector(4, i8){ -125, -125, 125, 125 }, @Vector(4, i8){ -3, -4, 2, 3 }, &result);988 var lhs = @Vector(4, i8){ -125, -125, 125, 125 };
989 var rhs = @Vector(4, i8){ -3, -4, 2, 3 };
990 var overflow = @addWithOverflow(@Vector(4, i8), lhs, rhs, &result);
987 var expected: @Vector(4, bool) = .{ false, true, false, true };991 var expected: @Vector(4, bool) = .{ false, true, false, true };
988 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));992 try expectEqual(expected, overflow);
989 }993 }
990 {994 {
991 var result: @Vector(4, u1) = undefined;995 var result: @Vector(4, u1) = undefined;
992 var overflow = @addWithOverflow(@Vector(4, u1), @Vector(4, u1){ 0, 0, 1, 1 }, @Vector(4, u1){ 0, 1, 0, 1 }, &result);996 var lhs = @Vector(4, u1){ 0, 0, 1, 1 };
997 var rhs = @Vector(4, u1){ 0, 1, 0, 1 };
998 var overflow = @addWithOverflow(@Vector(4, u1), lhs, rhs, &result);
993 var expected: @Vector(4, bool) = .{ false, false, false, true };999 var expected: @Vector(4, bool) = .{ false, false, false, true };
994 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));1000 try expectEqual(expected, overflow);
995 }1001 }
996 {1002 {
997 var result: @Vector(4, u0) = undefined;1003 var result: @Vector(4, u0) = undefined;
998 var overflow = @addWithOverflow(@Vector(4, u0), @Vector(4, u0){ 0, 0, 0, 0 }, @Vector(4, u0){ 0, 0, 0, 0 }, &result);1004 var lhs = @Vector(4, u0){ 0, 0, 0, 0 };
1005 var rhs = @Vector(4, u0){ 0, 0, 0, 0 };
1006 var overflow = @addWithOverflow(@Vector(4, u0), lhs, rhs, &result);
999 var expected: @Vector(4, bool) = .{ false, false, false, false };1007 var expected: @Vector(4, bool) = .{ false, false, false, false };
1000 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));1008 try expectEqual(expected, overflow);
1001 }1009 }
1002 }1010 }
1003 };1011 };
...@@ -1019,15 +1027,19 @@ test "@subWithOverflow" {...@@ -1019,15 +1027,19 @@ test "@subWithOverflow" {
1019 fn doTheTest() !void {1027 fn doTheTest() !void {
1020 {1028 {
1021 var result: @Vector(2, u8) = undefined;1029 var result: @Vector(2, u8) = undefined;
1022 var overflow = @subWithOverflow(@Vector(2, u8), @Vector(2, u8){ 5, 5 }, @Vector(2, u8){ 5, 6 }, &result);1030 var lhs = @Vector(2, u8){ 5, 5 };
1031 var rhs = @Vector(2, u8){ 5, 6 };
1032 var overflow = @subWithOverflow(@Vector(2, u8), lhs, rhs, &result);
1023 var expected: @Vector(2, bool) = .{ false, true };1033 var expected: @Vector(2, bool) = .{ false, true };
1024 try expect(mem.eql(bool, &@as([2]bool, overflow), &@as([2]bool, expected)));1034 try expectEqual(expected, overflow);
1025 }1035 }
1026 {1036 {
1027 var result: @Vector(4, i8) = undefined;1037 var result: @Vector(4, i8) = undefined;
1028 var overflow = @subWithOverflow(@Vector(4, i8), @Vector(4, i8){ -120, -120, 120, 120 }, @Vector(4, i8){ 8, 9, -7, -8 }, &result);1038 var lhs = @Vector(4, i8){ -120, -120, 120, 120 };
1039 var rhs = @Vector(4, i8){ 8, 9, -7, -8 };
1040 var overflow = @subWithOverflow(@Vector(4, i8), lhs, rhs, &result);
1029 var expected: @Vector(4, bool) = .{ false, true, false, true };1041 var expected: @Vector(4, bool) = .{ false, true, false, true };
1030 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));1042 try expectEqual(expected, overflow);
1031 }1043 }
1032 }1044 }
1033 };1045 };
...@@ -1048,9 +1060,11 @@ test "@mulWithOverflow" {...@@ -1048,9 +1060,11 @@ test "@mulWithOverflow" {
1048 const S = struct {1060 const S = struct {
1049 fn doTheTest() !void {1061 fn doTheTest() !void {
1050 var result: @Vector(4, u8) = undefined;1062 var result: @Vector(4, u8) = undefined;
1051 var overflow = @mulWithOverflow(@Vector(4, u8), @Vector(4, u8){ 10, 10, 10, 10 }, @Vector(4, u8){ 25, 26, 0, 30 }, &result);1063 var lhs = @Vector(4, u8){ 10, 10, 10, 10 };
1064 var rhs = @Vector(4, u8){ 25, 26, 0, 30 };
1065 var overflow = @mulWithOverflow(@Vector(4, u8), lhs, rhs, &result);
1052 var expected: @Vector(4, bool) = .{ false, true, false, true };1066 var expected: @Vector(4, bool) = .{ false, true, false, true };
1053 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));1067 try expectEqual(expected, overflow);
1054 }1068 }
1055 };1069 };
1056 try S.doTheTest();1070 try S.doTheTest();
...@@ -1062,6 +1076,7 @@ test "@shlWithOverflow" {...@@ -1062,6 +1076,7 @@ test "@shlWithOverflow" {
1062 // stage1 doesn't support vector args1076 // stage1 doesn't support vector args
1063 return error.SkipZigTest;1077 return error.SkipZigTest;
1064 }1078 }
1079 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1065 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1080 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1066 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1081 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1067 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1082 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -1070,9 +1085,11 @@ test "@shlWithOverflow" {...@@ -1070,9 +1085,11 @@ test "@shlWithOverflow" {
1070 const S = struct {1085 const S = struct {
1071 fn doTheTest() !void {1086 fn doTheTest() !void {
1072 var result: @Vector(4, u8) = undefined;1087 var result: @Vector(4, u8) = undefined;
1073 var overflow = @shlWithOverflow(@Vector(4, u8), @Vector(4, u8){ 0, 1, 8, 255 }, @Vector(4, u3){ 7, 7, 7, 7 }, &result);1088 var lhs = @Vector(4, u8){ 0, 1, 8, 255 };
1089 var rhs = @Vector(4, u3){ 7, 7, 7, 7 };
1090 var overflow = @shlWithOverflow(@Vector(4, u8), lhs, rhs, &result);
1074 var expected: @Vector(4, bool) = .{ false, false, true, true };1091 var expected: @Vector(4, bool) = .{ false, false, true, true };
1075 try expect(mem.eql(bool, &@as([4]bool, overflow), &@as([4]bool, expected)));1092 try expectEqual(expected, overflow);
1076 }1093 }
1077 };1094 };
1078 try S.doTheTest();1095 try S.doTheTest();