| ... | @@ -2591,12 +2591,7 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, | ... | @@ -2591,12 +2591,7 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, |
| 2591 | } | 2591 | } |
| 2592 | | 2592 | |
| 2593 | static LLVMValueRef gen_float_op(CodeGen *g, LLVMValueRef val, ZigType *type_entry, BuiltinFnId op) { | 2593 | static LLVMValueRef gen_float_op(CodeGen *g, LLVMValueRef val, ZigType *type_entry, BuiltinFnId op) { |
| 2594 | if ((op == BuiltinFnIdCeil || | 2594 | assert(type_entry->id == ZigTypeIdFloat || type_entry->id == ZigTypeIdVector); |
| 2595 | op == BuiltinFnIdFloor) && | | |
| 2596 | type_entry->id == ZigTypeIdInt) | | |
| 2597 | return val; | | |
| 2598 | assert(type_entry->id == ZigTypeIdFloat); | | |
| 2599 | | | |
| 2600 | LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloatOp, op); | 2595 | LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloatOp, op); |
| 2601 | return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); | 2596 | return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); |
| 2602 | } | 2597 | } |
| ... | @@ -2612,6 +2607,21 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { | ... | @@ -2612,6 +2607,21 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { |
| 2612 | if (bigint->digit_count == 0) { | 2607 | if (bigint->digit_count == 0) { |
| 2613 | return LLVMConstNull(type_ref); | 2608 | return LLVMConstNull(type_ref); |
| 2614 | } | 2609 | } |
| | 2610 | |
| | 2611 | if (LLVMGetTypeKind(type_ref) == LLVMVectorTypeKind) { |
| | 2612 | const unsigned vector_len = LLVMGetVectorSize(type_ref); |
| | 2613 | LLVMTypeRef elem_type = LLVMGetElementType(type_ref); |
| | 2614 | |
| | 2615 | LLVMValueRef *values = heap::c_allocator.allocate_nonzero<LLVMValueRef>(vector_len); |
| | 2616 | // Create a vector with all the elements having the same value |
| | 2617 | for (unsigned i = 0; i < vector_len; i++) { |
| | 2618 | values[i] = bigint_to_llvm_const(elem_type, bigint); |
| | 2619 | } |
| | 2620 | LLVMValueRef result = LLVMConstVector(values, vector_len); |
| | 2621 | heap::c_allocator.deallocate(values, vector_len); |
| | 2622 | return result; |
| | 2623 | } |
| | 2624 | |
| 2615 | LLVMValueRef unsigned_val; | 2625 | LLVMValueRef unsigned_val; |
| 2616 | if (bigint->digit_count == 1) { | 2626 | if (bigint->digit_count == 1) { |
| 2617 | unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false); | 2627 | unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false); |
| ... | @@ -2625,22 +2635,40 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { | ... | @@ -2625,22 +2635,40 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { |
| 2625 | } | 2635 | } |
| 2626 | } | 2636 | } |
| 2627 | | 2637 | |
| | 2638 | // Collapses a <N x i1> vector into a single i1 whose value is 1 iff all the |
| | 2639 | // vector elements are 1 |
| | 2640 | static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val) { |
| | 2641 | assert(LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMVectorTypeKind); |
| | 2642 | LLVMTypeRef scalar_type = LLVMIntType(LLVMGetVectorSize(LLVMTypeOf(val))); |
| | 2643 | LLVMValueRef all_ones = LLVMConstAllOnes(scalar_type); |
| | 2644 | LLVMValueRef casted = LLVMBuildBitCast(g->builder, val, scalar_type, ""); |
| | 2645 | return LLVMBuildICmp(g->builder, LLVMIntEQ, casted, all_ones, ""); |
| | 2646 | } |
| | 2647 | |
| 2628 | static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, | 2648 | static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, |
| 2629 | LLVMValueRef val1, LLVMValueRef val2, | 2649 | LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, DivKind div_kind) |
| 2630 | ZigType *type_entry, DivKind div_kind) | | |
| 2631 | { | 2650 | { |
| | 2651 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? |
| | 2652 | operand_type->data.vector.elem_type : operand_type; |
| | 2653 | |
| 2632 | ZigLLVMSetFastMath(g->builder, want_fast_math); | 2654 | ZigLLVMSetFastMath(g->builder, want_fast_math); |
| 2633 | | 2655 | |
| 2634 | LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, type_entry)); | 2656 | LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, operand_type)); |
| 2635 | if (want_runtime_safety && (want_fast_math || type_entry->id != ZigTypeIdFloat)) { | 2657 | if (want_runtime_safety && (want_fast_math || scalar_type->id != ZigTypeIdFloat)) { |
| | 2658 | // Safety check: divisor != 0 |
| 2636 | LLVMValueRef is_zero_bit; | 2659 | LLVMValueRef is_zero_bit; |
| 2637 | if (type_entry->id == ZigTypeIdInt) { | 2660 | if (scalar_type->id == ZigTypeIdInt) { |
| 2638 | is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); | 2661 | is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); |
| 2639 | } else if (type_entry->id == ZigTypeIdFloat) { | 2662 | } else if (scalar_type->id == ZigTypeIdFloat) { |
| 2640 | is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); | 2663 | is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); |
| 2641 | } else { | 2664 | } else { |
| 2642 | zig_unreachable(); | 2665 | zig_unreachable(); |
| 2643 | } | 2666 | } |
| | 2667 | |
| | 2668 | if (operand_type->id == ZigTypeIdVector) { |
| | 2669 | is_zero_bit = scalarize_cmp_result(g, is_zero_bit); |
| | 2670 | } |
| | 2671 | |
| 2644 | LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); | 2672 | LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); |
| 2645 | LLVMBasicBlockRef div_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk"); | 2673 | LLVMBasicBlockRef div_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk"); |
| 2646 | LLVMBuildCondBr(g->builder, is_zero_bit, div_zero_fail_block, div_zero_ok_block); | 2674 | LLVMBuildCondBr(g->builder, is_zero_bit, div_zero_fail_block, div_zero_ok_block); |
| ... | @@ -2650,16 +2678,21 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2650,16 +2678,21 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2650 | | 2678 | |
| 2651 | LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block); | 2679 | LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block); |
| 2652 | | 2680 | |
| 2653 | if (type_entry->id == ZigTypeIdInt && type_entry->data.integral.is_signed) { | 2681 | // Safety check: check for overflow (dividend = minInt and divisor = -1) |
| 2654 | LLVMValueRef neg_1_value = LLVMConstInt(get_llvm_type(g, type_entry), -1, true); | 2682 | if (scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) { |
| | 2683 | LLVMValueRef neg_1_value = LLVMConstAllOnes(get_llvm_type(g, operand_type)); |
| 2655 | BigInt int_min_bi = {0}; | 2684 | BigInt int_min_bi = {0}; |
| 2656 | eval_min_max_value_int(g, type_entry, &int_min_bi, false); | 2685 | eval_min_max_value_int(g, scalar_type, &int_min_bi, false); |
| 2657 | LLVMValueRef int_min_value = bigint_to_llvm_const(get_llvm_type(g, type_entry), &int_min_bi); | 2686 | LLVMValueRef int_min_value = bigint_to_llvm_const(get_llvm_type(g, operand_type), &int_min_bi); |
| | 2687 | |
| 2658 | LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail"); | 2688 | LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail"); |
| 2659 | LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk"); | 2689 | LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk"); |
| 2660 | LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, ""); | 2690 | LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, ""); |
| 2661 | LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, ""); | 2691 | LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, ""); |
| 2662 | LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, ""); | 2692 | LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, ""); |
| | 2693 | if (operand_type->id == ZigTypeIdVector) { |
| | 2694 | overflow_fail_bit = scalarize_cmp_result(g, overflow_fail_bit); |
| | 2695 | } |
| 2663 | LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); | 2696 | LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); |
| 2664 | | 2697 | |
| 2665 | LLVMPositionBuilderAtEnd(g->builder, overflow_fail_block); | 2698 | LLVMPositionBuilderAtEnd(g->builder, overflow_fail_block); |
| ... | @@ -2669,18 +2702,22 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2669,18 +2702,22 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2669 | } | 2702 | } |
| 2670 | } | 2703 | } |
| 2671 | | 2704 | |
| 2672 | if (type_entry->id == ZigTypeIdFloat) { | 2705 | if (scalar_type->id == ZigTypeIdFloat) { |
| 2673 | LLVMValueRef result = LLVMBuildFDiv(g->builder, val1, val2, ""); | 2706 | LLVMValueRef result = LLVMBuildFDiv(g->builder, val1, val2, ""); |
| 2674 | switch (div_kind) { | 2707 | switch (div_kind) { |
| 2675 | case DivKindFloat: | 2708 | case DivKindFloat: |
| 2676 | return result; | 2709 | return result; |
| 2677 | case DivKindExact: | 2710 | case DivKindExact: |
| 2678 | if (want_runtime_safety) { | 2711 | if (want_runtime_safety) { |
| 2679 | LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); | 2712 | // Safety check: a / b == floor(a / b) |
| | 2713 | LLVMValueRef floored = gen_float_op(g, result, operand_type, BuiltinFnIdFloor); |
| | 2714 | |
| 2680 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); | 2715 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); |
| 2681 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | 2716 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| 2682 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); | 2717 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); |
| 2683 | | 2718 | if (operand_type->id == ZigTypeIdVector) { |
| | 2719 | ok_bit = scalarize_cmp_result(g, ok_bit); |
| | 2720 | } |
| 2684 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 2721 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2685 | | 2722 | |
| 2686 | LLVMPositionBuilderAtEnd(g->builder, fail_block); | 2723 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| ... | @@ -2695,54 +2732,61 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2695,54 +2732,61 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2695 | LLVMBasicBlockRef gez_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncGEZero"); | 2732 | LLVMBasicBlockRef gez_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncGEZero"); |
| 2696 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd"); | 2733 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd"); |
| 2697 | LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, ""); | 2734 | LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, ""); |
| | 2735 | if (operand_type->id == ZigTypeIdVector) { |
| | 2736 | ltz = scalarize_cmp_result(g, ltz); |
| | 2737 | } |
| 2698 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); | 2738 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); |
| 2699 | | 2739 | |
| 2700 | LLVMPositionBuilderAtEnd(g->builder, ltz_block); | 2740 | LLVMPositionBuilderAtEnd(g->builder, ltz_block); |
| 2701 | LLVMValueRef ceiled = gen_float_op(g, result, type_entry, BuiltinFnIdCeil); | 2741 | LLVMValueRef ceiled = gen_float_op(g, result, operand_type, BuiltinFnIdCeil); |
| 2702 | LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); | 2742 | LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); |
| 2703 | LLVMBuildBr(g->builder, end_block); | 2743 | LLVMBuildBr(g->builder, end_block); |
| 2704 | | 2744 | |
| 2705 | LLVMPositionBuilderAtEnd(g->builder, gez_block); | 2745 | LLVMPositionBuilderAtEnd(g->builder, gez_block); |
| 2706 | LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); | 2746 | LLVMValueRef floored = gen_float_op(g, result, operand_type, BuiltinFnIdFloor); |
| 2707 | LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); | 2747 | LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); |
| 2708 | LLVMBuildBr(g->builder, end_block); | 2748 | LLVMBuildBr(g->builder, end_block); |
| 2709 | | 2749 | |
| 2710 | LLVMPositionBuilderAtEnd(g->builder, end_block); | 2750 | LLVMPositionBuilderAtEnd(g->builder, end_block); |
| 2711 | LLVMValueRef phi = LLVMBuildPhi(g->builder, get_llvm_type(g, type_entry), ""); | 2751 | LLVMValueRef phi = LLVMBuildPhi(g->builder, get_llvm_type(g, operand_type), ""); |
| 2712 | LLVMValueRef incoming_values[] = { ceiled, floored }; | 2752 | LLVMValueRef incoming_values[] = { ceiled, floored }; |
| 2713 | LLVMBasicBlockRef incoming_blocks[] = { ceiled_end_block, floored_end_block }; | 2753 | LLVMBasicBlockRef incoming_blocks[] = { ceiled_end_block, floored_end_block }; |
| 2714 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); | 2754 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); |
| 2715 | return phi; | 2755 | return phi; |
| 2716 | } | 2756 | } |
| 2717 | case DivKindFloor: | 2757 | case DivKindFloor: |
| 2718 | return gen_float_op(g, result, type_entry, BuiltinFnIdFloor); | 2758 | return gen_float_op(g, result, operand_type, BuiltinFnIdFloor); |
| 2719 | } | 2759 | } |
| 2720 | zig_unreachable(); | 2760 | zig_unreachable(); |
| 2721 | } | 2761 | } |
| 2722 | | 2762 | |
| 2723 | assert(type_entry->id == ZigTypeIdInt); | 2763 | assert(scalar_type->id == ZigTypeIdInt); |
| 2724 | | 2764 | |
| 2725 | switch (div_kind) { | 2765 | switch (div_kind) { |
| 2726 | case DivKindFloat: | 2766 | case DivKindFloat: |
| 2727 | zig_unreachable(); | 2767 | zig_unreachable(); |
| 2728 | case DivKindTrunc: | 2768 | case DivKindTrunc: |
| 2729 | if (type_entry->data.integral.is_signed) { | 2769 | if (scalar_type->data.integral.is_signed) { |
| 2730 | return LLVMBuildSDiv(g->builder, val1, val2, ""); | 2770 | return LLVMBuildSDiv(g->builder, val1, val2, ""); |
| 2731 | } else { | 2771 | } else { |
| 2732 | return LLVMBuildUDiv(g->builder, val1, val2, ""); | 2772 | return LLVMBuildUDiv(g->builder, val1, val2, ""); |
| 2733 | } | 2773 | } |
| 2734 | case DivKindExact: | 2774 | case DivKindExact: |
| 2735 | if (want_runtime_safety) { | 2775 | if (want_runtime_safety) { |
| | 2776 | // Safety check: a % b == 0 |
| 2736 | LLVMValueRef remainder_val; | 2777 | LLVMValueRef remainder_val; |
| 2737 | if (type_entry->data.integral.is_signed) { | 2778 | if (scalar_type->data.integral.is_signed) { |
| 2738 | remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); | 2779 | remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); |
| 2739 | } else { | 2780 | } else { |
| 2740 | remainder_val = LLVMBuildURem(g->builder, val1, val2, ""); | 2781 | remainder_val = LLVMBuildURem(g->builder, val1, val2, ""); |
| 2741 | } | 2782 | } |
| 2742 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); | | |
| 2743 | | 2783 | |
| 2744 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); | 2784 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); |
| 2745 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | 2785 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| | 2786 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); |
| | 2787 | if (operand_type->id == ZigTypeIdVector) { |
| | 2788 | ok_bit = scalarize_cmp_result(g, ok_bit); |
| | 2789 | } |
| 2746 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 2790 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 2747 | | 2791 | |
| 2748 | LLVMPositionBuilderAtEnd(g->builder, fail_block); | 2792 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| ... | @@ -2750,14 +2794,14 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2750,14 +2794,14 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2750 | | 2794 | |
| 2751 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | 2795 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 2752 | } | 2796 | } |
| 2753 | if (type_entry->data.integral.is_signed) { | 2797 | if (scalar_type->data.integral.is_signed) { |
| 2754 | return LLVMBuildExactSDiv(g->builder, val1, val2, ""); | 2798 | return LLVMBuildExactSDiv(g->builder, val1, val2, ""); |
| 2755 | } else { | 2799 | } else { |
| 2756 | return LLVMBuildExactUDiv(g->builder, val1, val2, ""); | 2800 | return LLVMBuildExactUDiv(g->builder, val1, val2, ""); |
| 2757 | } | 2801 | } |
| 2758 | case DivKindFloor: | 2802 | case DivKindFloor: |
| 2759 | { | 2803 | { |
| 2760 | if (!type_entry->data.integral.is_signed) { | 2804 | if (!scalar_type->data.integral.is_signed) { |
| 2761 | return LLVMBuildUDiv(g->builder, val1, val2, ""); | 2805 | return LLVMBuildUDiv(g->builder, val1, val2, ""); |
| 2762 | } | 2806 | } |
| 2763 | // const d = @divTrunc(a, b); | 2807 | // const d = @divTrunc(a, b); |
| ... | @@ -2784,22 +2828,30 @@ enum RemKind { | ... | @@ -2784,22 +2828,30 @@ enum RemKind { |
| 2784 | }; | 2828 | }; |
| 2785 | | 2829 | |
| 2786 | static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast_math, | 2830 | static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast_math, |
| 2787 | LLVMValueRef val1, LLVMValueRef val2, | 2831 | LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, RemKind rem_kind) |
| 2788 | ZigType *type_entry, RemKind rem_kind) | | |
| 2789 | { | 2832 | { |
| | 2833 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? |
| | 2834 | operand_type->data.vector.elem_type : operand_type; |
| | 2835 | |
| 2790 | ZigLLVMSetFastMath(g->builder, want_fast_math); | 2836 | ZigLLVMSetFastMath(g->builder, want_fast_math); |
| 2791 | | 2837 | |
| 2792 | LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, type_entry)); | 2838 | LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, operand_type)); |
| 2793 | if (want_runtime_safety) { | 2839 | if (want_runtime_safety) { |
| | 2840 | // Safety check: divisor != 0 |
| 2794 | LLVMValueRef is_zero_bit; | 2841 | LLVMValueRef is_zero_bit; |
| 2795 | if (type_entry->id == ZigTypeIdInt) { | 2842 | if (scalar_type->id == ZigTypeIdInt) { |
| 2796 | LLVMIntPredicate pred = type_entry->data.integral.is_signed ? LLVMIntSLE : LLVMIntEQ; | 2843 | LLVMIntPredicate pred = scalar_type->data.integral.is_signed ? LLVMIntSLE : LLVMIntEQ; |
| 2797 | is_zero_bit = LLVMBuildICmp(g->builder, pred, val2, zero, ""); | 2844 | is_zero_bit = LLVMBuildICmp(g->builder, pred, val2, zero, ""); |
| 2798 | } else if (type_entry->id == ZigTypeIdFloat) { | 2845 | } else if (scalar_type->id == ZigTypeIdFloat) { |
| 2799 | is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); | 2846 | is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); |
| 2800 | } else { | 2847 | } else { |
| 2801 | zig_unreachable(); | 2848 | zig_unreachable(); |
| 2802 | } | 2849 | } |
| | 2850 | |
| | 2851 | if (operand_type->id == ZigTypeIdVector) { |
| | 2852 | is_zero_bit = scalarize_cmp_result(g, is_zero_bit); |
| | 2853 | } |
| | 2854 | |
| 2803 | LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk"); | 2855 | LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk"); |
| 2804 | LLVMBasicBlockRef rem_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroFail"); | 2856 | LLVMBasicBlockRef rem_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroFail"); |
| 2805 | LLVMBuildCondBr(g->builder, is_zero_bit, rem_zero_fail_block, rem_zero_ok_block); | 2857 | LLVMBuildCondBr(g->builder, is_zero_bit, rem_zero_fail_block, rem_zero_ok_block); |
| ... | @@ -2810,7 +2862,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2810,7 +2862,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2810 | LLVMPositionBuilderAtEnd(g->builder, rem_zero_ok_block); | 2862 | LLVMPositionBuilderAtEnd(g->builder, rem_zero_ok_block); |
| 2811 | } | 2863 | } |
| 2812 | | 2864 | |
| 2813 | if (type_entry->id == ZigTypeIdFloat) { | 2865 | if (scalar_type->id == ZigTypeIdFloat) { |
| 2814 | if (rem_kind == RemKindRem) { | 2866 | if (rem_kind == RemKindRem) { |
| 2815 | return LLVMBuildFRem(g->builder, val1, val2, ""); | 2867 | return LLVMBuildFRem(g->builder, val1, val2, ""); |
| 2816 | } else { | 2868 | } else { |
| ... | @@ -2821,8 +2873,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2821,8 +2873,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2821 | return LLVMBuildSelect(g->builder, ltz, c, a, ""); | 2873 | return LLVMBuildSelect(g->builder, ltz, c, a, ""); |
| 2822 | } | 2874 | } |
| 2823 | } else { | 2875 | } else { |
| 2824 | assert(type_entry->id == ZigTypeIdInt); | 2876 | assert(scalar_type->id == ZigTypeIdInt); |
| 2825 | if (type_entry->data.integral.is_signed) { | 2877 | if (scalar_type->data.integral.is_signed) { |
| 2826 | if (rem_kind == RemKindRem) { | 2878 | if (rem_kind == RemKindRem) { |
| 2827 | return LLVMBuildSRem(g->builder, val1, val2, ""); | 2879 | return LLVMBuildSRem(g->builder, val1, val2, ""); |
| 2828 | } else { | 2880 | } else { |
| ... | @@ -3010,22 +3062,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable, | ... | @@ -3010,22 +3062,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable, |
| 3010 | } | 3062 | } |
| 3011 | case IrBinOpDivUnspecified: | 3063 | case IrBinOpDivUnspecified: |
| 3012 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3064 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3013 | op1_value, op2_value, scalar_type, DivKindFloat); | 3065 | op1_value, op2_value, operand_type, DivKindFloat); |
| 3014 | case IrBinOpDivExact: | 3066 | case IrBinOpDivExact: |
| 3015 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3067 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3016 | op1_value, op2_value, scalar_type, DivKindExact); | 3068 | op1_value, op2_value, operand_type, DivKindExact); |
| 3017 | case IrBinOpDivTrunc: | 3069 | case IrBinOpDivTrunc: |
| 3018 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3070 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3019 | op1_value, op2_value, scalar_type, DivKindTrunc); | 3071 | op1_value, op2_value, operand_type, DivKindTrunc); |
| 3020 | case IrBinOpDivFloor: | 3072 | case IrBinOpDivFloor: |
| 3021 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3073 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3022 | op1_value, op2_value, scalar_type, DivKindFloor); | 3074 | op1_value, op2_value, operand_type, DivKindFloor); |
| 3023 | case IrBinOpRemRem: | 3075 | case IrBinOpRemRem: |
| 3024 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3076 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3025 | op1_value, op2_value, scalar_type, RemKindRem); | 3077 | op1_value, op2_value, operand_type, RemKindRem); |
| 3026 | case IrBinOpRemMod: | 3078 | case IrBinOpRemMod: |
| 3027 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3079 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3028 | op1_value, op2_value, scalar_type, RemKindMod); | 3080 | op1_value, op2_value, operand_type, RemKindMod); |
| 3029 | } | 3081 | } |
| 3030 | zig_unreachable(); | 3082 | zig_unreachable(); |
| 3031 | } | 3083 | } |