authorgravatar for dakongsgaard@gmail.comDaniel Kongsgaard <dakongsgaard@gmail.com> 2025-06-13 00:16:23+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-06-12 15:16:23-07:00
log5e3c0b7af7cd866f5464c244b9775e488b93ae48
tree3e13c42df3ad3491c5b920c986abd62298b4e450
parent4a02e080d127cc577d40f8ea5d68122ba8ac4243
signaturebadge-check Signed by PGP key B5690EEEBB952194

Allow more operators on bool vectors (#24131)

* Sema: allow binary operations and boolean not on vectors of bool * langref: Clarify use of operators on vectors (`and` and `or` not allowed) closes #24093

5 files changed, 79 insertions(+), 50 deletions(-)

doc/langref.html.in+5-2
...@@ -1926,8 +1926,10 @@ or...@@ -1926,8 +1926,10 @@ or
1926 Vector types are created with the builtin function {#link|@Vector#}.1926 Vector types are created with the builtin function {#link|@Vector#}.
1927 </p>1927 </p>
1928 <p>1928 <p>
1929 Vectors support the same builtin operators as their underlying base types.1929 Vectors generally support the same builtin operators as their underlying base types.
1930 These operations are performed element-wise, and return a vector of the same length1930 The only exception to this is the keywords `and` and `or` on vectors of bools, since
1931 these operators affect control flow, which is not allowed for vectors.
1932 All other operations are performed element-wise, and return a vector of the same length
1931 as the input vectors. This includes:1933 as the input vectors. This includes:
1932 </p>1934 </p>
1933 <ul>1935 <ul>
...@@ -1937,6 +1939,7 @@ or...@@ -1937,6 +1939,7 @@ or
1937 <li>Bitwise operators ({#syntax#}>>{#endsyntax#}, {#syntax#}<<{#endsyntax#}, {#syntax#}&{#endsyntax#},1939 <li>Bitwise operators ({#syntax#}>>{#endsyntax#}, {#syntax#}<<{#endsyntax#}, {#syntax#}&{#endsyntax#},
1938 {#syntax#}|{#endsyntax#}, {#syntax#}~{#endsyntax#}, etc.)</li>1940 {#syntax#}|{#endsyntax#}, {#syntax#}~{#endsyntax#}, etc.)</li>
1939 <li>Comparison operators ({#syntax#}<{#endsyntax#}, {#syntax#}>{#endsyntax#}, {#syntax#}=={#endsyntax#}, etc.)</li>1941 <li>Comparison operators ({#syntax#}<{#endsyntax#}, {#syntax#}>{#endsyntax#}, {#syntax#}=={#endsyntax#}, etc.)</li>
1942 <li>Boolean not ({#syntax#}!{#endsyntax#})</li>
1940 </ul>1943 </ul>
1941 <p>1944 <p>
1942 It is prohibited to use a math operator on a mixture of scalars (individual numbers)1945 It is prohibited to use a math operator on a mixture of scalars (individual numbers)
lib/std/zig/AstGen.zig+1-1
...@@ -806,7 +806,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -806,7 +806,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
806 .bool_and => return boolBinOp(gz, scope, ri, node, .bool_br_and),806 .bool_and => return boolBinOp(gz, scope, ri, node, .bool_br_and),
807 .bool_or => return boolBinOp(gz, scope, ri, node, .bool_br_or),807 .bool_or => return boolBinOp(gz, scope, ri, node, .bool_br_or),
808808
809 .bool_not => return simpleUnOp(gz, scope, ri, node, coerced_bool_ri, tree.nodeData(node).node, .bool_not),809 .bool_not => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, tree.nodeData(node).node, .bool_not),
810 .bit_not => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, tree.nodeData(node).node, .bit_not),810 .bit_not => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, tree.nodeData(node).node, .bit_not),
811811
812 .negation => return negation(gz, scope, ri, node),812 .negation => return negation(gz, scope, ri, node),
src/Sema.zig+17-27
...@@ -1171,11 +1171,11 @@ fn analyzeBodyInner(...@@ -1171,11 +1171,11 @@ fn analyzeBodyInner(
1171 .as_node => try sema.zirAsNode(block, inst),1171 .as_node => try sema.zirAsNode(block, inst),
1172 .as_shift_operand => try sema.zirAsShiftOperand(block, inst),1172 .as_shift_operand => try sema.zirAsShiftOperand(block, inst),
1173 .bit_and => try sema.zirBitwise(block, inst, .bit_and),1173 .bit_and => try sema.zirBitwise(block, inst, .bit_and),
1174 .bit_not => try sema.zirBitNot(block, inst),1174 .bit_not => try sema.zirBitNot(block, inst, false),
1175 .bit_or => try sema.zirBitwise(block, inst, .bit_or),1175 .bit_or => try sema.zirBitwise(block, inst, .bit_or),
1176 .bitcast => try sema.zirBitcast(block, inst),1176 .bitcast => try sema.zirBitcast(block, inst),
1177 .suspend_block => try sema.zirSuspendBlock(block, inst),1177 .suspend_block => try sema.zirSuspendBlock(block, inst),
1178 .bool_not => try sema.zirBoolNot(block, inst),1178 .bool_not => try sema.zirBitNot(block, inst, true),
1179 .bool_br_and => try sema.zirBoolBr(block, inst, false),1179 .bool_br_and => try sema.zirBoolBr(block, inst, false),
1180 .bool_br_or => try sema.zirBoolBr(block, inst, true),1180 .bool_br_or => try sema.zirBoolBr(block, inst, true),
1181 .c_import => try sema.zirCImport(block, inst),1181 .c_import => try sema.zirCImport(block, inst),
...@@ -14412,9 +14412,9 @@ fn zirBitwise(...@@ -14412,9 +14412,9 @@ fn zirBitwise(
14412 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);14412 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
14413 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);14413 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1441414414
14415 const is_int = scalar_tag == .int or scalar_tag == .comptime_int;14415 const is_int_or_bool = scalar_tag == .int or scalar_tag == .comptime_int or scalar_tag == .bool;
1441614416
14417 if (!is_int) {14417 if (!is_int_or_bool) {
14418 return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag(zcu)), @tagName(rhs_ty.zigTypeTag(zcu)) });14418 return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag(zcu)), @tagName(rhs_ty.zigTypeTag(zcu)) });
14419 }14419 }
1442014420
...@@ -14442,7 +14442,12 @@ fn zirBitwise(...@@ -14442,7 +14442,12 @@ fn zirBitwise(
14442 return block.addBinOp(air_tag, casted_lhs, casted_rhs);14442 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
14443}14443}
1444414444
14445fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {14445fn zirBitNot(
14446 sema: *Sema,
14447 block: *Block,
14448 inst: Zir.Inst.Index,
14449 is_bool_not: bool,
14450) CompileError!Air.Inst.Ref {
14446 const tracy = trace(@src());14451 const tracy = trace(@src());
14447 defer tracy.end();14452 defer tracy.end();
1444814453
...@@ -14455,10 +14460,14 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -14455,10 +14460,14 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
14455 const operand = try sema.resolveInst(inst_data.operand);14460 const operand = try sema.resolveInst(inst_data.operand);
14456 const operand_type = sema.typeOf(operand);14461 const operand_type = sema.typeOf(operand);
14457 const scalar_type = operand_type.scalarType(zcu);14462 const scalar_type = operand_type.scalarType(zcu);
14463 const scalar_tag = scalar_type.zigTypeTag(zcu);
1445814464
14459 if (scalar_type.zigTypeTag(zcu) != .int) {14465 const is_finite_int_or_bool = scalar_tag == .int or scalar_tag == .bool;
14460 return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{14466 const is_allowed_type = if (is_bool_not) scalar_tag == .bool else is_finite_int_or_bool;
14461 operand_type.fmt(pt),14467
14468 if (!is_allowed_type) {
14469 return sema.fail(block, src, "unable to perform {s} not operation on type '{}'", .{
14470 if (is_bool_not) "boolean" else "binary", operand_type.fmt(pt),
14462 });14471 });
14463 }14472 }
1446414473
...@@ -18336,25 +18345,6 @@ fn zirTypeofPeer(...@@ -18336,25 +18345,6 @@ fn zirTypeofPeer(
18336 return Air.internedToRef(result_type.toIntern());18345 return Air.internedToRef(result_type.toIntern());
18337}18346}
1833818347
18339fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
18340 const tracy = trace(@src());
18341 defer tracy.end();
18342
18343 const pt = sema.pt;
18344 const zcu = pt.zcu;
18345 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
18346 const src = block.nodeOffset(inst_data.src_node);
18347 const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
18348 const uncasted_operand = try sema.resolveInst(inst_data.operand);
18349
18350 const operand = try sema.coerce(block, .bool, uncasted_operand, operand_src);
18351 if (try sema.resolveValue(operand)) |val| {
18352 return if (val.isUndef(zcu)) .undef_bool else if (val.toBool()) .bool_false else .bool_true;
18353 }
18354 try sema.requireRuntimeBlock(block, src, null);
18355 return block.addTyOp(.not, .bool, operand);
18356}
18357
18358fn zirBoolBr(18348fn zirBoolBr(
18359 sema: *Sema,18349 sema: *Sema,
18360 parent_block: *Block,18350 parent_block: *Block,
src/Value.zig+10-10
...@@ -1627,7 +1627,7 @@ pub fn numberMin(lhs: Value, rhs: Value, zcu: *Zcu) Value {...@@ -1627,7 +1627,7 @@ pub fn numberMin(lhs: Value, rhs: Value, zcu: *Zcu) Value {
1627 };1627 };
1628}1628}
16291629
1630/// operands must be (vectors of) integers; handles undefined scalars.1630/// operands must be (vectors of) integers or bools; handles undefined scalars.
1631pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1631pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1632 const zcu = pt.zcu;1632 const zcu = pt.zcu;
1633 if (ty.zigTypeTag(zcu) == .vector) {1633 if (ty.zigTypeTag(zcu) == .vector) {
...@@ -1645,7 +1645,7 @@ pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Va...@@ -1645,7 +1645,7 @@ pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Va
1645 return bitwiseNotScalar(val, ty, arena, pt);1645 return bitwiseNotScalar(val, ty, arena, pt);
1646}1646}
16471647
1648/// operands must be integers; handles undefined.1648/// operands must be integers or bools; handles undefined.
1649pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1649pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1650 const zcu = pt.zcu;1650 const zcu = pt.zcu;
1651 if (val.isUndef(zcu)) return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));1651 if (val.isUndef(zcu)) return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
...@@ -1671,7 +1671,7 @@ pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThrea...@@ -1671,7 +1671,7 @@ pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, pt: Zcu.PerThrea
1671 return pt.intValue_big(ty, result_bigint.toConst());1671 return pt.intValue_big(ty, result_bigint.toConst());
1672}1672}
16731673
1674/// operands must be (vectors of) integers; handles undefined scalars.1674/// operands must be (vectors of) integers or bools; handles undefined scalars.
1675pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu.PerThread) !Value {1675pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu.PerThread) !Value {
1676 const zcu = pt.zcu;1676 const zcu = pt.zcu;
1677 if (ty.zigTypeTag(zcu) == .vector) {1677 if (ty.zigTypeTag(zcu) == .vector) {
...@@ -1690,7 +1690,7 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zc...@@ -1690,7 +1690,7 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zc
1690 return bitwiseAndScalar(lhs, rhs, ty, allocator, pt);1690 return bitwiseAndScalar(lhs, rhs, ty, allocator, pt);
1691}1691}
16921692
1693/// operands must be integers; handles undefined.1693/// operands must be integers or bools; handles undefined.
1694pub fn bitwiseAndScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1694pub fn bitwiseAndScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1695 const zcu = pt.zcu;1695 const zcu = pt.zcu;
1696 // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can1696 // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can
...@@ -1744,7 +1744,7 @@ fn intValueAa(ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {...@@ -1744,7 +1744,7 @@ fn intValueAa(ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1744 return pt.intValue_big(ty, result_bigint.toConst());1744 return pt.intValue_big(ty, result_bigint.toConst());
1745}1745}
17461746
1747/// operands must be (vectors of) integers; handles undefined scalars.1747/// operands must be (vectors of) integers or bools; handles undefined scalars.
1748pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1748pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1749 const zcu = pt.zcu;1749 const zcu = pt.zcu;
1750 if (ty.zigTypeTag(zcu) == .vector) {1750 if (ty.zigTypeTag(zcu) == .vector) {
...@@ -1763,7 +1763,7 @@ pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.P...@@ -1763,7 +1763,7 @@ pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.P
1763 return bitwiseNandScalar(lhs, rhs, ty, arena, pt);1763 return bitwiseNandScalar(lhs, rhs, ty, arena, pt);
1764}1764}
17651765
1766/// operands must be integers; handles undefined.1766/// operands must be integers or bools; handles undefined.
1767pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1767pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1768 const zcu = pt.zcu;1768 const zcu = pt.zcu;
1769 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));1769 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
...@@ -1774,7 +1774,7 @@ pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt:...@@ -1774,7 +1774,7 @@ pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt:
1774 return bitwiseXor(anded, all_ones, ty, arena, pt);1774 return bitwiseXor(anded, all_ones, ty, arena, pt);
1775}1775}
17761776
1777/// operands must be (vectors of) integers; handles undefined scalars.1777/// operands must be (vectors of) integers or bools; handles undefined scalars.
1778pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu.PerThread) !Value {1778pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu.PerThread) !Value {
1779 const zcu = pt.zcu;1779 const zcu = pt.zcu;
1780 if (ty.zigTypeTag(zcu) == .vector) {1780 if (ty.zigTypeTag(zcu) == .vector) {
...@@ -1793,7 +1793,7 @@ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu...@@ -1793,7 +1793,7 @@ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu
1793 return bitwiseOrScalar(lhs, rhs, ty, allocator, pt);1793 return bitwiseOrScalar(lhs, rhs, ty, allocator, pt);
1794}1794}
17951795
1796/// operands must be integers; handles undefined.1796/// operands must be integers or bools; handles undefined.
1797pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1797pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1798 // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can1798 // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can
1799 // still zero out some bits.1799 // still zero out some bits.
...@@ -1827,7 +1827,7 @@ pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Alloca...@@ -1827,7 +1827,7 @@ pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Alloca
1827 return pt.intValue_big(ty, result_bigint.toConst());1827 return pt.intValue_big(ty, result_bigint.toConst());
1828}1828}
18291829
1830/// operands must be (vectors of) integers; handles undefined scalars.1830/// operands must be (vectors of) integers or bools; handles undefined scalars.
1831pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu.PerThread) !Value {1831pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zcu.PerThread) !Value {
1832 const zcu = pt.zcu;1832 const zcu = pt.zcu;
1833 if (ty.zigTypeTag(zcu) == .vector) {1833 if (ty.zigTypeTag(zcu) == .vector) {
...@@ -1846,7 +1846,7 @@ pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zc...@@ -1846,7 +1846,7 @@ pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, pt: Zc
1846 return bitwiseXorScalar(lhs, rhs, ty, allocator, pt);1846 return bitwiseXorScalar(lhs, rhs, ty, allocator, pt);
1847}1847}
18481848
1849/// operands must be integers; handles undefined.1849/// operands must be integers or bools; handles undefined.
1850pub fn bitwiseXorScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {1850pub fn bitwiseXorScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, pt: Zcu.PerThread) !Value {
1851 const zcu = pt.zcu;1851 const zcu = pt.zcu;
1852 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));1852 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
test/behavior/vector.zig+46-10
...@@ -152,12 +152,22 @@ test "vector bit operators" {...@@ -152,12 +152,22 @@ test "vector bit operators" {
152152
153 const S = struct {153 const S = struct {
154 fn doTheTest() !void {154 fn doTheTest() !void {
155 var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };155 {
156 var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };156 var v: @Vector(4, bool) = [4]bool{ false, false, true, true };
157 _ = .{ &v, &x };157 var x: @Vector(4, bool) = [4]bool{ true, false, true, false };
158 try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));158 _ = .{ &v, &x };
159 try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));159 try expect(mem.eql(bool, &@as([4]bool, v ^ x), &[4]bool{ true, false, false, true }));
160 try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));160 try expect(mem.eql(bool, &@as([4]bool, v | x), &[4]bool{ true, false, true, true }));
161 try expect(mem.eql(bool, &@as([4]bool, v & x), &[4]bool{ false, false, true, false }));
162 }
163 {
164 var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
165 var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
166 _ = .{ &v, &x };
167 try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
168 try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
169 try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));
170 }
161 }171 }
162 };172 };
163 try S.doTheTest();173 try S.doTheTest();
...@@ -659,15 +669,41 @@ test "vector bitwise not operator" {...@@ -659,15 +669,41 @@ test "vector bitwise not operator" {
659 }669 }
660 }670 }
661 fn doTheTest() !void {671 fn doTheTest() !void {
662 try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 });672 try doTheTestNot(bool, [_]bool{ true, false, true, false });
663 try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 });
664 try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 });
665 try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 });
666673
667 try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 });674 try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 });
668 try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 });675 try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 });
669 try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 });676 try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 });
670 try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 });677 try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 });
678
679 try doTheTestNot(i8, [_]i8{ 0, 2, 4, 127 });
680 try doTheTestNot(i16, [_]i16{ 0, 2, 4, 127 });
681 try doTheTestNot(i32, [_]i32{ 0, 2, 4, 127 });
682 try doTheTestNot(i64, [_]i64{ 0, 2, 4, 127 });
683 }
684 };
685
686 try S.doTheTest();
687 try comptime S.doTheTest();
688}
689
690test "vector boolean not operator" {
691 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
692 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
693 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
694 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
695 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
696 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
697
698 const S = struct {
699 fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {
700 const y = !x;
701 for (@as([4]T, y), 0..) |v, i| {
702 try expect(!x[i] == v);
703 }
704 }
705 fn doTheTest() !void {
706 try doTheTestNot(bool, [_]bool{ true, false, true, false });
671 }707 }
672 };708 };
673709