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,...@@ -155,6 +155,7 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstGen *source_instr,
155 LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type,155 LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type,
156 LLVMValueRef result_loc, bool non_async);156 LLVMValueRef result_loc, bool non_async);
157static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix);157static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix);
158static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val);
158159
159static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {160static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {
160 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));161 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
...@@ -2535,19 +2536,21 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir...@@ -2535,19 +2536,21 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir
2535 return nullptr;2536 return nullptr;
2536}2537}
25372538
2538static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,2539static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type,
2539 LLVMValueRef val1, LLVMValueRef val2)2540 LLVMValueRef val1, LLVMValueRef val2)
2540{2541{
2541 // for unsigned left shifting, we do the lossy shift, then logically shift2542 // for unsigned left shifting, we do the lossy shift, then logically shift
2542 // right the same number of bits2543 // right the same number of bits
2543 // if the values don't match, we have an overflow2544 // if the values don't match, we have an overflow
2544 // for signed left shifting we do the same except arithmetic shift right2545 // 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
2548 LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");2551 LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
2549 LLVMValueRef orig_val;2552 LLVMValueRef orig_val;
2550 if (type_entry->data.integral.is_signed) {2553 if (scalar_type->data.integral.is_signed) {
2551 orig_val = LLVMBuildAShr(g->builder, result, val2, "");2554 orig_val = LLVMBuildAShr(g->builder, result, val2, "");
2552 } else {2555 } else {
2553 orig_val = LLVMBuildLShr(g->builder, result, val2, "");2556 orig_val = LLVMBuildLShr(g->builder, result, val2, "");
...@@ -2556,6 +2559,9 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,...@@ -2556,6 +2559,9 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,
25562559
2557 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");2560 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
2558 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");2561 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 }
2559 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);2565 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
25602566
2561 LLVMPositionBuilderAtEnd(g->builder, fail_block);2567 LLVMPositionBuilderAtEnd(g->builder, fail_block);
...@@ -2565,13 +2571,16 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,...@@ -2565,13 +2571,16 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,
2565 return result;2571 return result;
2566}2572}
25672573
2568static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,2574static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type,
2569 LLVMValueRef val1, LLVMValueRef val2)2575 LLVMValueRef val1, LLVMValueRef val2)
2570{2576{
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
2573 LLVMValueRef result;2582 LLVMValueRef result;
2574 if (type_entry->data.integral.is_signed) {2583 if (scalar_type->data.integral.is_signed) {
2575 result = LLVMBuildAShr(g->builder, val1, val2, "");2584 result = LLVMBuildAShr(g->builder, val1, val2, "");
2576 } else {2585 } else {
2577 result = LLVMBuildLShr(g->builder, val1, val2, "");2586 result = LLVMBuildLShr(g->builder, val1, val2, "");
...@@ -2581,6 +2590,9 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,...@@ -2581,6 +2590,9 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,
25812590
2582 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");2591 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
2583 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");2592 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 }
2584 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);2596 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
25852597
2586 LLVMPositionBuilderAtEnd(g->builder, fail_block);2598 LLVMPositionBuilderAtEnd(g->builder, fail_block);
...@@ -2897,11 +2909,17 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type...@@ -2897,11 +2909,17 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type
2897 // otherwise the check is useful as the allowed values are limited by the2909 // otherwise the check is useful as the allowed values are limited by the
2898 // operand type itself2910 // operand type itself
2899 if (!is_power_of_2(lhs_type->data.integral.bit_count)) {2911 if (!is_power_of_2(lhs_type->data.integral.bit_count)) {
2900 LLVMValueRef bit_count_value = LLVMConstInt(get_llvm_type(g, rhs_type),2912 BigInt bit_count_bi = {0};
2901 lhs_type->data.integral.bit_count, false);2913 bigint_init_unsigned(&bit_count_bi, lhs_type->data.integral.bit_count);
2902 LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, "");2914 LLVMValueRef bit_count_value = bigint_to_llvm_const(get_llvm_type(g, rhs_type),
2915 &bit_count_bi);
2916
2903 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail");2917 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail");
2904 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk");2918 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 }
2905 LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block);2923 LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block);
29062924
2907 LLVMPositionBuilderAtEnd(g->builder, fail_block);2925 LLVMPositionBuilderAtEnd(g->builder, fail_block);
...@@ -3018,7 +3036,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,...@@ -3018,7 +3036,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
3018 case IrBinOpBitShiftLeftExact:3036 case IrBinOpBitShiftLeftExact:
3019 {3037 {
3020 assert(scalar_type->id == ZigTypeIdInt);3038 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
3023 if (want_runtime_safety) {3042 if (want_runtime_safety) {
3024 gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value);3043 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,...@@ -3028,7 +3047,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
3028 if (is_sloppy) {3047 if (is_sloppy) {
3029 return LLVMBuildShl(g->builder, op1_value, op2_casted, "");3048 return LLVMBuildShl(g->builder, op1_value, op2_casted, "");
3030 } else if (want_runtime_safety) {3049 } 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);
3032 } else if (scalar_type->data.integral.is_signed) {3051 } else if (scalar_type->data.integral.is_signed) {
3033 return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, "");3052 return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, "");
3034 } else {3053 } else {
...@@ -3039,7 +3058,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,...@@ -3039,7 +3058,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
3039 case IrBinOpBitShiftRightExact:3058 case IrBinOpBitShiftRightExact:
3040 {3059 {
3041 assert(scalar_type->id == ZigTypeIdInt);3060 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
3044 if (want_runtime_safety) {3064 if (want_runtime_safety) {
3045 gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value);3065 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,...@@ -3053,7 +3073,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
3053 return LLVMBuildLShr(g->builder, op1_value, op2_casted, "");3073 return LLVMBuildLShr(g->builder, op1_value, op2_casted, "");
3054 }3074 }
3055 } else if (want_runtime_safety) {3075 } 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);
3057 } else if (scalar_type->data.integral.is_signed) {3077 } else if (scalar_type->data.integral.is_signed) {
3058 return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, "");3078 return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, "");
3059 } else {3079 } else {
src/ir.cpp+82-32
...@@ -283,6 +283,8 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi...@@ -283,6 +283,8 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi
283 IrInstGen *result_loc);283 IrInstGen *result_loc);
284static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr,284static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr,
285 IrInstGen *struct_operand, TypeStructField *field);285 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
287static void destroy_instruction_src(IrInstSrc *inst) {289static void destroy_instruction_src(IrInstSrc *inst) {
288 switch (inst->id) {290 switch (inst->id) {
...@@ -16803,7 +16805,6 @@ static IrInstGen *ir_analyze_math_op(IrAnalyze *ira, IrInst* source_instr,...@@ -16803,7 +16805,6 @@ static IrInstGen *ir_analyze_math_op(IrAnalyze *ira, IrInst* source_instr,
16803 ZigValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i];16805 ZigValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i];
16804 ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];16806 ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
16805 assert(scalar_op1_val->type == scalar_type);16807 assert(scalar_op1_val->type == scalar_type);
16806 assert(scalar_op2_val->type == scalar_type);
16807 assert(scalar_out_val->type == scalar_type);16808 assert(scalar_out_val->type == scalar_type);
16808 ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type,16809 ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type,
16809 scalar_op1_val, op_id, scalar_op2_val, scalar_out_val);16810 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...@@ -16828,27 +16829,49 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
16828 if (type_is_invalid(op1->value->type))16829 if (type_is_invalid(op1->value->type))
16829 return ira->codegen->invalid_inst_gen;16830 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) {
16832 ir_add_error(ira, &bin_op_instruction->op1->base,16840 ir_add_error(ira, &bin_op_instruction->op1->base,
16833 buf_sprintf("bit shifting operation expected integer type, found '%s'",16841 buf_sprintf("bit shifting operation expected vector type, found '%s'",
16834 buf_ptr(&op1->value->type->name)));16842 buf_ptr(&op2_type->name)));
16835 return ira->codegen->invalid_inst_gen;16843 return ira->codegen->invalid_inst_gen;
16836 }16844 }
1683716845
16838 IrInstGen *op2 = bin_op_instruction->op2->child;16846 if (op1_type->id != ZigTypeIdVector && op2_type->id == ZigTypeIdVector) {
16839 if (type_is_invalid(op2->value->type))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)));
16840 return ira->codegen->invalid_inst_gen;16850 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) {
16843 ir_add_error(ira, &bin_op_instruction->op2->base,16866 ir_add_error(ira, &bin_op_instruction->op2->base,
16844 buf_sprintf("shift amount has to be an integer type, but found '%s'",16867 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)));
16846 return ira->codegen->invalid_inst_gen;16869 return ira->codegen->invalid_inst_gen;
16847 }16870 }
1684816871
16849 IrInstGen *casted_op2;16872 IrInstGen *casted_op2;
16850 IrBinOp op_id = bin_op_instruction->op_id;16873 IrBinOp op_id = bin_op_instruction->op_id;
16851 if (op1->value->type->id == ZigTypeIdComptimeInt) {16874 if (op1_scalar_type->id == ZigTypeIdComptimeInt) {
16852 // comptime_int has no finite bit width16875 // comptime_int has no finite bit width
16853 casted_op2 = op2;16876 casted_op2 = op2;
1685416877
...@@ -16874,10 +16897,15 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in...@@ -16874,10 +16897,15 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
16874 return ira->codegen->invalid_inst_gen;16897 return ira->codegen->invalid_inst_gen;
16875 }16898 }
16876 } else {16899 } 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;
16878 ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,16901 ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
16879 bit_count > 0 ? bit_count - 1 : 0);16902 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
16881 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);16909 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
16882 if (type_is_invalid(casted_op2->value->type))16910 if (type_is_invalid(casted_op2->value->type))
16883 return ira->codegen->invalid_inst_gen;16911 return ira->codegen->invalid_inst_gen;
...@@ -16888,10 +16916,10 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in...@@ -16888,10 +16916,10 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
16888 if (op2_val == nullptr)16916 if (op2_val == nullptr)
16889 return ira->codegen->invalid_inst_gen;16917 return ira->codegen->invalid_inst_gen;
1689016918
16891 BigInt bit_count_value = {0};16919 ZigValue bit_count_value;
16892 bigint_init_unsigned(&bit_count_value, bit_count);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)) {
16895 ErrorMsg* msg = ir_add_error(ira,16923 ErrorMsg* msg = ir_add_error(ira,
16896 &bin_op_instruction->base.base,16924 &bin_op_instruction->base.base,
16897 buf_sprintf("RHS of shift is too large for LHS type"));16925 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...@@ -16910,7 +16938,7 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
16910 if (op2_val == nullptr)16938 if (op2_val == nullptr)
16911 return ira->codegen->invalid_inst_gen;16939 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))
16914 return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1);16942 return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1);
16915 }16943 }
1691616944
...@@ -16923,7 +16951,7 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in...@@ -16923,7 +16951,7 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
16923 if (op2_val == nullptr)16951 if (op2_val == nullptr)
16924 return ira->codegen->invalid_inst_gen;16952 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);
16927 }16955 }
1692816956
16929 return ir_build_bin_op_gen(ira, &bin_op_instruction->base.base, op1->value->type,16957 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) {...@@ -16991,31 +17019,53 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
16991 zig_unreachable();17019 zig_unreachable();
16992}17020}
1699317021
16994static bool value_cmp_zero_any(ZigValue *value, Cmp predicate) {17022static bool value_cmp_numeric_val(ZigValue *left, Cmp predicate, ZigValue *right, bool any) {
16995 assert(value->special == ConstValSpecialStatic);17023 assert(left->special == ConstValSpecialStatic);
17024 assert(right == nullptr || right->special == ConstValSpecialStatic);
1699617025
16997 switch (value->type->id) {17026 switch (left->type->id) {
16998 case ZigTypeIdComptimeInt:17027 case ZigTypeIdComptimeInt:
16999 case ZigTypeIdInt:17028 case ZigTypeIdInt: {
17000 return bigint_cmp_zero(&value->data.x_bigint) == predicate;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 }
17001 case ZigTypeIdComptimeFloat:17034 case ZigTypeIdComptimeFloat:
17002 case ZigTypeIdFloat:17035 case ZigTypeIdFloat: {
17003 if (float_is_nan(value))17036 if (float_is_nan(left))
17004 return false;17037 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 }
17006 case ZigTypeIdVector: {17044 case ZigTypeIdVector: {
17007 for (size_t i = 0; i < value->type->data.vector.len; i++) {17045 for (size_t i = 0; i < left->type->data.vector.len; i++) {
17008 ZigValue *scalar_val = &value->data.x_array.data.s_none.elements[i];17046 ZigValue *scalar_val = &left->data.x_array.data.s_none.elements[i];
17009 if (!value_cmp_zero_any(scalar_val, predicate))17047 const bool result = value_cmp_numeric_val(scalar_val, predicate, right, any);
17010 return true;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
17011 }17053 }
17012 return false;17054 return any ? false : true;
17013 }17055 }
17014 default:17056 default:
17015 zig_unreachable();17057 zig_unreachable();
17016 }17058 }
17017}17059}
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
17019static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruction) {17069static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruction) {
17020 Error err;17070 Error err;
1702117071
...@@ -17165,8 +17215,8 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc...@@ -17165,8 +17215,8 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc
17165 return ira->codegen->invalid_inst_gen;17215 return ira->codegen->invalid_inst_gen;
1716617216
17167 // Promote division with negative numbers to signed17217 // Promote division with negative numbers to signed
17168 bool is_signed_div = value_cmp_zero_any(op1_val, CmpLT) ||17218 bool is_signed_div = value_cmp_numeric_val_any(op1_val, CmpLT, nullptr) ||
17169 value_cmp_zero_any(op2_val, CmpLT);17219 value_cmp_numeric_val_any(op2_val, CmpLT, nullptr);
1717017220
17171 if (op_id == IrBinOpDivUnspecified && is_int) {17221 if (op_id == IrBinOpDivUnspecified && is_int) {
17172 // Default to truncating division and check if it's valid for the17222 // 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...@@ -17176,7 +17226,7 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc
17176 if (is_signed_div) {17226 if (is_signed_div) {
17177 bool ok = false;17227 bool ok = false;
1717817228
17179 if (value_cmp_zero_any(op2_val, CmpEQ)) {17229 if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) {
17180 // the division by zero error will be caught later, but we don't have a17230 // the division by zero error will be caught later, but we don't have a
17181 // division function ambiguity problem.17231 // division function ambiguity problem.
17182 ok = true;17232 ok = true;
...@@ -17215,7 +17265,7 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc...@@ -17215,7 +17265,7 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc
17215 if (is_signed_div) {17265 if (is_signed_div) {
17216 bool ok = false;17266 bool ok = false;
1721717267
17218 if (value_cmp_zero_any(op2_val, CmpEQ)) {17268 if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) {
17219 // the division by zero error will be caught later, but we don't have a17269 // the division by zero error will be caught later, but we don't have a
17220 // division function ambiguity problem.17270 // division function ambiguity problem.
17221 ok = true;17271 ok = true;
test/stage1/behavior/vector.zig+65
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const math = std.math;
3const expect = std.testing.expect;4const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
56
...@@ -376,3 +377,67 @@ test "vector bitwise not operator" {...@@ -376,3 +377,67 @@ test "vector bitwise not operator" {
376 S.doTheTest();377 S.doTheTest();
377 comptime S.doTheTest();378 comptime S.doTheTest();
378}379}
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}