| ... | @@ -715,38 +715,59 @@ static void clear_debug_source_node(CodeGen *g) { | ... | @@ -715,38 +715,59 @@ static void clear_debug_source_node(CodeGen *g) { |
| 715 | ZigLLVMClearCurrentDebugLocation(g->builder); | 715 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 716 | } | 716 | } |
| 717 | | 717 | |
| 718 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *type_entry, | 718 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type, |
| 719 | const char *signed_name, const char *unsigned_name) | 719 | const char *signed_name, const char *unsigned_name) |
| 720 | { | 720 | { |
| | 721 | ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| 721 | char fn_name[64]; | 722 | char fn_name[64]; |
| 722 | | 723 | |
| 723 | assert(type_entry->id == ZigTypeIdInt); | 724 | assert(int_type->id == ZigTypeIdInt); |
| 724 | const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name; | 725 | const char *signed_str = int_type->data.integral.is_signed ? signed_name : unsigned_name; |
| 725 | sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, type_entry->data.integral.bit_count); | | |
| 726 | | 726 | |
| 727 | LLVMTypeRef return_elem_types[] = { | | |
| 728 | type_entry->type_ref, | | |
| 729 | LLVMInt1Type(), | | |
| 730 | }; | | |
| 731 | LLVMTypeRef param_types[] = { | 727 | LLVMTypeRef param_types[] = { |
| 732 | type_entry->type_ref, | 728 | operand_type->type_ref, |
| 733 | type_entry->type_ref, | 729 | operand_type->type_ref, |
| 734 | }; | 730 | }; |
| 735 | LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); | 731 | |
| 736 | LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); | 732 | if (operand_type->id == ZigTypeIdVector) { |
| 737 | LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); | 733 | sprintf(fn_name, "llvm.%s.with.overflow.v%" PRIu32 "i%" PRIu32, signed_str, |
| 738 | assert(LLVMGetIntrinsicID(fn_val)); | 734 | operand_type->data.vector.len, int_type->data.integral.bit_count); |
| 739 | return fn_val; | 735 | |
| | 736 | LLVMTypeRef return_elem_types[] = { |
| | 737 | operand_type->type_ref, |
| | 738 | LLVMVectorType(LLVMInt1Type(), operand_type->data.vector.len), |
| | 739 | }; |
| | 740 | LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); |
| | 741 | LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); |
| | 742 | LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); |
| | 743 | assert(LLVMGetIntrinsicID(fn_val)); |
| | 744 | return fn_val; |
| | 745 | } else { |
| | 746 | sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, int_type->data.integral.bit_count); |
| | 747 | |
| | 748 | LLVMTypeRef return_elem_types[] = { |
| | 749 | operand_type->type_ref, |
| | 750 | LLVMInt1Type(), |
| | 751 | }; |
| | 752 | LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); |
| | 753 | LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); |
| | 754 | LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); |
| | 755 | assert(LLVMGetIntrinsicID(fn_val)); |
| | 756 | return fn_val; |
| | 757 | } |
| 740 | } | 758 | } |
| 741 | | 759 | |
| 742 | static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubMul add_sub_mul) { | 760 | static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSubMul add_sub_mul) { |
| 743 | assert(type_entry->id == ZigTypeIdInt); | 761 | ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| | 762 | assert(int_type->id == ZigTypeIdInt); |
| 744 | | 763 | |
| 745 | ZigLLVMFnKey key = {}; | 764 | ZigLLVMFnKey key = {}; |
| 746 | key.id = ZigLLVMFnIdOverflowArithmetic; | 765 | key.id = ZigLLVMFnIdOverflowArithmetic; |
| 747 | key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed; | 766 | key.data.overflow_arithmetic.is_signed = int_type->data.integral.is_signed; |
| 748 | key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; | 767 | key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; |
| 749 | key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count; | 768 | key.data.overflow_arithmetic.bit_count = (uint32_t)int_type->data.integral.bit_count; |
| | 769 | key.data.overflow_arithmetic.vector_len = (operand_type->id == ZigTypeIdVector) ? |
| | 770 | operand_type->data.vector.len : 0; |
| 750 | | 771 | |
| 751 | auto existing_entry = g->llvm_fn_table.maybe_get(key); | 772 | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| 752 | if (existing_entry) | 773 | if (existing_entry) |
| ... | @@ -755,13 +776,13 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubM | ... | @@ -755,13 +776,13 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubM |
| 755 | LLVMValueRef fn_val; | 776 | LLVMValueRef fn_val; |
| 756 | switch (add_sub_mul) { | 777 | switch (add_sub_mul) { |
| 757 | case AddSubMulAdd: | 778 | case AddSubMulAdd: |
| 758 | fn_val = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd"); | 779 | fn_val = get_arithmetic_overflow_fn(g, operand_type, "sadd", "uadd"); |
| 759 | break; | 780 | break; |
| 760 | case AddSubMulSub: | 781 | case AddSubMulSub: |
| 761 | fn_val = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub"); | 782 | fn_val = get_arithmetic_overflow_fn(g, operand_type, "ssub", "usub"); |
| 762 | break; | 783 | break; |
| 763 | case AddSubMulMul: | 784 | case AddSubMulMul: |
| 764 | fn_val = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul"); | 785 | fn_val = get_arithmetic_overflow_fn(g, operand_type, "smul", "umul"); |
| 765 | break; | 786 | break; |
| 766 | } | 787 | } |
| 767 | | 788 | |
| ... | @@ -1752,17 +1773,28 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z | ... | @@ -1752,17 +1773,28 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z |
| 1752 | } | 1773 | } |
| 1753 | } | 1774 | } |
| 1754 | | 1775 | |
| 1755 | static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *type_entry, AddSubMul op, | 1776 | static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op, |
| 1756 | LLVMValueRef val1, LLVMValueRef val2) | 1777 | LLVMValueRef val1, LLVMValueRef val2) |
| 1757 | { | 1778 | { |
| 1758 | LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op); | 1779 | LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); |
| 1759 | LLVMValueRef params[] = { | 1780 | LLVMValueRef params[] = { |
| 1760 | val1, | 1781 | val1, |
| 1761 | val2, | 1782 | val2, |
| 1762 | }; | 1783 | }; |
| 1763 | LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); | 1784 | LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 1764 | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); | 1785 | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 1765 | LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); | 1786 | |
| | 1787 | LLVMValueRef overflow_bit; |
| | 1788 | if (operand_type->id == ZigTypeIdVector) { |
| | 1789 | LLVMValueRef overflow_vector = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); |
| | 1790 | LLVMTypeRef bigger_int_type_ref = LLVMIntType(operand_type->data.vector.len); |
| | 1791 | LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bigger_int_type_ref, ""); |
| | 1792 | LLVMValueRef zero = LLVMConstNull(bigger_int_type_ref); |
| | 1793 | overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, bitcasted_overflow, zero, ""); |
| | 1794 | } else { |
| | 1795 | overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); |
| | 1796 | } |
| | 1797 | |
| 1766 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); | 1798 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); |
| 1767 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); | 1799 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 1768 | LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); | 1800 | LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); |
| ... | @@ -2608,7 +2640,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2608,7 +2640,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2608 | (op_id == IrBinOpAdd || op_id == IrBinOpSub) && | 2640 | (op_id == IrBinOpAdd || op_id == IrBinOpSub) && |
| 2609 | op1->value.type->data.pointer.ptr_len == PtrLenUnknown) | 2641 | op1->value.type->data.pointer.ptr_len == PtrLenUnknown) |
| 2610 | ); | 2642 | ); |
| 2611 | ZigType *type_entry = op1->value.type; | 2643 | ZigType *operand_type = op1->value.type; |
| | 2644 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| 2612 | | 2645 | |
| 2613 | bool want_runtime_safety = bin_op_instruction->safety_check_on && | 2646 | bool want_runtime_safety = bin_op_instruction->safety_check_on && |
| 2614 | ir_want_runtime_safety(g, &bin_op_instruction->base); | 2647 | ir_want_runtime_safety(g, &bin_op_instruction->base); |
| ... | @@ -2634,17 +2667,17 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2634,17 +2667,17 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2634 | case IrBinOpCmpGreaterThan: | 2667 | case IrBinOpCmpGreaterThan: |
| 2635 | case IrBinOpCmpLessOrEq: | 2668 | case IrBinOpCmpLessOrEq: |
| 2636 | case IrBinOpCmpGreaterOrEq: | 2669 | case IrBinOpCmpGreaterOrEq: |
| 2637 | if (type_entry->id == ZigTypeIdFloat) { | 2670 | if (scalar_type->id == ZigTypeIdFloat) { |
| 2638 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | 2671 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); |
| 2639 | LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); | 2672 | LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); |
| 2640 | return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); | 2673 | return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); |
| 2641 | } else if (type_entry->id == ZigTypeIdInt) { | 2674 | } else if (scalar_type->id == ZigTypeIdInt) { |
| 2642 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed); | 2675 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, scalar_type->data.integral.is_signed); |
| 2643 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); | 2676 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| 2644 | } else if (type_entry->id == ZigTypeIdEnum || | 2677 | } else if (scalar_type->id == ZigTypeIdEnum || |
| 2645 | type_entry->id == ZigTypeIdErrorSet || | 2678 | scalar_type->id == ZigTypeIdErrorSet || |
| 2646 | type_entry->id == ZigTypeIdBool || | 2679 | scalar_type->id == ZigTypeIdBool || |
| 2647 | get_codegen_ptr_type(type_entry) != nullptr) | 2680 | get_codegen_ptr_type(scalar_type) != nullptr) |
| 2648 | { | 2681 | { |
| 2649 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); | 2682 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); |
| 2650 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); | 2683 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| ... | @@ -2665,23 +2698,16 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2665,23 +2698,16 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2665 | static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; | 2698 | static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; |
| 2666 | static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; | 2699 | static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; |
| 2667 | | 2700 | |
| 2668 | bool is_vector = type_entry->id == ZigTypeIdVector; | | |
| 2669 | bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); | 2701 | bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); |
| 2670 | AddSubMul add_sub_mul = | 2702 | AddSubMul add_sub_mul = |
| 2671 | op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : | 2703 | op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : |
| 2672 | op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub : | 2704 | op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub : |
| 2673 | AddSubMulMul; | 2705 | AddSubMulMul; |
| 2674 | | 2706 | |
| 2675 | // The code that is generated for vectors and scalars are the same, | 2707 | if (scalar_type->id == ZigTypeIdPointer) { |
| 2676 | // so we can just set type_entry to the vectors elem_type an avoid | 2708 | assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown); |
| 2677 | // a lot of repeated code. | | |
| 2678 | if (is_vector) | | |
| 2679 | type_entry = type_entry->data.vector.elem_type; | | |
| 2680 | | | |
| 2681 | if (type_entry->id == ZigTypeIdPointer) { | | |
| 2682 | assert(type_entry->data.pointer.ptr_len == PtrLenUnknown); | | |
| 2683 | LLVMValueRef subscript_value; | 2709 | LLVMValueRef subscript_value; |
| 2684 | if (is_vector) | 2710 | if (operand_type->id == ZigTypeIdVector) |
| 2685 | zig_panic("TODO: Implement vector operations on pointers."); | 2711 | zig_panic("TODO: Implement vector operations on pointers."); |
| 2686 | | 2712 | |
| 2687 | switch (add_sub_mul) { | 2713 | switch (add_sub_mul) { |
| ... | @@ -2697,17 +2723,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2697,17 +2723,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2697 | | 2723 | |
| 2698 | // TODO runtime safety | 2724 | // TODO runtime safety |
| 2699 | return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, ""); | 2725 | return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, ""); |
| 2700 | } else if (type_entry->id == ZigTypeIdFloat) { | 2726 | } else if (scalar_type->id == ZigTypeIdFloat) { |
| 2701 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | 2727 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); |
| 2702 | return float_op[add_sub_mul](g->builder, op1_value, op2_value, ""); | 2728 | return float_op[add_sub_mul](g->builder, op1_value, op2_value, ""); |
| 2703 | } else if (type_entry->id == ZigTypeIdInt) { | 2729 | } else if (scalar_type->id == ZigTypeIdInt) { |
| 2704 | if (is_wrapping) { | 2730 | if (is_wrapping) { |
| 2705 | return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, ""); | 2731 | return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, ""); |
| 2706 | } else if (want_runtime_safety) { | 2732 | } else if (want_runtime_safety) { |
| 2707 | if (is_vector) | 2733 | return gen_overflow_op(g, operand_type, add_sub_mul, op1_value, op2_value); |
| 2708 | zig_panic("TODO: Implement runtime safety vector operations."); | 2734 | } else if (scalar_type->data.integral.is_signed) { |
| 2709 | return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value); | | |
| 2710 | } else if (type_entry->data.integral.is_signed) { | | |
| 2711 | return signed_op[add_sub_mul](g->builder, op1_value, op2_value, ""); | 2735 | return signed_op[add_sub_mul](g->builder, op1_value, op2_value, ""); |
| 2712 | } else { | 2736 | } else { |
| 2713 | return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, ""); | 2737 | return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, ""); |
| ... | @@ -2725,15 +2749,14 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2725,15 +2749,14 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2725 | case IrBinOpBitShiftLeftLossy: | 2749 | case IrBinOpBitShiftLeftLossy: |
| 2726 | case IrBinOpBitShiftLeftExact: | 2750 | case IrBinOpBitShiftLeftExact: |
| 2727 | { | 2751 | { |
| 2728 | assert(type_entry->id == ZigTypeIdInt); | 2752 | assert(scalar_type->id == ZigTypeIdInt); |
| 2729 | LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, | 2753 | LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, scalar_type, op2_value); |
| 2730 | type_entry, op2_value); | | |
| 2731 | bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); | 2754 | bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); |
| 2732 | if (is_sloppy) { | 2755 | if (is_sloppy) { |
| 2733 | return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); | 2756 | return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); |
| 2734 | } else if (want_runtime_safety) { | 2757 | } else if (want_runtime_safety) { |
| 2735 | return gen_overflow_shl_op(g, type_entry, op1_value, op2_casted); | 2758 | return gen_overflow_shl_op(g, scalar_type, op1_value, op2_casted); |
| 2736 | } else if (type_entry->data.integral.is_signed) { | 2759 | } else if (scalar_type->data.integral.is_signed) { |
| 2737 | return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); | 2760 | return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); |
| 2738 | } else { | 2761 | } else { |
| 2739 | return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, ""); | 2762 | return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, ""); |
| ... | @@ -2742,19 +2765,18 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2742,19 +2765,18 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2742 | case IrBinOpBitShiftRightLossy: | 2765 | case IrBinOpBitShiftRightLossy: |
| 2743 | case IrBinOpBitShiftRightExact: | 2766 | case IrBinOpBitShiftRightExact: |
| 2744 | { | 2767 | { |
| 2745 | assert(type_entry->id == ZigTypeIdInt); | 2768 | assert(scalar_type->id == ZigTypeIdInt); |
| 2746 | LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, | 2769 | LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, scalar_type, op2_value); |
| 2747 | type_entry, op2_value); | | |
| 2748 | bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy); | 2770 | bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy); |
| 2749 | if (is_sloppy) { | 2771 | if (is_sloppy) { |
| 2750 | if (type_entry->data.integral.is_signed) { | 2772 | if (scalar_type->data.integral.is_signed) { |
| 2751 | return LLVMBuildAShr(g->builder, op1_value, op2_casted, ""); | 2773 | return LLVMBuildAShr(g->builder, op1_value, op2_casted, ""); |
| 2752 | } else { | 2774 | } else { |
| 2753 | return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); | 2775 | return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); |
| 2754 | } | 2776 | } |
| 2755 | } else if (want_runtime_safety) { | 2777 | } else if (want_runtime_safety) { |
| 2756 | return gen_overflow_shr_op(g, type_entry, op1_value, op2_casted); | 2778 | return gen_overflow_shr_op(g, scalar_type, op1_value, op2_casted); |
| 2757 | } else if (type_entry->data.integral.is_signed) { | 2779 | } else if (scalar_type->data.integral.is_signed) { |
| 2758 | return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); | 2780 | return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); |
| 2759 | } else { | 2781 | } else { |
| 2760 | return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, ""); | 2782 | return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, ""); |
| ... | @@ -2762,22 +2784,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2762,22 +2784,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2762 | } | 2784 | } |
| 2763 | case IrBinOpDivUnspecified: | 2785 | case IrBinOpDivUnspecified: |
| 2764 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 2786 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 2765 | op1_value, op2_value, type_entry, DivKindFloat); | 2787 | op1_value, op2_value, scalar_type, DivKindFloat); |
| 2766 | case IrBinOpDivExact: | 2788 | case IrBinOpDivExact: |
| 2767 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 2789 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 2768 | op1_value, op2_value, type_entry, DivKindExact); | 2790 | op1_value, op2_value, scalar_type, DivKindExact); |
| 2769 | case IrBinOpDivTrunc: | 2791 | case IrBinOpDivTrunc: |
| 2770 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 2792 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 2771 | op1_value, op2_value, type_entry, DivKindTrunc); | 2793 | op1_value, op2_value, scalar_type, DivKindTrunc); |
| 2772 | case IrBinOpDivFloor: | 2794 | case IrBinOpDivFloor: |
| 2773 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 2795 | return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 2774 | op1_value, op2_value, type_entry, DivKindFloor); | 2796 | op1_value, op2_value, scalar_type, DivKindFloor); |
| 2775 | case IrBinOpRemRem: | 2797 | case IrBinOpRemRem: |
| 2776 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 2798 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 2777 | op1_value, op2_value, type_entry, RemKindRem); | 2799 | op1_value, op2_value, scalar_type, RemKindRem); |
| 2778 | case IrBinOpRemMod: | 2800 | case IrBinOpRemMod: |
| 2779 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 2801 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 2780 | op1_value, op2_value, type_entry, RemKindMod); | 2802 | op1_value, op2_value, scalar_type, RemKindMod); |
| 2781 | } | 2803 | } |
| 2782 | zig_unreachable(); | 2804 | zig_unreachable(); |
| 2783 | } | 2805 | } |