| ... | ... | @@ -816,6 +816,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 816 | 816 | IrInstruction *op2 = bin_op_instruction->op2; |
| 817 | 817 | |
| 818 | 818 | assert(op1->value.type == op2->value.type); |
| 819 | TypeTableEntry *canon_type = get_underlying_type(op1->value.type); |
| 819 | 820 | |
| 820 | 821 | bool want_debug_safety = bin_op_instruction->safety_check_on && |
| 821 | 822 | ir_want_debug_safety(g, &bin_op_instruction->base); |
| ... | ... | @@ -837,22 +838,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 837 | 838 | case IrBinOpCmpGreaterThan: |
| 838 | 839 | case IrBinOpCmpLessOrEq: |
| 839 | 840 | case IrBinOpCmpGreaterOrEq: |
| 840 | | if (op1->value.type->id == TypeTableEntryIdFloat) { |
| 841 | if (canon_type->id == TypeTableEntryIdFloat) { |
| 841 | 842 | LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); |
| 842 | 843 | return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); |
| 843 | | } else if (op1->value.type->id == TypeTableEntryIdInt) { |
| 844 | | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->value.type->data.integral.is_signed); |
| 844 | } else if (canon_type->id == TypeTableEntryIdInt) { |
| 845 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, canon_type->data.integral.is_signed); |
| 845 | 846 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| 846 | | } else if (op1->value.type->id == TypeTableEntryIdEnum) { |
| 847 | | if (op1->value.type->data.enumeration.gen_field_count == 0) { |
| 847 | } else if (canon_type->id == TypeTableEntryIdEnum) { |
| 848 | if (canon_type->data.enumeration.gen_field_count == 0) { |
| 848 | 849 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); |
| 849 | 850 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| 850 | 851 | } else { |
| 851 | 852 | zig_unreachable(); |
| 852 | 853 | } |
| 853 | | } else if (op1->value.type->id == TypeTableEntryIdPureError || |
| 854 | | op1->value.type->id == TypeTableEntryIdPointer || |
| 855 | | op1->value.type->id == TypeTableEntryIdBool) |
| 854 | } else if (canon_type->id == TypeTableEntryIdPureError || |
| 855 | canon_type->id == TypeTableEntryIdPointer || |
| 856 | canon_type->id == TypeTableEntryIdBool) |
| 856 | 857 | { |
| 857 | 858 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); |
| 858 | 859 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| ... | ... | @@ -861,15 +862,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 861 | 862 | } |
| 862 | 863 | case IrBinOpAdd: |
| 863 | 864 | case IrBinOpAddWrap: |
| 864 | | if (op1->value.type->id == TypeTableEntryIdFloat) { |
| 865 | if (canon_type->id == TypeTableEntryIdFloat) { |
| 865 | 866 | return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); |
| 866 | | } else if (op1->value.type->id == TypeTableEntryIdInt) { |
| 867 | } else if (canon_type->id == TypeTableEntryIdInt) { |
| 867 | 868 | bool is_wrapping = (op_id == IrBinOpAddWrap); |
| 868 | 869 | if (is_wrapping) { |
| 869 | 870 | return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); |
| 870 | 871 | } else if (want_debug_safety) { |
| 871 | | return gen_overflow_op(g, op1->value.type, AddSubMulAdd, op1_value, op2_value); |
| 872 | | } else if (op1->value.type->data.integral.is_signed) { |
| 872 | return gen_overflow_op(g, canon_type, AddSubMulAdd, op1_value, op2_value); |
| 873 | } else if (canon_type->data.integral.is_signed) { |
| 873 | 874 | return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); |
| 874 | 875 | } else { |
| 875 | 876 | return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); |
| ... | ... | @@ -886,36 +887,36 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 886 | 887 | case IrBinOpBitShiftLeft: |
| 887 | 888 | case IrBinOpBitShiftLeftWrap: |
| 888 | 889 | { |
| 889 | | assert(op1->value.type->id == TypeTableEntryIdInt); |
| 890 | assert(canon_type->id == TypeTableEntryIdInt); |
| 890 | 891 | bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap); |
| 891 | 892 | if (is_wrapping) { |
| 892 | 893 | return LLVMBuildShl(g->builder, op1_value, op2_value, ""); |
| 893 | 894 | } else if (want_debug_safety) { |
| 894 | | return gen_overflow_shl_op(g, op1->value.type, op1_value, op2_value); |
| 895 | | } else if (op1->value.type->data.integral.is_signed) { |
| 895 | return gen_overflow_shl_op(g, canon_type, op1_value, op2_value); |
| 896 | } else if (canon_type->data.integral.is_signed) { |
| 896 | 897 | return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, ""); |
| 897 | 898 | } else { |
| 898 | 899 | return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, ""); |
| 899 | 900 | } |
| 900 | 901 | } |
| 901 | 902 | case IrBinOpBitShiftRight: |
| 902 | | assert(op1->value.type->id == TypeTableEntryIdInt); |
| 903 | | if (op1->value.type->data.integral.is_signed) { |
| 903 | assert(canon_type->id == TypeTableEntryIdInt); |
| 904 | if (canon_type->data.integral.is_signed) { |
| 904 | 905 | return LLVMBuildAShr(g->builder, op1_value, op2_value, ""); |
| 905 | 906 | } else { |
| 906 | 907 | return LLVMBuildLShr(g->builder, op1_value, op2_value, ""); |
| 907 | 908 | } |
| 908 | 909 | case IrBinOpSub: |
| 909 | 910 | case IrBinOpSubWrap: |
| 910 | | if (op1->value.type->id == TypeTableEntryIdFloat) { |
| 911 | if (canon_type->id == TypeTableEntryIdFloat) { |
| 911 | 912 | return LLVMBuildFSub(g->builder, op1_value, op2_value, ""); |
| 912 | | } else if (op1->value.type->id == TypeTableEntryIdInt) { |
| 913 | } else if (canon_type->id == TypeTableEntryIdInt) { |
| 913 | 914 | bool is_wrapping = (op_id == IrBinOpSubWrap); |
| 914 | 915 | if (is_wrapping) { |
| 915 | 916 | return LLVMBuildSub(g->builder, op1_value, op2_value, ""); |
| 916 | 917 | } else if (want_debug_safety) { |
| 917 | | return gen_overflow_op(g, op1->value.type, AddSubMulSub, op1_value, op2_value); |
| 918 | | } else if (op1->value.type->data.integral.is_signed) { |
| 918 | return gen_overflow_op(g, canon_type, AddSubMulSub, op1_value, op2_value); |
| 919 | } else if (canon_type->data.integral.is_signed) { |
| 919 | 920 | return LLVMBuildNSWSub(g->builder, op1_value, op2_value, ""); |
| 920 | 921 | } else { |
| 921 | 922 | return LLVMBuildNUWSub(g->builder, op1_value, op2_value, ""); |
| ... | ... | @@ -925,15 +926,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 925 | 926 | } |
| 926 | 927 | case IrBinOpMult: |
| 927 | 928 | case IrBinOpMultWrap: |
| 928 | | if (op1->value.type->id == TypeTableEntryIdFloat) { |
| 929 | if (canon_type->id == TypeTableEntryIdFloat) { |
| 929 | 930 | return LLVMBuildFMul(g->builder, op1_value, op2_value, ""); |
| 930 | | } else if (op1->value.type->id == TypeTableEntryIdInt) { |
| 931 | } else if (canon_type->id == TypeTableEntryIdInt) { |
| 931 | 932 | bool is_wrapping = (op_id == IrBinOpMultWrap); |
| 932 | 933 | if (is_wrapping) { |
| 933 | 934 | return LLVMBuildMul(g->builder, op1_value, op2_value, ""); |
| 934 | 935 | } else if (want_debug_safety) { |
| 935 | | return gen_overflow_op(g, op1->value.type, AddSubMulMul, op1_value, op2_value); |
| 936 | | } else if (op1->value.type->data.integral.is_signed) { |
| 936 | return gen_overflow_op(g, canon_type, AddSubMulMul, op1_value, op2_value); |
| 937 | } else if (canon_type->data.integral.is_signed) { |
| 937 | 938 | return LLVMBuildNSWMul(g->builder, op1_value, op2_value, ""); |
| 938 | 939 | } else { |
| 939 | 940 | return LLVMBuildNUWMul(g->builder, op1_value, op2_value, ""); |
| ... | ... | @@ -942,13 +943,13 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 942 | 943 | zig_unreachable(); |
| 943 | 944 | } |
| 944 | 945 | case IrBinOpDiv: |
| 945 | | return gen_div(g, want_debug_safety, op1_value, op2_value, op1->value.type, false); |
| 946 | return gen_div(g, want_debug_safety, op1_value, op2_value, canon_type, false); |
| 946 | 947 | case IrBinOpMod: |
| 947 | | if (op1->value.type->id == TypeTableEntryIdFloat) { |
| 948 | if (canon_type->id == TypeTableEntryIdFloat) { |
| 948 | 949 | return LLVMBuildFRem(g->builder, op1_value, op2_value, ""); |
| 949 | 950 | } else { |
| 950 | | assert(op1->value.type->id == TypeTableEntryIdInt); |
| 951 | | if (op1->value.type->data.integral.is_signed) { |
| 951 | assert(canon_type->id == TypeTableEntryIdInt); |
| 952 | if (canon_type->data.integral.is_signed) { |
| 952 | 953 | return LLVMBuildSRem(g->builder, op1_value, op2_value, ""); |
| 953 | 954 | } else { |
| 954 | 955 | return LLVMBuildURem(g->builder, op1_value, op2_value, ""); |