| author | |
| committer | |
| log | d2d97e55ccd2d7c992d01bd05ea52a52fe36776e |
| tree | 98da26db32bc99194799c677cc46fbc72704fd1c |
| parent | 2485f3004659723a1ccd2799a6e0bddb09e32d3b |
| signature | Commit is signed but in an unrecognized format. |
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 | 155 | LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type, |
| 156 | 156 | LLVMValueRef result_loc, bool non_async); |
| 157 | 157 | static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix); |
| 158 | static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val); | |
| 158 | 159 | |
| 159 | 160 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { |
| 160 | 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 | 2536 | return nullptr; |
| 2536 | 2537 | } |
| 2537 | 2538 | |
| 2538 | static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry, | |
| 2539 | LLVMValueRef val1, LLVMValueRef val2) | |
| 2539 | static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, | |
| 2540 | LLVMValueRef val1, LLVMValueRef val2) | |
| 2540 | 2541 | { |
| 2541 | 2542 | // for unsigned left shifting, we do the lossy shift, then logically shift |
| 2542 | 2543 | // right the same number of bits |
| 2543 | 2544 | // if the values don't match, we have an overflow |
| 2544 | 2545 | // 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; | |
| 2545 | 2548 | |
| 2546 | assert(type_entry->id == ZigTypeIdInt); | |
| 2549 | assert(scalar_type->id == ZigTypeIdInt); | |
| 2547 | 2550 | |
| 2548 | 2551 | LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); |
| 2549 | 2552 | LLVMValueRef orig_val; |
| 2550 | if (type_entry->data.integral.is_signed) { | |
| 2553 | if (scalar_type->data.integral.is_signed) { | |
| 2551 | 2554 | orig_val = LLVMBuildAShr(g->builder, result, val2, ""); |
| 2552 | 2555 | } else { |
| 2553 | 2556 | orig_val = LLVMBuildLShr(g->builder, result, val2, ""); |
| ... | ... | @@ -2556,6 +2559,9 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry, |
| 2556 | 2559 | |
| 2557 | 2560 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 2558 | 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 | 2565 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2560 | 2566 | |
| 2561 | 2567 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| ... | ... | @@ -2565,13 +2571,16 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry, |
| 2565 | 2571 | return result; |
| 2566 | 2572 | } |
| 2567 | 2573 | |
| 2568 | static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, | |
| 2569 | LLVMValueRef val1, LLVMValueRef val2) | |
| 2574 | static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type, | |
| 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); | |
| 2572 | 2581 | |
| 2573 | 2582 | LLVMValueRef result; |
| 2574 | if (type_entry->data.integral.is_signed) { | |
| 2583 | if (scalar_type->data.integral.is_signed) { | |
| 2575 | 2584 | result = LLVMBuildAShr(g->builder, val1, val2, ""); |
| 2576 | 2585 | } else { |
| 2577 | 2586 | result = LLVMBuildLShr(g->builder, val1, val2, ""); |
| ... | ... | @@ -2581,6 +2590,9 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, |
| 2581 | 2590 | |
| 2582 | 2591 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 2583 | 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 | 2596 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2585 | 2597 | |
| 2586 | 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 | 2909 | // otherwise the check is useful as the allowed values are limited by the |
| 2898 | 2910 | // operand type itself |
| 2899 | 2911 | 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 | ||
| 2903 | 2917 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail"); |
| 2904 | 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 | 2923 | LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block); |
| 2906 | 2924 | |
| 2907 | 2925 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| ... | ... | @@ -3018,7 +3036,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable, |
| 3018 | 3036 | case IrBinOpBitShiftLeftExact: |
| 3019 | 3037 | { |
| 3020 | 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); | |
| 3022 | 3041 | |
| 3023 | 3042 | if (want_runtime_safety) { |
| 3024 | 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 | 3047 | if (is_sloppy) { |
| 3029 | 3048 | return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); |
| 3030 | 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 | 3051 | } else if (scalar_type->data.integral.is_signed) { |
| 3033 | 3052 | return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); |
| 3034 | 3053 | } else { |
| ... | ... | @@ -3039,7 +3058,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable, |
| 3039 | 3058 | case IrBinOpBitShiftRightExact: |
| 3040 | 3059 | { |
| 3041 | 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); | |
| 3043 | 3063 | |
| 3044 | 3064 | if (want_runtime_safety) { |
| 3045 | 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 | 3073 | return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); |
| 3054 | 3074 | } |
| 3055 | 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 | 3077 | } else if (scalar_type->data.integral.is_signed) { |
| 3058 | 3078 | return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); |
| 3059 | 3079 | } else { |
src/ir.cpp+82-32| ... | ... | @@ -283,6 +283,8 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi |
| 283 | 283 | IrInstGen *result_loc); |
| 284 | 284 | static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr, |
| 285 | 285 | IrInstGen *struct_operand, TypeStructField *field); |
| 286 | static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right); | |
| 287 | static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right); | |
| 286 | 288 | |
| 287 | 289 | static void destroy_instruction_src(IrInstSrc *inst) { |
| 288 | 290 | switch (inst->id) { |
| ... | ... | @@ -16803,7 +16805,6 @@ static IrInstGen *ir_analyze_math_op(IrAnalyze *ira, IrInst* source_instr, |
| 16803 | 16805 | ZigValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i]; |
| 16804 | 16806 | ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; |
| 16805 | 16807 | assert(scalar_op1_val->type == scalar_type); |
| 16806 | assert(scalar_op2_val->type == scalar_type); | |
| 16807 | 16808 | assert(scalar_out_val->type == scalar_type); |
| 16808 | 16809 | ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type, |
| 16809 | 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 | 16829 | if (type_is_invalid(op1->value->type)) |
| 16829 | 16830 | return ira->codegen->invalid_inst_gen; |
| 16830 | 16831 | |
| 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 | 16840 | 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))); | |
| 16835 | 16843 | return ira->codegen->invalid_inst_gen; |
| 16836 | 16844 | } |
| 16837 | 16845 | |
| 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))); | |
| 16840 | 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 | } | |
| 16841 | 16864 | |
| 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 | 16866 | ir_add_error(ira, &bin_op_instruction->op2->base, |
| 16844 | 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 | 16869 | return ira->codegen->invalid_inst_gen; |
| 16847 | 16870 | } |
| 16848 | 16871 | |
| 16849 | 16872 | IrInstGen *casted_op2; |
| 16850 | 16873 | IrBinOp op_id = bin_op_instruction->op_id; |
| 16851 | if (op1->value->type->id == ZigTypeIdComptimeInt) { | |
| 16874 | if (op1_scalar_type->id == ZigTypeIdComptimeInt) { | |
| 16852 | 16875 | // comptime_int has no finite bit width |
| 16853 | 16876 | casted_op2 = op2; |
| 16854 | 16877 | |
| ... | ... | @@ -16874,10 +16897,15 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in |
| 16874 | 16897 | return ira->codegen->invalid_inst_gen; |
| 16875 | 16898 | } |
| 16876 | 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 | 16901 | ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, |
| 16879 | 16902 | bit_count > 0 ? bit_count - 1 : 0); |
| 16880 | 16903 | |
| 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 | 16909 | casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); |
| 16882 | 16910 | if (type_is_invalid(casted_op2->value->type)) |
| 16883 | 16911 | return ira->codegen->invalid_inst_gen; |
| ... | ... | @@ -16888,10 +16916,10 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in |
| 16888 | 16916 | if (op2_val == nullptr) |
| 16889 | 16917 | return ira->codegen->invalid_inst_gen; |
| 16890 | 16918 | |
| 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); | |
| 16893 | 16921 | |
| 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 | 16923 | ErrorMsg* msg = ir_add_error(ira, |
| 16896 | 16924 | &bin_op_instruction->base.base, |
| 16897 | 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 | 16938 | if (op2_val == nullptr) |
| 16911 | 16939 | return ira->codegen->invalid_inst_gen; |
| 16912 | 16940 | |
| 16913 | if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ) | |
| 16941 | if (value_cmp_numeric_val_all(op2_val, CmpEQ, nullptr)) | |
| 16914 | 16942 | return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1); |
| 16915 | 16943 | } |
| 16916 | 16944 | |
| ... | ... | @@ -16923,7 +16951,7 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in |
| 16923 | 16951 | if (op2_val == nullptr) |
| 16924 | 16952 | return ira->codegen->invalid_inst_gen; |
| 16925 | 16953 | |
| 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 | } |
| 16928 | 16956 | |
| 16929 | 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 | 17019 | zig_unreachable(); |
| 16992 | 17020 | } |
| 16993 | 17021 | |
| 16994 | static bool value_cmp_zero_any(ZigValue *value, Cmp predicate) { | |
| 16995 | assert(value->special == ConstValSpecialStatic); | |
| 17022 | static 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); | |
| 16996 | 17025 | |
| 16997 | switch (value->type->id) { | |
| 17026 | switch (left->type->id) { | |
| 16998 | 17027 | 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 | } | |
| 17001 | 17034 | case ZigTypeIdComptimeFloat: |
| 17002 | case ZigTypeIdFloat: | |
| 17003 | if (float_is_nan(value)) | |
| 17035 | case ZigTypeIdFloat: { | |
| 17036 | if (float_is_nan(left)) | |
| 17004 | 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 | 17044 | 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 | |
| 17011 | 17053 | } |
| 17012 | return false; | |
| 17054 | return any ? false : true; | |
| 17013 | 17055 | } |
| 17014 | 17056 | default: |
| 17015 | 17057 | zig_unreachable(); |
| 17016 | 17058 | } |
| 17017 | 17059 | } |
| 17018 | 17060 | |
| 17061 | static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right) { | |
| 17062 | return value_cmp_numeric_val(left, predicate, right, true); | |
| 17063 | } | |
| 17064 | ||
| 17065 | static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right) { | |
| 17066 | return value_cmp_numeric_val(left, predicate, right, false); | |
| 17067 | } | |
| 17068 | ||
| 17019 | 17069 | static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruction) { |
| 17020 | 17070 | Error err; |
| 17021 | 17071 | |
| ... | ... | @@ -17165,8 +17215,8 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc |
| 17165 | 17215 | return ira->codegen->invalid_inst_gen; |
| 17166 | 17216 | |
| 17167 | 17217 | // 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); | |
| 17170 | 17220 | |
| 17171 | 17221 | if (op_id == IrBinOpDivUnspecified && is_int) { |
| 17172 | 17222 | // 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 | 17226 | if (is_signed_div) { |
| 17177 | 17227 | bool ok = false; |
| 17178 | 17228 | |
| 17179 | if (value_cmp_zero_any(op2_val, CmpEQ)) { | |
| 17229 | if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) { | |
| 17180 | 17230 | // the division by zero error will be caught later, but we don't have a |
| 17181 | 17231 | // division function ambiguity problem. |
| 17182 | 17232 | ok = true; |
| ... | ... | @@ -17215,7 +17265,7 @@ static IrInstGen *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstSrcBinOp *instruc |
| 17215 | 17265 | if (is_signed_div) { |
| 17216 | 17266 | bool ok = false; |
| 17217 | 17267 | |
| 17218 | if (value_cmp_zero_any(op2_val, CmpEQ)) { | |
| 17268 | if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) { | |
| 17219 | 17269 | // the division by zero error will be caught later, but we don't have a |
| 17220 | 17270 | // division function ambiguity problem. |
| 17221 | 17271 | ok = true; |
test/stage1/behavior/vector.zig+65| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const mem = std.mem; |
| 3 | const math = std.math; | |
| 3 | 4 | const expect = std.testing.expect; |
| 4 | 5 | const expectEqual = std.testing.expectEqual; |
| 5 | 6 | |
| ... | ... | @@ -376,3 +377,67 @@ test "vector bitwise not operator" { |
| 376 | 377 | S.doTheTest(); |
| 377 | 378 | comptime S.doTheTest(); |
| 378 | 379 | } |
| 380 | ||
| 381 | test "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 | } |