authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-28 14:17:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-28 14:17:05-07:00
logb6ccde47adeb0dbd7b39150c36498100e0d98075
treec9fff157c08701cd6d6849a1c95fddd5385e1c86
parent691c7cb3cd3cc6cb4f6324d0ad4a5c3e2e8ff94c

Sema: allow mixing array and vector operands

* Added peer type resolution for arrays and vectors: the vector type is selected. * Fixed passing the lhs type or rhs type instead of the peer resolved type when calling Value methods during analyzeArithmetic handling of comptime expressions. * `checkVectorizableBinaryOperands` now allows mixing vectors and arrays, as long as one of the operands is a vector. This matches stage1's handling of `^=` but apparently stage1 is inconsistent and does not handle e.g. `*=`. stage2 now will always allow mixing vector and array operands for all operations.

2 files changed, 61 insertions(+), 14 deletions(-)

src/Sema.zig+37-14
...@@ -9617,7 +9617,7 @@ fn analyzeArithmetic(...@@ -9617,7 +9617,7 @@ fn analyzeArithmetic(
9617 if (lhs_val.isUndef()) {9617 if (lhs_val.isUndef()) {
9618 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {9618 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
9619 if (maybe_rhs_val) |rhs_val| {9619 if (maybe_rhs_val) |rhs_val| {
9620 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty, target)) {9620 if (rhs_val.compare(.neq, Value.negative_one, resolved_type, target)) {
9621 return sema.addConstUndef(resolved_type);9621 return sema.addConstUndef(resolved_type);
9622 }9622 }
9623 }9623 }
...@@ -9692,7 +9692,7 @@ fn analyzeArithmetic(...@@ -9692,7 +9692,7 @@ fn analyzeArithmetic(
9692 if (lhs_val.isUndef()) {9692 if (lhs_val.isUndef()) {
9693 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {9693 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
9694 if (maybe_rhs_val) |rhs_val| {9694 if (maybe_rhs_val) |rhs_val| {
9695 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty, target)) {9695 if (rhs_val.compare(.neq, Value.negative_one, resolved_type, target)) {
9696 return sema.addConstUndef(resolved_type);9696 return sema.addConstUndef(resolved_type);
9697 }9697 }
9698 }9698 }
...@@ -9755,7 +9755,7 @@ fn analyzeArithmetic(...@@ -9755,7 +9755,7 @@ fn analyzeArithmetic(
9755 if (lhs_val.isUndef()) {9755 if (lhs_val.isUndef()) {
9756 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {9756 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
9757 if (maybe_rhs_val) |rhs_val| {9757 if (maybe_rhs_val) |rhs_val| {
9758 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty, target)) {9758 if (rhs_val.compare(.neq, Value.negative_one, resolved_type, target)) {
9759 return sema.addConstUndef(resolved_type);9759 return sema.addConstUndef(resolved_type);
9760 }9760 }
9761 }9761 }
...@@ -9845,7 +9845,7 @@ fn analyzeArithmetic(...@@ -9845,7 +9845,7 @@ fn analyzeArithmetic(
9845 if (lhs_val.compareWithZero(.eq)) {9845 if (lhs_val.compareWithZero(.eq)) {
9846 return sema.addConstant(resolved_type, Value.zero);9846 return sema.addConstant(resolved_type, Value.zero);
9847 }9847 }
9848 if (lhs_val.compare(.eq, Value.one, lhs_ty, target)) {9848 if (lhs_val.compare(.eq, Value.one, resolved_type, target)) {
9849 return casted_rhs;9849 return casted_rhs;
9850 }9850 }
9851 }9851 }
...@@ -9861,7 +9861,7 @@ fn analyzeArithmetic(...@@ -9861,7 +9861,7 @@ fn analyzeArithmetic(
9861 if (rhs_val.compareWithZero(.eq)) {9861 if (rhs_val.compareWithZero(.eq)) {
9862 return sema.addConstant(resolved_type, Value.zero);9862 return sema.addConstant(resolved_type, Value.zero);
9863 }9863 }
9864 if (rhs_val.compare(.eq, Value.one, rhs_ty, target)) {9864 if (rhs_val.compare(.eq, Value.one, resolved_type, target)) {
9865 return casted_lhs;9865 return casted_lhs;
9866 }9866 }
9867 if (maybe_lhs_val) |lhs_val| {9867 if (maybe_lhs_val) |lhs_val| {
...@@ -9896,7 +9896,7 @@ fn analyzeArithmetic(...@@ -9896,7 +9896,7 @@ fn analyzeArithmetic(
9896 if (lhs_val.compareWithZero(.eq)) {9896 if (lhs_val.compareWithZero(.eq)) {
9897 return sema.addConstant(resolved_type, Value.zero);9897 return sema.addConstant(resolved_type, Value.zero);
9898 }9898 }
9899 if (lhs_val.compare(.eq, Value.one, lhs_ty, target)) {9899 if (lhs_val.compare(.eq, Value.one, resolved_type, target)) {
9900 return casted_rhs;9900 return casted_rhs;
9901 }9901 }
9902 }9902 }
...@@ -9908,7 +9908,7 @@ fn analyzeArithmetic(...@@ -9908,7 +9908,7 @@ fn analyzeArithmetic(
9908 if (rhs_val.compareWithZero(.eq)) {9908 if (rhs_val.compareWithZero(.eq)) {
9909 return sema.addConstant(resolved_type, Value.zero);9909 return sema.addConstant(resolved_type, Value.zero);
9910 }9910 }
9911 if (rhs_val.compare(.eq, Value.one, rhs_ty, target)) {9911 if (rhs_val.compare(.eq, Value.one, resolved_type, target)) {
9912 return casted_lhs;9912 return casted_lhs;
9913 }9913 }
9914 if (maybe_lhs_val) |lhs_val| {9914 if (maybe_lhs_val) |lhs_val| {
...@@ -9932,7 +9932,7 @@ fn analyzeArithmetic(...@@ -9932,7 +9932,7 @@ fn analyzeArithmetic(
9932 if (lhs_val.compareWithZero(.eq)) {9932 if (lhs_val.compareWithZero(.eq)) {
9933 return sema.addConstant(resolved_type, Value.zero);9933 return sema.addConstant(resolved_type, Value.zero);
9934 }9934 }
9935 if (lhs_val.compare(.eq, Value.one, lhs_ty, target)) {9935 if (lhs_val.compare(.eq, Value.one, resolved_type, target)) {
9936 return casted_rhs;9936 return casted_rhs;
9937 }9937 }
9938 }9938 }
...@@ -9944,7 +9944,7 @@ fn analyzeArithmetic(...@@ -9944,7 +9944,7 @@ fn analyzeArithmetic(
9944 if (rhs_val.compareWithZero(.eq)) {9944 if (rhs_val.compareWithZero(.eq)) {
9945 return sema.addConstant(resolved_type, Value.zero);9945 return sema.addConstant(resolved_type, Value.zero);
9946 }9946 }
9947 if (rhs_val.compare(.eq, Value.one, rhs_ty, target)) {9947 if (rhs_val.compare(.eq, Value.one, resolved_type, target)) {
9948 return casted_lhs;9948 return casted_lhs;
9949 }9949 }
9950 if (maybe_lhs_val) |lhs_val| {9950 if (maybe_lhs_val) |lhs_val| {
...@@ -14521,9 +14521,20 @@ fn checkVectorizableBinaryOperands(...@@ -14521,9 +14521,20 @@ fn checkVectorizableBinaryOperands(
14521) CompileError!void {14521) CompileError!void {
14522 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();14522 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
14523 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();14523 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
14524 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {14524 if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return;
14525 const lhs_len = lhs_ty.vectorLen();14525
14526 const rhs_len = rhs_ty.vectorLen();14526 const lhs_is_vector = switch (lhs_zig_ty_tag) {
14527 .Vector, .Array => true,
14528 else => false,
14529 };
14530 const rhs_is_vector = switch (rhs_zig_ty_tag) {
14531 .Vector, .Array => true,
14532 else => false,
14533 };
14534
14535 if (lhs_is_vector and rhs_is_vector) {
14536 const lhs_len = lhs_ty.arrayLen();
14537 const rhs_len = rhs_ty.arrayLen();
14527 if (lhs_len != rhs_len) {14538 if (lhs_len != rhs_len) {
14528 const msg = msg: {14539 const msg = msg: {
14529 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});14540 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
...@@ -14534,14 +14545,14 @@ fn checkVectorizableBinaryOperands(...@@ -14534,14 +14545,14 @@ fn checkVectorizableBinaryOperands(
14534 };14545 };
14535 return sema.failWithOwnedErrorMsg(block, msg);14546 return sema.failWithOwnedErrorMsg(block, msg);
14536 }14547 }
14537 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {14548 } else {
14538 const target = sema.mod.getTarget();14549 const target = sema.mod.getTarget();
14539 const msg = msg: {14550 const msg = msg: {
14540 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{14551 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{
14541 lhs_ty.fmt(target), rhs_ty.fmt(target),14552 lhs_ty.fmt(target), rhs_ty.fmt(target),
14542 });14553 });
14543 errdefer msg.destroy(sema.gpa);14554 errdefer msg.destroy(sema.gpa);
14544 if (lhs_zig_ty_tag == .Vector) {14555 if (lhs_is_vector) {
14545 try sema.errNote(block, lhs_src, msg, "vector here", .{});14556 try sema.errNote(block, lhs_src, msg, "vector here", .{});
14546 try sema.errNote(block, rhs_src, msg, "scalar here", .{});14557 try sema.errNote(block, rhs_src, msg, "scalar here", .{});
14547 } else {14558 } else {
...@@ -21017,6 +21028,18 @@ fn resolvePeerTypes(...@@ -21017,6 +21028,18 @@ fn resolvePeerTypes(
21017 chosen_i = candidate_i + 1;21028 chosen_i = candidate_i + 1;
21018 continue;21029 continue;
21019 },21030 },
21031 .Vector => switch (chosen_ty_tag) {
21032 .Array => {
21033 chosen = candidate;
21034 chosen_i = candidate_i + 1;
21035 continue;
21036 },
21037 else => {},
21038 },
21039 .Array => switch (chosen_ty_tag) {
21040 .Vector => continue,
21041 else => {},
21042 },
21020 else => {},21043 else => {},
21021 }21044 }
2102221045
test/behavior/vector.zig+24
...@@ -879,3 +879,27 @@ test "saturating shift-left" {...@@ -879,3 +879,27 @@ test "saturating shift-left" {
879 try S.doTheTest();879 try S.doTheTest();
880 comptime try S.doTheTest();880 comptime try S.doTheTest();
881}881}
882
883test "multiplication-assignment operator with an array operand" {
884 if (builtin.zig_backend == .stage1) {
885 // stage1 emits a compile error
886 return error.SkipZigTest;
887 }
888 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
889 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
890 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
891 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893
894 const S = struct {
895 fn doTheTest() !void {
896 var x: @Vector(3, i32) = .{ 1, 2, 3 };
897 x *= [_]i32{ 4, 5, 6 };
898 try expect(x[0] == 4);
899 try expect(x[1] == 10);
900 try expect(x[2] == 18);
901 }
902 };
903 try S.doTheTest();
904 comptime try S.doTheTest();
905}