| author | |
| committer | |
| log | 52bb71867d8d6e738eefb7dafead875eb21a4ae7 |
| tree | 317c8b0f23e603c590f943700587c3a6596bc8ff |
| parent | 2fe8a0831f2830a3357cdf65b2ebfe1214b13a83 |
| signature |
also fix vector behavior tests, they weren't actually testing
runtime vectors, but now they are.
See #9035 files changed, 157 insertions(+), 47 deletions(-)
src/codegen.cpp+6-5| ... | @@ -3229,7 +3229,8 @@ static LLVMValueRef ir_render_br(CodeGen *g, IrExecutable *executable, IrInstruc | ... | @@ -3229,7 +3229,8 @@ static LLVMValueRef ir_render_br(CodeGen *g, IrExecutable *executable, IrInstruc |
| 3229 | static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInstructionUnOp *un_op_instruction) { | 3229 | static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInstructionUnOp *un_op_instruction) { |
| 3230 | IrUnOp op_id = un_op_instruction->op_id; | 3230 | IrUnOp op_id = un_op_instruction->op_id; |
| 3231 | LLVMValueRef expr = ir_llvm_value(g, un_op_instruction->value); | 3231 | LLVMValueRef expr = ir_llvm_value(g, un_op_instruction->value); |
| 3232 | ZigType *expr_type = un_op_instruction->value->value.type; | 3232 | ZigType *operand_type = un_op_instruction->value->value.type; |
| 3233 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; | ||
| 3233 | 3234 | ||
| 3234 | switch (op_id) { | 3235 | switch (op_id) { |
| 3235 | case IrUnOpInvalid: | 3236 | case IrUnOpInvalid: |
| ... | @@ -3239,16 +3240,16 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -3239,16 +3240,16 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst |
| 3239 | case IrUnOpNegation: | 3240 | case IrUnOpNegation: |
| 3240 | case IrUnOpNegationWrap: | 3241 | case IrUnOpNegationWrap: |
| 3241 | { | 3242 | { |
| 3242 | if (expr_type->id == ZigTypeIdFloat) { | 3243 | if (scalar_type->id == ZigTypeIdFloat) { |
| 3243 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &un_op_instruction->base)); | 3244 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &un_op_instruction->base)); |
| 3244 | return LLVMBuildFNeg(g->builder, expr, ""); | 3245 | return LLVMBuildFNeg(g->builder, expr, ""); |
| 3245 | } else if (expr_type->id == ZigTypeIdInt) { | 3246 | } else if (scalar_type->id == ZigTypeIdInt) { |
| 3246 | if (op_id == IrUnOpNegationWrap) { | 3247 | if (op_id == IrUnOpNegationWrap) { |
| 3247 | return LLVMBuildNeg(g->builder, expr, ""); | 3248 | return LLVMBuildNeg(g->builder, expr, ""); |
| 3248 | } else if (ir_want_runtime_safety(g, &un_op_instruction->base)) { | 3249 | } else if (ir_want_runtime_safety(g, &un_op_instruction->base)) { |
| 3249 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr)); | 3250 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr)); |
| 3250 | return gen_overflow_op(g, expr_type, AddSubMulSub, zero, expr); | 3251 | return gen_overflow_op(g, operand_type, AddSubMulSub, zero, expr); |
| 3251 | } else if (expr_type->data.integral.is_signed) { | 3252 | } else if (scalar_type->data.integral.is_signed) { |
| 3252 | return LLVMBuildNSWNeg(g->builder, expr, ""); | 3253 | return LLVMBuildNSWNeg(g->builder, expr, ""); |
| 3253 | } else { | 3254 | } else { |
| 3254 | return LLVMBuildNUWNeg(g->builder, expr, ""); | 3255 | return LLVMBuildNUWNeg(g->builder, expr, ""); |
src/ir.cpp+71-33| ... | @@ -14620,6 +14620,41 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ | ... | @@ -14620,6 +14620,41 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ |
| 14620 | zig_unreachable(); | 14620 | zig_unreachable(); |
| 14621 | } | 14621 | } |
| 14622 | 14622 | ||
| 14623 | static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type, | ||
| 14624 | ConstExprValue *operand_val, ConstExprValue *scalar_out_val, bool is_wrap_op) | ||
| 14625 | { | ||
| 14626 | bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat); | ||
| 14627 | |||
| 14628 | bool ok_type = ((scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) || | ||
| 14629 | scalar_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op)); | ||
| 14630 | |||
| 14631 | if (!ok_type) { | ||
| 14632 | const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; | ||
| 14633 | return ir_add_error(ira, source_instr, buf_sprintf(fmt, buf_ptr(&scalar_type->name))); | ||
| 14634 | } | ||
| 14635 | |||
| 14636 | if (is_float) { | ||
| 14637 | float_negate(scalar_out_val, operand_val); | ||
| 14638 | } else if (is_wrap_op) { | ||
| 14639 | bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint, | ||
| 14640 | scalar_type->data.integral.bit_count); | ||
| 14641 | } else { | ||
| 14642 | bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint); | ||
| 14643 | } | ||
| 14644 | |||
| 14645 | scalar_out_val->type = scalar_type; | ||
| 14646 | scalar_out_val->special = ConstValSpecialStatic; | ||
| 14647 | |||
| 14648 | if (is_wrap_op || is_float || scalar_type->id == ZigTypeIdComptimeInt) { | ||
| 14649 | return nullptr; | ||
| 14650 | } | ||
| 14651 | |||
| 14652 | if (!bigint_fits_in_bits(&scalar_out_val->data.x_bigint, scalar_type->data.integral.bit_count, true)) { | ||
| 14653 | return ir_add_error(ira, source_instr, buf_sprintf("negation caused overflow")); | ||
| 14654 | } | ||
| 14655 | return nullptr; | ||
| 14656 | } | ||
| 14657 | |||
| 14623 | static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *instruction) { | 14658 | static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *instruction) { |
| 14624 | IrInstruction *value = instruction->value->child; | 14659 | IrInstruction *value = instruction->value->child; |
| 14625 | ZigType *expr_type = value->value.type; | 14660 | ZigType *expr_type = value->value.type; |
| ... | @@ -14628,47 +14663,50 @@ static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *ins | ... | @@ -14628,47 +14663,50 @@ static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *ins |
| 14628 | 14663 | ||
| 14629 | bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap); | 14664 | bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap); |
| 14630 | 14665 | ||
| 14631 | bool is_float = (expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat); | 14666 | ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; |
| 14632 | 14667 | ||
| 14633 | if ((expr_type->id == ZigTypeIdInt && expr_type->data.integral.is_signed) || | 14668 | if (instr_is_comptime(value)) { |
| 14634 | expr_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op)) | 14669 | ConstExprValue *operand_val = ir_resolve_const(ira, value, UndefBad); |
| 14635 | { | 14670 | if (!operand_val) |
| 14636 | if (instr_is_comptime(value)) { | 14671 | return ira->codegen->invalid_instruction; |
| 14637 | ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad); | ||
| 14638 | if (!target_const_val) | ||
| 14639 | return ira->codegen->invalid_instruction; | ||
| 14640 | 14672 | ||
| 14641 | IrInstruction *result = ir_const(ira, &instruction->base, expr_type); | 14673 | IrInstruction *result_instruction = ir_const(ira, &instruction->base, expr_type); |
| 14642 | ConstExprValue *out_val = &result->value; | 14674 | ConstExprValue *out_val = &result_instruction->value; |
| 14643 | if (is_float) { | 14675 | if (expr_type->id == ZigTypeIdVector) { |
| 14644 | float_negate(out_val, target_const_val); | 14676 | expand_undef_array(ira->codegen, operand_val); |
| 14645 | } else if (is_wrap_op) { | 14677 | out_val->special = ConstValSpecialUndef; |
| 14646 | bigint_negate_wrap(&out_val->data.x_bigint, &target_const_val->data.x_bigint, | 14678 | expand_undef_array(ira->codegen, out_val); |
| 14647 | expr_type->data.integral.bit_count); | 14679 | size_t len = expr_type->data.vector.len; |
| 14648 | } else { | 14680 | for (size_t i = 0; i < len; i += 1) { |
| 14649 | bigint_negate(&out_val->data.x_bigint, &target_const_val->data.x_bigint); | 14681 | ConstExprValue *scalar_operand_val = &operand_val->data.x_array.data.s_none.elements[i]; |
| 14650 | } | 14682 | ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; |
| 14651 | if (is_wrap_op || is_float || expr_type->id == ZigTypeIdComptimeInt) { | 14683 | assert(scalar_operand_val->type == scalar_type); |
| 14652 | return result; | 14684 | assert(scalar_out_val->type == scalar_type); |
| 14685 | ErrorMsg *msg = ir_eval_negation_scalar(ira, &instruction->base, scalar_type, | ||
| 14686 | scalar_operand_val, scalar_out_val, is_wrap_op); | ||
| 14687 | if (msg != nullptr) { | ||
| 14688 | add_error_note(ira->codegen, msg, instruction->base.source_node, | ||
| 14689 | buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); | ||
| 14690 | return ira->codegen->invalid_instruction; | ||
| 14691 | } | ||
| 14653 | } | 14692 | } |
| 14654 | 14693 | out_val->type = expr_type; | |
| 14655 | if (!bigint_fits_in_bits(&out_val->data.x_bigint, expr_type->data.integral.bit_count, true)) { | 14694 | out_val->special = ConstValSpecialStatic; |
| 14656 | ir_add_error(ira, &instruction->base, buf_sprintf("negation caused overflow")); | 14695 | } else { |
| 14696 | if (ir_eval_negation_scalar(ira, &instruction->base, scalar_type, operand_val, out_val, | ||
| 14697 | is_wrap_op) != nullptr) | ||
| 14698 | { | ||
| 14657 | return ira->codegen->invalid_instruction; | 14699 | return ira->codegen->invalid_instruction; |
| 14658 | } | 14700 | } |
| 14659 | return result; | ||
| 14660 | } | 14701 | } |
| 14661 | 14702 | return result_instruction; | |
| 14662 | IrInstruction *result = ir_build_un_op(&ira->new_irb, | ||
| 14663 | instruction->base.scope, instruction->base.source_node, | ||
| 14664 | instruction->op_id, value); | ||
| 14665 | result->value.type = expr_type; | ||
| 14666 | return result; | ||
| 14667 | } | 14703 | } |
| 14668 | 14704 | ||
| 14669 | const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; | 14705 | IrInstruction *result = ir_build_un_op(&ira->new_irb, |
| 14670 | ir_add_error(ira, &instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name))); | 14706 | instruction->base.scope, instruction->base.source_node, |
| 14671 | return ira->codegen->invalid_instruction; | 14707 | instruction->op_id, value); |
| 14708 | result->value.type = expr_type; | ||
| 14709 | return result; | ||
| 14672 | } | 14710 | } |
| 14673 | 14711 | ||
| 14674 | static IrInstruction *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *instruction) { | 14712 | static IrInstruction *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *instruction) { |
test/compile_errors.zig+12| ... | @@ -1,6 +1,18 @@ | ... | @@ -1,6 +1,18 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4 | cases.addTest( | ||
| 5 | "comptime vector overflow shows the index", | ||
| 6 | \\comptime { | ||
| 7 | \\ var a: @Vector(4, u8) = []u8{ 1, 2, 255, 4 }; | ||
| 8 | \\ var b: @Vector(4, u8) = []u8{ 5, 6, 1, 8 }; | ||
| 9 | \\ var x = a + b; | ||
| 10 | \\} | ||
| 11 | , | ||
| 12 | ".tmp_source.zig:4:15: error: operation caused overflow", | ||
| 13 | ".tmp_source.zig:4:15: note: when computing vector element at index 2", | ||
| 14 | ); | ||
| 15 | |||
| 4 | cases.addTest( | 16 | cases.addTest( |
| 5 | "packed struct with fields of not allowed types", | 17 | "packed struct with fields of not allowed types", |
| 6 | \\const A = packed struct { | 18 | \\const A = packed struct { |
test/runtime_safety.zig+41| ... | @@ -118,6 +118,47 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -118,6 +118,47 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 118 | \\} | 118 | \\} |
| 119 | ); | 119 | ); |
| 120 | 120 | ||
| 121 | cases.addRuntimeSafety("vector integer subtraction overflow", | ||
| 122 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | ||
| 123 | \\ @import("std").os.exit(126); | ||
| 124 | \\} | ||
| 125 | \\pub fn main() void { | ||
| 126 | \\ var a: @Vector(4, u32) = []u32{ 1, 2, 8, 4 }; | ||
| 127 | \\ var b: @Vector(4, u32) = []u32{ 5, 6, 7, 8 }; | ||
| 128 | \\ const x = sub(b, a); | ||
| 129 | \\} | ||
| 130 | \\fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) { | ||
| 131 | \\ return a - b; | ||
| 132 | \\} | ||
| 133 | ); | ||
| 134 | |||
| 135 | cases.addRuntimeSafety("vector integer multiplication overflow", | ||
| 136 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | ||
| 137 | \\ @import("std").os.exit(126); | ||
| 138 | \\} | ||
| 139 | \\pub fn main() void { | ||
| 140 | \\ var a: @Vector(4, u8) = []u8{ 1, 2, 200, 4 }; | ||
| 141 | \\ var b: @Vector(4, u8) = []u8{ 5, 6, 2, 8 }; | ||
| 142 | \\ const x = mul(b, a); | ||
| 143 | \\} | ||
| 144 | \\fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) { | ||
| 145 | \\ return a * b; | ||
| 146 | \\} | ||
| 147 | ); | ||
| 148 | |||
| 149 | cases.addRuntimeSafety("vector integer negation overflow", | ||
| 150 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | ||
| 151 | \\ @import("std").os.exit(126); | ||
| 152 | \\} | ||
| 153 | \\pub fn main() void { | ||
| 154 | \\ var a: @Vector(4, i16) = []i16{ 1, -32768, 200, 4 }; | ||
| 155 | \\ const x = neg(a); | ||
| 156 | \\} | ||
| 157 | \\fn neg(a: @Vector(4, i16)) @Vector(4, i16) { | ||
| 158 | \\ return -a; | ||
| 159 | \\} | ||
| 160 | ); | ||
| 161 | |||
| 121 | cases.addRuntimeSafety("integer subtraction overflow", | 162 | cases.addRuntimeSafety("integer subtraction overflow", |
| 122 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 163 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { |
| 123 | \\ @import("std").os.exit(126); | 164 | \\ @import("std").os.exit(126); |
test/stage1/behavior/vector.zig+27-9| ... | @@ -5,11 +5,28 @@ const expect = std.testing.expect; | ... | @@ -5,11 +5,28 @@ const expect = std.testing.expect; |
| 5 | test "vector wrap operators" { | 5 | test "vector wrap operators" { |
| 6 | const S = struct { | 6 | const S = struct { |
| 7 | fn doTheTest() void { | 7 | fn doTheTest() void { |
| 8 | const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; | 8 | var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; |
| 9 | const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; | 9 | var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; |
| 10 | expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 })); | 10 | expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ -2147483648, 2147483645, 33, 44 })); |
| 11 | expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 })); | 11 | expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 2147483646, 2147483647, 27, 36 })); |
| 12 | expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 })); | 12 | expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 2147483647, 2, 90, 160 })); |
| 13 | var z: @Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 }; | ||
| 14 | expect(mem.eql(i32, ([4]i32)(-%z), [4]i32{ -1, -2, -3, -2147483648 })); | ||
| 15 | } | ||
| 16 | }; | ||
| 17 | S.doTheTest(); | ||
| 18 | comptime S.doTheTest(); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "vector int operators" { | ||
| 22 | const S = struct { | ||
| 23 | fn doTheTest() void { | ||
| 24 | var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; | ||
| 25 | var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; | ||
| 26 | expect(mem.eql(i32, ([4]i32)(v + x), [4]i32{ 11, 22, 33, 44 })); | ||
| 27 | expect(mem.eql(i32, ([4]i32)(v - x), [4]i32{ 9, 18, 27, 36 })); | ||
| 28 | expect(mem.eql(i32, ([4]i32)(v * x), [4]i32{ 10, 40, 90, 160 })); | ||
| 29 | expect(mem.eql(i32, ([4]i32)(-v), [4]i32{ -10, -20, -30, -40 })); | ||
| 13 | } | 30 | } |
| 14 | }; | 31 | }; |
| 15 | S.doTheTest(); | 32 | S.doTheTest(); |
| ... | @@ -19,11 +36,12 @@ test "vector wrap operators" { | ... | @@ -19,11 +36,12 @@ test "vector wrap operators" { |
| 19 | test "vector float operators" { | 36 | test "vector float operators" { |
| 20 | const S = struct { | 37 | const S = struct { |
| 21 | fn doTheTest() void { | 38 | fn doTheTest() void { |
| 22 | const v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 }; | 39 | var v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 }; |
| 23 | const x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 }; | 40 | var x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 }; |
| 24 | expect(mem.eql(f32, ([4]f32)(v + x), [4]f32{ 11, 22, 33, 44 })); | 41 | expect(mem.eql(f32, ([4]f32)(v + x), [4]f32{ 11, 22, 33, 44 })); |
| 25 | expect(mem.eql(f32, ([4]f32)(v - x), [4]f32{ 9, 18, 27, 36 })); | 42 | expect(mem.eql(f32, ([4]f32)(v - x), [4]f32{ 9, 18, 27, 36 })); |
| 26 | expect(mem.eql(f32, ([4]f32)(v * x), [4]f32{ 10, 40, 90, 160 })); | 43 | expect(mem.eql(f32, ([4]f32)(v * x), [4]f32{ 10, 40, 90, 160 })); |
| 44 | expect(mem.eql(f32, ([4]f32)(-x), [4]f32{ -1, -2, -3, -4 })); | ||
| 27 | } | 45 | } |
| 28 | }; | 46 | }; |
| 29 | S.doTheTest(); | 47 | S.doTheTest(); |
| ... | @@ -33,8 +51,8 @@ test "vector float operators" { | ... | @@ -33,8 +51,8 @@ test "vector float operators" { |
| 33 | test "vector bit operators" { | 51 | test "vector bit operators" { |
| 34 | const S = struct { | 52 | const S = struct { |
| 35 | fn doTheTest() void { | 53 | fn doTheTest() void { |
| 36 | const v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; | 54 | var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; |
| 37 | const x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 }; | 55 | var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 }; |
| 38 | expect(mem.eql(u8, ([4]u8)(v ^ x), [4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 })); | 56 | expect(mem.eql(u8, ([4]u8)(v ^ x), [4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 })); |
| 39 | expect(mem.eql(u8, ([4]u8)(v | x), [4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 })); | 57 | expect(mem.eql(u8, ([4]u8)(v | x), [4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 })); |
| 40 | expect(mem.eql(u8, ([4]u8)(v & x), [4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 })); | 58 | expect(mem.eql(u8, ([4]u8)(v & x), [4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 })); |