| ... | ... | @@ -1773,25 +1773,46 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z |
| 1773 | 1773 | } |
| 1774 | 1774 | } |
| 1775 | 1775 | |
| 1776 | typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); |
| 1777 | // These are lookup table using the AddSubMul enum as the lookup. |
| 1778 | // If AddSubMul ever changes, then these tables will be out of |
| 1779 | // date. |
| 1780 | static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; |
| 1781 | static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; |
| 1782 | static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; |
| 1783 | static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; |
| 1784 | |
| 1776 | 1785 | static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op, |
| 1777 | 1786 | LLVMValueRef val1, LLVMValueRef val2) |
| 1778 | 1787 | { |
| 1779 | | LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); |
| 1780 | | LLVMValueRef params[] = { |
| 1781 | | val1, |
| 1782 | | val2, |
| 1783 | | }; |
| 1784 | | LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 1785 | | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 1786 | | |
| 1787 | 1788 | LLVMValueRef overflow_bit; |
| 1789 | LLVMValueRef result; |
| 1790 | |
| 1788 | 1791 | 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); |
| 1792 | ZigType *int_type = operand_type->data.vector.elem_type; |
| 1793 | assert(int_type->id == ZigTypeIdInt); |
| 1794 | LLVMTypeRef one_more_bit_int = LLVMIntType(int_type->data.integral.bit_count + 1); |
| 1795 | LLVMTypeRef one_more_bit_int_vector = LLVMVectorType(one_more_bit_int, operand_type->data.vector.len); |
| 1796 | const auto buildExtFn = int_type->data.integral.is_signed ? LLVMBuildSExt : LLVMBuildZExt; |
| 1797 | LLVMValueRef extended1 = buildExtFn(g->builder, val1, one_more_bit_int_vector, ""); |
| 1798 | LLVMValueRef extended2 = buildExtFn(g->builder, val2, one_more_bit_int_vector, ""); |
| 1799 | LLVMValueRef extended_result = wrap_op[op](g->builder, extended1, extended2, ""); |
| 1800 | result = LLVMBuildTrunc(g->builder, extended_result, operand_type->type_ref, ""); |
| 1801 | |
| 1802 | LLVMValueRef re_extended_result = buildExtFn(g->builder, result, one_more_bit_int_vector, ""); |
| 1803 | LLVMValueRef overflow_vector = LLVMBuildICmp(g->builder, LLVMIntNE, extended_result, re_extended_result, ""); |
| 1804 | LLVMTypeRef bitcast_int_type = LLVMIntType(operand_type->data.vector.len); |
| 1805 | LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bitcast_int_type, ""); |
| 1806 | LLVMValueRef zero = LLVMConstNull(bitcast_int_type); |
| 1793 | 1807 | overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, bitcasted_overflow, zero, ""); |
| 1794 | 1808 | } else { |
| 1809 | LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); |
| 1810 | LLVMValueRef params[] = { |
| 1811 | val1, |
| 1812 | val2, |
| 1813 | }; |
| 1814 | LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 1815 | result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 1795 | 1816 | overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); |
| 1796 | 1817 | } |
| 1797 | 1818 | |
| ... | ... | @@ -2623,8 +2644,6 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2623 | 2644 | |
| 2624 | 2645 | } |
| 2625 | 2646 | |
| 2626 | | typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); |
| 2627 | | |
| 2628 | 2647 | static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2629 | 2648 | IrInstructionBinOp *bin_op_instruction) |
| 2630 | 2649 | { |
| ... | ... | @@ -2690,14 +2709,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2690 | 2709 | case IrBinOpAddWrap: |
| 2691 | 2710 | case IrBinOpSub: |
| 2692 | 2711 | case IrBinOpSubWrap: { |
| 2693 | | // These are lookup table using the AddSubMul enum as the lookup. |
| 2694 | | // If AddSubMul ever changes, then these tables will be out of |
| 2695 | | // date. |
| 2696 | | static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; |
| 2697 | | static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; |
| 2698 | | static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; |
| 2699 | | static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; |
| 2700 | | |
| 2701 | 2712 | bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); |
| 2702 | 2713 | AddSubMul add_sub_mul = |
| 2703 | 2714 | op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : |