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