authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-14 20:01:28+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-05 18:34:31-04:00
logd2d97e55ccd2d7c992d01bd05ea52a52fe36776e
tree98da26db32bc99194799c677cc46fbc72704fd1c
parent2485f3004659723a1ccd2799a6e0bddb09e32d3b
signaturelock-open Commit is signed but in an unrecognized format.

ir: Support shift left/right on vectors


3 files changed, 182 insertions(+), 47 deletions(-)

src/codegen.cpp+35-15
......@@ -155,6 +155,7 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstGen *source_instr,
155155 LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type,
156156 LLVMValueRef result_loc, bool non_async);
157157static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix);
158static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val);
158159
159160static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {
160161 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
......@@ -2535,19 +2536,21 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir
25352536 return nullptr;
25362537}
25372538
2538static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,
2539 LLVMValueRef val1, LLVMValueRef val2)
2539static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type,
2540 LLVMValueRef val1, LLVMValueRef val2)
25402541{
25412542 // for unsigned left shifting, we do the lossy shift, then logically shift
25422543 // right the same number of bits
25432544 // if the values don't match, we have an overflow
25442545 // for signed left shifting we do the same except arithmetic shift right
2546 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ?
2547 operand_type->data.vector.elem_type : operand_type;
25452548
2546 assert(type_entry->id == ZigTypeIdInt);
2549 assert(scalar_type->id == ZigTypeIdInt);
25472550
25482551 LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
25492552 LLVMValueRef orig_val;
2550 if (type_entry->data.integral.is_signed) {
2553 if (scalar_type->data.integral.is_signed) {
25512554 orig_val = LLVMBuildAShr(g->builder, result, val2, "");
25522555 } else {
25532556 orig_val = LLVMBuildLShr(g->builder, result, val2, "");
......@@ -2556,6 +2559,9 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,
25562559
25572560 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
25582561 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
2562 if (operand_type->id == ZigTypeIdVector) {
2563 ok_bit = scalarize_cmp_result(g, ok_bit);
2564 }
25592565 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
25602566
25612567 LLVMPositionBuilderAtEnd(g->builder, fail_block);
......@@ -2565,13 +2571,16 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,
25652571 return result;
25662572}
25672573
2568static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,
2569 LLVMValueRef val1, LLVMValueRef val2)
2574static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type,
2575 LLVMValueRef val1, LLVMValueRef val2)
25702576{
2571 assert(type_entry->id == ZigTypeIdInt);
2577 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ?
2578 operand_type->data.vector.elem_type : operand_type;
2579
2580 assert(scalar_type->id == ZigTypeIdInt);
25722581
25732582 LLVMValueRef result;
2574 if (type_entry->data.integral.is_signed) {
2583 if (scalar_type->data.integral.is_signed) {
25752584 result = LLVMBuildAShr(g->builder, val1, val2, "");
25762585 } else {
25772586 result = LLVMBuildLShr(g->builder, val1, val2, "");
......@@ -2581,6 +2590,9 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,
25812590
25822591 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
25832592 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
2593 if (operand_type->id == ZigTypeIdVector) {
2594 ok_bit = scalarize_cmp_result(g, ok_bit);
2595 }
25842596 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
25852597
25862598 LLVMPositionBuilderAtEnd(g->builder, fail_block);
......@@ -2897,11 +2909,17 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type
28972909 // otherwise the check is useful as the allowed values are limited by the
28982910 // operand type itself
28992911 if (!is_power_of_2(lhs_type->data.integral.bit_count)) {
2900 LLVMValueRef bit_count_value = LLVMConstInt(get_llvm_type(g, rhs_type),
2901 lhs_type->data.integral.bit_count, false);
2902 LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, "");
2912 BigInt bit_count_bi = {0};
2913 bigint_init_unsigned(&bit_count_bi, lhs_type->data.integral.bit_count);
2914 LLVMValueRef bit_count_value = bigint_to_llvm_const(get_llvm_type(g, rhs_type),
2915 &bit_count_bi);
2916
29032917 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail");
29042918 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk");
2919 LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, "");
2920 if (rhs_type->id == ZigTypeIdVector) {
2921 less_than_bit = scalarize_cmp_result(g, less_than_bit);
2922 }
29052923 LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block);
29062924
29072925 LLVMPositionBuilderAtEnd(g->builder, fail_block);
......@@ -3018,7 +3036,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
30183036 case IrBinOpBitShiftLeftExact:
30193037 {
30203038 assert(scalar_type->id == ZigTypeIdInt);
3021 LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value->type, scalar_type, op2_value);
3039 LLVMValueRef op2_casted = LLVMBuildZExt(g->builder, op2_value,
3040 LLVMTypeOf(op1_value), "");//gen_widen_or_shorten(g, false, op2->value->type, scalar_type, op2_value);
30223041
30233042 if (want_runtime_safety) {
30243043 gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value);
......@@ -3028,7 +3047,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
30283047 if (is_sloppy) {
30293048 return LLVMBuildShl(g->builder, op1_value, op2_casted, "");
30303049 } else if (want_runtime_safety) {
3031 return gen_overflow_shl_op(g, scalar_type, op1_value, op2_casted);
3050 return gen_overflow_shl_op(g, operand_type, op1_value, op2_casted);
30323051 } else if (scalar_type->data.integral.is_signed) {
30333052 return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, "");
30343053 } else {
......@@ -3039,7 +3058,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
30393058 case IrBinOpBitShiftRightExact:
30403059 {
30413060 assert(scalar_type->id == ZigTypeIdInt);
3042 LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value->type, scalar_type, op2_value);
3061 LLVMValueRef op2_casted = LLVMBuildZExt(g->builder, op2_value,
3062 LLVMTypeOf(op1_value), "");//gen_widen_or_shorten(g, false, op2->value->type, scalar_type, op2_value);
30433063
30443064 if (want_runtime_safety) {
30453065 gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value);
......@@ -3053,7 +3073,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
30533073 return LLVMBuildLShr(g->builder, op1_value, op2_casted, "");
30543074 }
30553075 } else if (want_runtime_safety) {
3056 return gen_overflow_shr_op(g, scalar_type, op1_value, op2_casted);
3076 return gen_overflow_shr_op(g, operand_type, op1_value, op2_casted);
30573077 } else if (scalar_type->data.integral.is_signed) {
30583078 return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, "");
30593079 } else {
src/ir.cpp+82-32
......@@ -283,6 +283,8 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi
283283 IrInstGen *result_loc);
284284static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr,
285285 IrInstGen *struct_operand, TypeStructField *field);
286static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right);
287static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right);
286288
287289static void destroy_instruction_src(IrInstSrc *inst) {
288290 switch (inst->id) {
......@@ -16803,7 +16805,6 @@ static IrInstGen *ir_analyze_math_op(IrAnalyze *ira, IrInst* source_instr,
1680316805 ZigValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i];
1680416806 ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
1680516807 assert(scalar_op1_val->type == scalar_type);
16806 assert(scalar_op2_val->type == scalar_type);
1680716808 assert(scalar_out_val->type == scalar_type);
1680816809 ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type,
1680916810 scalar_op1_val, op_id, scalar_op2_val, scalar_out_val);
......@@ -16828,27 +16829,49 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
1682816829 if (type_is_invalid(op1->value->type))
1682916830 return ira->codegen->invalid_inst_gen;
1683016831
16831 if (op1->value->type->id != ZigTypeIdInt && op1->value->type->id != ZigTypeIdComptimeInt) {
16832 IrInstGen *op2 = bin_op_instruction->op2->child;
16833 if (type_is_invalid(op2->value->type))
16834 return ira->codegen->invalid_inst_gen;
16835
16836 ZigType *op1_type = op1->value->type;
16837 ZigType *op2_type = op2->value->type;
16838
16839 if (op1_type->id == ZigTypeIdVector && op2_type->id != ZigTypeIdVector) {
1683216840 ir_add_error(ira, &bin_op_instruction->op1->base,
16833 buf_sprintf("bit shifting operation expected integer type, found '%s'",
16834 buf_ptr(&op1->value->type->name)));
16841 buf_sprintf("bit shifting operation expected vector type, found '%s'",
16842 buf_ptr(&op2_type->name)));
1683516843 return ira->codegen->invalid_inst_gen;
1683616844 }
1683716845
16838 IrInstGen *op2 = bin_op_instruction->op2->child;
16839 if (type_is_invalid(op2->value->type))
16846 if (op1_type->id != ZigTypeIdVector && op2_type->id == ZigTypeIdVector) {
16847 ir_add_error(ira, &bin_op_instruction->op1->base,
16848 buf_sprintf("bit shifting operation expected vector type, found '%s'",
16849 buf_ptr(&op1_type->name)));
1684016850 return ira->codegen->invalid_inst_gen;
16851 }
16852
16853 ZigType *op1_scalar_type = (op1_type->id == ZigTypeIdVector) ?
16854 op1_type->data.vector.elem_type : op1_type;
16855 ZigType *op2_scalar_type = (op2_type->id == ZigTypeIdVector) ?
16856 op2_type->data.vector.elem_type : op2_type;
16857
16858 if (op1_scalar_type->id != ZigTypeIdInt && op1_scalar_type->id != ZigTypeIdComptimeInt) {
16859 ir_add_error(ira, &bin_op_instruction->op1->base,
16860 buf_sprintf("bit shifting operation expected integer type, found '%s'",
16861 buf_ptr(&op1_scalar_type->name)));
16862 return ira->codegen->invalid_inst_gen;
16863 }
1684116864
16842 if (op2->value->type->id != ZigTypeIdInt && op2->value->type->id != ZigTypeIdComptimeInt) {
16865 if (op2_scalar_type->id != ZigTypeIdInt && op2_scalar_type->id != ZigTypeIdComptimeInt) {
1684316866 ir_add_error(ira, &bin_op_instruction->op2->base,
1684416867 buf_sprintf("shift amount has to be an integer type, but found '%s'",
16845 buf_ptr(&op2->value->type->name)));
16868 buf_ptr(&op2_scalar_type->name)));
1684616869 return ira->codegen->invalid_inst_gen;
1684716870 }
1684816871
1684916872 IrInstGen *casted_op2;
1685016873 IrBinOp op_id = bin_op_instruction->op_id;
16851 if (op1->value->type->id == ZigTypeIdComptimeInt) {
16874 if (op1_scalar_type->id == ZigTypeIdComptimeInt) {
1685216875 // comptime_int has no finite bit width
1685316876 casted_op2 = op2;
1685416877
......@@ -16874,10 +16897,15 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
1687416897 return ira->codegen->invalid_inst_gen;
1687516898 }
1687616899 } else {
16877 const unsigned bit_count = op1->value->type->data.integral.bit_count;
16900 const unsigned bit_count = op1_scalar_type->data.integral.bit_count;
1687816901 ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
1687916902 bit_count > 0 ? bit_count - 1 : 0);
1688016903
16904 if (op1_type->id == ZigTypeIdVector) {
16905 shift_amt_type = get_vector_type(ira->codegen, op1_type->data.vector.len,
16906 shift_amt_type);
16907 }
16908
1688116909 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
1688216910 if (type_is_invalid(casted_op2->value->type))
1688316911 return ira->codegen->invalid_inst_gen;
......@@ -16888,10 +16916,10 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
1688816916 if (op2_val == nullptr)
1688916917 return ira->codegen->invalid_inst_gen;
1689016918
16891 BigInt bit_count_value = {0};
16892 bigint_init_unsigned(&bit_count_value, bit_count);
16919 ZigValue bit_count_value;
16920 init_const_usize(ira->codegen, &bit_count_value, bit_count);
1689316921
16894 if (bigint_cmp(&op2_val->data.x_bigint, &bit_count_value) != CmpLT) {
16922 if (!value_cmp_numeric_val_all(op2_val, CmpLT, &bit_count_value)) {
1689516923 ErrorMsg* msg = ir_add_error(ira,
1689616924 &bin_op_instruction->base.base,
1689716925 buf_sprintf("RHS of shift is too large for LHS type"));
......@@ -16910,7 +16938,7 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
1691016938 if (op2_val == nullptr)
1691116939 return ira->codegen->invalid_inst_gen;
1691216940
16913 if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ)
16941 if (value_cmp_numeric_val_all(op2_val, CmpEQ, nullptr))
1691416942 return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1);
1691516943 }
1691616944
......@@ -16923,7 +16951,7 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
1692316951 if (op2_val == nullptr)
1692416952 return ira->codegen->invalid_inst_gen;
1692516953
16926 return ir_analyze_math_op(ira, &bin_op_instruction->base.base, op1->value->type, op1_val, op_id, op2_val);
16954 return ir_analyze_math_op(ira, &bin_op_instruction->base.base, op1_type, op1_val, op_id, op2_val);
1692716955 }
1692816956
1692916957 return ir_build_bin_op_gen(ira, &bin_op_instruction->base.base, op1->value->type,
......@@ -16991,31 +17019,53 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
1699117019 zig_unreachable();
1699217020}
1699317021
16994static bool value_cmp_zero_any(ZigValue *value, Cmp predicate) {
16995 assert(value->special == ConstValSpecialStatic);
17022static bool value_cmp_numeric_val(ZigValue *left, Cmp predicate, ZigValue *right, bool any) {
17023 assert(left->special == ConstValSpecialStatic);
17024 assert(right == nullptr || right->special == ConstValSpecialStatic);
1699617025
16997 switch (value->type->id) {
17026 switch (left->type->id) {
1699817027 case ZigTypeIdComptimeInt:
16999 case ZigTypeIdInt:
17000 return bigint_cmp_zero(&value->data.x_bigint) == predicate;
17028 case ZigTypeIdInt: {
17029 const Cmp result = right ?
17030 bigint_cmp(&left->data.x_bigint, &right->data.x_bigint) :
17031 bigint_cmp_zero(&left->data.x_bigint);
17032 return result == predicate;
17033 }
1700117034 case ZigTypeIdComptimeFloat:
17002 case ZigTypeIdFloat:
17003 if (float_is_nan(value))
17035 case ZigTypeIdFloat: {
17036 if (float_is_nan(left))
1700417037 return false;
17005 return float_cmp_zero(value) == predicate;
17038 if (right != nullptr && float_is_nan(right))
17039 return false;
17040
17041 const Cmp result = right ? float_cmp(left, right) : float_cmp_zero(left);
17042 return result == predicate;
17043 }
1700617044 case ZigTypeIdVector: {
17007 for (size_t i = 0; i < value->type->data.vector.len; i++) {
17008 ZigValue *scalar_val = &value->data.x_array.data.s_none.elements[i];
17009 if (!value_cmp_zero_any(scalar_val, predicate))
17010 return true;
17045 for (size_t i = 0; i < left->type->data.vector.len; i++) {
17046 ZigValue *scalar_val = &left->data.x_array.data.s_none.elements[i];
17047 const bool result = value_cmp_numeric_val(scalar_val, predicate, right, any);
17048
17049 if (any && result)
17050 return true; // This element satisfies the predicate
17051 else if (!any && !result)
17052 return false; // This element doesn't satisfy the predicate
1701117053 }
17012 return false;
17054 return any ? false : true;
1701317055 }
1701417056 default:
1701517057 zig_unreachable();
1701617058 }
1701717059}
1701817060
17061static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right) {
17062 return value_cmp_numeric_val(left, predicate, right, true);
17063}
17064
17065static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right) {
17066 return value_cmp_numeric_val(left, predicate, right, false);
17067}
17068
1701917069static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruction) {
1702017070 Error err;
1702117071
......@@ -17165,8 +17215,8 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc
1716517215 return ira->codegen->invalid_inst_gen;
1716617216
1716717217 // Promote division with negative numbers to signed
17168 bool is_signed_div = value_cmp_zero_any(op1_val, CmpLT) ||
17169 value_cmp_zero_any(op2_val, CmpLT);
17218 bool is_signed_div = value_cmp_numeric_val_any(op1_val, CmpLT, nullptr) ||
17219 value_cmp_numeric_val_any(op2_val, CmpLT, nullptr);
1717017220
1717117221 if (op_id == IrBinOpDivUnspecified && is_int) {
1717217222 // Default to truncating division and check if it's valid for the
......@@ -17176,7 +17226,7 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc
1717617226 if (is_signed_div) {
1717717227 bool ok = false;
1717817228
17179 if (value_cmp_zero_any(op2_val, CmpEQ)) {
17229 if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) {
1718017230 // the division by zero error will be caught later, but we don't have a
1718117231 // division function ambiguity problem.
1718217232 ok = true;
......@@ -17215,7 +17265,7 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc
1721517265 if (is_signed_div) {
1721617266 bool ok = false;
1721717267
17218 if (value_cmp_zero_any(op2_val, CmpEQ)) {
17268 if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) {
1721917269 // the division by zero error will be caught later, but we don't have a
1722017270 // division function ambiguity problem.
1722117271 ok = true;
test/stage1/behavior/vector.zig+65
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const mem = std.mem;
3const math = std.math;
34const expect = std.testing.expect;
45const expectEqual = std.testing.expectEqual;
56
......@@ -376,3 +377,67 @@ test "vector bitwise not operator" {
376377 S.doTheTest();
377378 comptime S.doTheTest();
378379}
380
381test "vector shift operators" {
382 const S = struct {
383 fn doTheTestShift(x: var, y: var) void {
384 const N = @typeInfo(@TypeOf(x)).Array.len;
385 const TX = @typeInfo(@TypeOf(x)).Array.child;
386 const TY = @typeInfo(@TypeOf(y)).Array.child;
387
388 var xv = @as(@Vector(N, TX), x);
389 var yv = @as(@Vector(N, TY), y);
390
391 var z0 = xv >> yv;
392 for (@as([N]TX, z0)) |v, i| {
393 expectEqual(x[i] >> y[i], v);
394 }
395 var z1 = xv << yv;
396 for (@as([N]TX, z1)) |v, i| {
397 expectEqual(x[i] << y[i], v);
398 }
399 }
400 fn doTheTestShiftExact(x: var, y: var, dir: enum { Left, Right }) void {
401 const N = @typeInfo(@TypeOf(x)).Array.len;
402 const TX = @typeInfo(@TypeOf(x)).Array.child;
403 const TY = @typeInfo(@TypeOf(y)).Array.child;
404
405 var xv = @as(@Vector(N, TX), x);
406 var yv = @as(@Vector(N, TY), y);
407
408 var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv);
409 for (@as([N]TX, z)) |v, i| {
410 const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i];
411 expectEqual(check, v);
412 }
413 }
414 fn doTheTest() void {
415 doTheTestShift([_]u8{ 0, 2, 4, math.maxInt(u8) }, [_]u3{ 2, 0, 2, 7 });
416 doTheTestShift([_]u16{ 0, 2, 4, math.maxInt(u16) }, [_]u4{ 2, 0, 2, 15 });
417 doTheTestShift([_]u24{ 0, 2, 4, math.maxInt(u24) }, [_]u5{ 2, 0, 2, 23 });
418 doTheTestShift([_]u32{ 0, 2, 4, math.maxInt(u32) }, [_]u5{ 2, 0, 2, 31 });
419 doTheTestShift([_]u64{ 0xfe, math.maxInt(u64) }, [_]u6{ 0, 63 });
420
421 doTheTestShift([_]i8{ 0, 2, 4, math.maxInt(i8) }, [_]u3{ 2, 0, 2, 7 });
422 doTheTestShift([_]i16{ 0, 2, 4, math.maxInt(i16) }, [_]u4{ 2, 0, 2, 7 });
423 doTheTestShift([_]i24{ 0, 2, 4, math.maxInt(i24) }, [_]u5{ 2, 0, 2, 7 });
424 doTheTestShift([_]i32{ 0, 2, 4, math.maxInt(i32) }, [_]u5{ 2, 0, 2, 7 });
425 doTheTestShift([_]i64{ 0xfe, math.maxInt(i64) }, [_]u6{ 0, 63 });
426
427 doTheTestShiftExact([_]u8{ 0, 1, 1 << 7, math.maxInt(u8) ^ 1 }, [_]u3{ 4, 0, 7, 1 }, .Right);
428 doTheTestShiftExact([_]u16{ 0, 1, 1 << 15, math.maxInt(u16) ^ 1 }, [_]u4{ 4, 0, 15, 1 }, .Right);
429 doTheTestShiftExact([_]u24{ 0, 1, 1 << 23, math.maxInt(u24) ^ 1 }, [_]u5{ 4, 0, 23, 1 }, .Right);
430 doTheTestShiftExact([_]u32{ 0, 1, 1 << 31, math.maxInt(u32) ^ 1 }, [_]u5{ 4, 0, 31, 1 }, .Right);
431 doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 63, 0 }, .Right);
432
433 doTheTestShiftExact([_]u8{ 0, 1, 1, math.maxInt(u8) ^ (1 << 7) }, [_]u3{ 4, 0, 7, 1 }, .Left);
434 doTheTestShiftExact([_]u16{ 0, 1, 1, math.maxInt(u16) ^ (1 << 15) }, [_]u4{ 4, 0, 15, 1 }, .Left);
435 doTheTestShiftExact([_]u24{ 0, 1, 1, math.maxInt(u24) ^ (1 << 23) }, [_]u5{ 4, 0, 23, 1 }, .Left);
436 doTheTestShiftExact([_]u32{ 0, 1, 1, math.maxInt(u32) ^ (1 << 31) }, [_]u5{ 4, 0, 31, 1 }, .Left);
437 doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 0, 63 }, .Left);
438 }
439 };
440
441 S.doTheTest();
442 comptime S.doTheTest();
443}