| ... | @@ -155,7 +155,6 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstGen *source_instr, | ... | @@ -155,7 +155,6 @@ 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); |
| 157 | static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix); | 157 | static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix); |
| 158 | static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val); | | |
| 159 | | 158 | |
| 160 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { | 159 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { |
| 161 | unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); | 160 | unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); |
| ... | @@ -2536,6 +2535,36 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir | ... | @@ -2536,6 +2535,36 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir |
| 2536 | return nullptr; | 2535 | return nullptr; |
| 2537 | } | 2536 | } |
| 2538 | | 2537 | |
| | 2538 | enum class ScalarizePredicate { |
| | 2539 | // Returns true iff all the elements in the vector are 1. |
| | 2540 | // Equivalent to folding all the bits with `and`. |
| | 2541 | All, |
| | 2542 | // Returns true iff there's at least one element in the vector that is 1. |
| | 2543 | // Equivalent to folding all the bits with `or`. |
| | 2544 | Any, |
| | 2545 | }; |
| | 2546 | |
| | 2547 | // Collapses a <N x i1> vector into a single i1 according to the given predicate |
| | 2548 | static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val, ScalarizePredicate predicate) { |
| | 2549 | assert(LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMVectorTypeKind); |
| | 2550 | LLVMTypeRef scalar_type = LLVMIntType(LLVMGetVectorSize(LLVMTypeOf(val))); |
| | 2551 | LLVMValueRef casted = LLVMBuildBitCast(g->builder, val, scalar_type, ""); |
| | 2552 | |
| | 2553 | switch (predicate) { |
| | 2554 | case ScalarizePredicate::Any: { |
| | 2555 | LLVMValueRef all_zeros = LLVMConstNull(scalar_type); |
| | 2556 | return LLVMBuildICmp(g->builder, LLVMIntNE, casted, all_zeros, ""); |
| | 2557 | } |
| | 2558 | case ScalarizePredicate::All: { |
| | 2559 | LLVMValueRef all_ones = LLVMConstAllOnes(scalar_type); |
| | 2560 | return LLVMBuildICmp(g->builder, LLVMIntEQ, casted, all_ones, ""); |
| | 2561 | } |
| | 2562 | } |
| | 2563 | |
| | 2564 | zig_unreachable(); |
| | 2565 | } |
| | 2566 | |
| | 2567 | |
| 2539 | static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, | 2568 | static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, |
| 2540 | LLVMValueRef val1, LLVMValueRef val2) | 2569 | LLVMValueRef val1, LLVMValueRef val2) |
| 2541 | { | 2570 | { |
| ... | @@ -2560,7 +2589,7 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, | ... | @@ -2560,7 +2589,7 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, |
| 2560 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); | 2589 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 2561 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); | 2590 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); |
| 2562 | if (operand_type->id == ZigTypeIdVector) { | 2591 | if (operand_type->id == ZigTypeIdVector) { |
| 2563 | ok_bit = scalarize_cmp_result(g, ok_bit); | 2592 | ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All); |
| 2564 | } | 2593 | } |
| 2565 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 2594 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2566 | | 2595 | |
| ... | @@ -2591,7 +2620,7 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type, | ... | @@ -2591,7 +2620,7 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type, |
| 2591 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); | 2620 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 2592 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); | 2621 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); |
| 2593 | if (operand_type->id == ZigTypeIdVector) { | 2622 | if (operand_type->id == ZigTypeIdVector) { |
| 2594 | ok_bit = scalarize_cmp_result(g, ok_bit); | 2623 | ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All); |
| 2595 | } | 2624 | } |
| 2596 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 2625 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2597 | | 2626 | |
| ... | @@ -2647,16 +2676,6 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { | ... | @@ -2647,16 +2676,6 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { |
| 2647 | } | 2676 | } |
| 2648 | } | 2677 | } |
| 2649 | | 2678 | |
| 2650 | // Collapses a <N x i1> vector into a single i1 whose value is 1 iff all the | | |
| 2651 | // vector elements are 1 | | |
| 2652 | static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val) { | | |
| 2653 | assert(LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMVectorTypeKind); | | |
| 2654 | LLVMTypeRef scalar_type = LLVMIntType(LLVMGetVectorSize(LLVMTypeOf(val))); | | |
| 2655 | LLVMValueRef all_ones = LLVMConstAllOnes(scalar_type); | | |
| 2656 | LLVMValueRef casted = LLVMBuildBitCast(g->builder, val, scalar_type, ""); | | |
| 2657 | return LLVMBuildICmp(g->builder, LLVMIntEQ, casted, all_ones, ""); | | |
| 2658 | } | | |
| 2659 | | | |
| 2660 | static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, | 2679 | static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, |
| 2661 | LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, DivKind div_kind) | 2680 | LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, DivKind div_kind) |
| 2662 | { | 2681 | { |
| ... | @@ -2678,7 +2697,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2678,7 +2697,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2678 | } | 2697 | } |
| 2679 | | 2698 | |
| 2680 | if (operand_type->id == ZigTypeIdVector) { | 2699 | if (operand_type->id == ZigTypeIdVector) { |
| 2681 | is_zero_bit = scalarize_cmp_result(g, is_zero_bit); | 2700 | is_zero_bit = scalarize_cmp_result(g, is_zero_bit, ScalarizePredicate::Any); |
| 2682 | } | 2701 | } |
| 2683 | | 2702 | |
| 2684 | LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); | 2703 | LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); |
| ... | @@ -2703,7 +2722,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2703,7 +2722,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2703 | LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, ""); | 2722 | LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, ""); |
| 2704 | LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, ""); | 2723 | LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, ""); |
| 2705 | if (operand_type->id == ZigTypeIdVector) { | 2724 | if (operand_type->id == ZigTypeIdVector) { |
| 2706 | overflow_fail_bit = scalarize_cmp_result(g, overflow_fail_bit); | 2725 | overflow_fail_bit = scalarize_cmp_result(g, overflow_fail_bit, ScalarizePredicate::Any); |
| 2707 | } | 2726 | } |
| 2708 | LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); | 2727 | LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); |
| 2709 | | 2728 | |
| ... | @@ -2728,7 +2747,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2728,7 +2747,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2728 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | 2747 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| 2729 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); | 2748 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); |
| 2730 | if (operand_type->id == ZigTypeIdVector) { | 2749 | if (operand_type->id == ZigTypeIdVector) { |
| 2731 | ok_bit = scalarize_cmp_result(g, ok_bit); | 2750 | ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All); |
| 2732 | } | 2751 | } |
| 2733 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 2752 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2734 | | 2753 | |
| ... | @@ -2745,7 +2764,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2745,7 +2764,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2745 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd"); | 2764 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd"); |
| 2746 | LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, ""); | 2765 | LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, ""); |
| 2747 | if (operand_type->id == ZigTypeIdVector) { | 2766 | if (operand_type->id == ZigTypeIdVector) { |
| 2748 | ltz = scalarize_cmp_result(g, ltz); | 2767 | ltz = scalarize_cmp_result(g, ltz, ScalarizePredicate::Any); |
| 2749 | } | 2768 | } |
| 2750 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); | 2769 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); |
| 2751 | | 2770 | |
| ... | @@ -2797,7 +2816,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2797,7 +2816,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2797 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | 2816 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| 2798 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); | 2817 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); |
| 2799 | if (operand_type->id == ZigTypeIdVector) { | 2818 | if (operand_type->id == ZigTypeIdVector) { |
| 2800 | ok_bit = scalarize_cmp_result(g, ok_bit); | 2819 | ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All); |
| 2801 | } | 2820 | } |
| 2802 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 2821 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2803 | | 2822 | |
| ... | @@ -2861,7 +2880,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2861,7 +2880,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2861 | } | 2880 | } |
| 2862 | | 2881 | |
| 2863 | if (operand_type->id == ZigTypeIdVector) { | 2882 | if (operand_type->id == ZigTypeIdVector) { |
| 2864 | is_zero_bit = scalarize_cmp_result(g, is_zero_bit); | 2883 | is_zero_bit = scalarize_cmp_result(g, is_zero_bit, ScalarizePredicate::Any); |
| 2865 | } | 2884 | } |
| 2866 | | 2885 | |
| 2867 | LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk"); | 2886 | LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk"); |
| ... | @@ -2918,7 +2937,7 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type | ... | @@ -2918,7 +2937,7 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type |
| 2918 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk"); | 2937 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk"); |
| 2919 | LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, ""); | 2938 | LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, ""); |
| 2920 | if (rhs_type->id == ZigTypeIdVector) { | 2939 | if (rhs_type->id == ZigTypeIdVector) { |
| 2921 | less_than_bit = scalarize_cmp_result(g, less_than_bit); | 2940 | less_than_bit = scalarize_cmp_result(g, less_than_bit, ScalarizePredicate::Any); |
| 2922 | } | 2941 | } |
| 2923 | LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block); | 2942 | LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block); |
| 2924 | | 2943 | |