authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-03 12:09:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-03 12:09:13-05:00
loge00eec1c299ccc721f4272a506321939be7094f1
treea1069f5a6fa80841338bcd5d4a77a95b2ecfa03b
parentaae168550fa3d8b21478deb7198513dad8cc0b37

typedefs work for binary math operations


4 files changed, 65 insertions(+), 50 deletions(-)

src/codegen.cpp+30-29
...@@ -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;
817817
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);
819820
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, "");
src/ir.cpp+22-21
...@@ -7302,8 +7302,8 @@ static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,...@@ -7302,8 +7302,8 @@ static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
7302 return 0;7302 return 0;
7303}7303}
73047304
7305static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,7305static int ir_eval_math_op(TypeTableEntry *canon_type, ConstExprValue *op1_val,
7306 IrBinOp op_id, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)7306 IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val)
7307{7307{
7308 switch (op_id) {7308 switch (op_id) {
7309 case IrBinOpInvalid:7309 case IrBinOpInvalid:
...@@ -7319,33 +7319,33 @@ static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -7319,33 +7319,33 @@ static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
7319 case IrBinOpArrayMult:7319 case IrBinOpArrayMult:
7320 zig_unreachable();7320 zig_unreachable();
7321 case IrBinOpBinOr:7321 case IrBinOpBinOr:
7322 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false);7322 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, canon_type, false);
7323 case IrBinOpBinXor:7323 case IrBinOpBinXor:
7324 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false);7324 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, canon_type, false);
7325 case IrBinOpBinAnd:7325 case IrBinOpBinAnd:
7326 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false);7326 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, canon_type, false);
7327 case IrBinOpBitShiftLeft:7327 case IrBinOpBitShiftLeft:
7328 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false);7328 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, canon_type, false);
7329 case IrBinOpBitShiftLeftWrap:7329 case IrBinOpBitShiftLeftWrap:
7330 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true);7330 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, canon_type, true);
7331 case IrBinOpBitShiftRight:7331 case IrBinOpBitShiftRight:
7332 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false);7332 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, canon_type, false);
7333 case IrBinOpAdd:7333 case IrBinOpAdd:
7334 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false);7334 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, canon_type, false);
7335 case IrBinOpAddWrap:7335 case IrBinOpAddWrap:
7336 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true);7336 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, canon_type, true);
7337 case IrBinOpSub:7337 case IrBinOpSub:
7338 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false);7338 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, canon_type, false);
7339 case IrBinOpSubWrap:7339 case IrBinOpSubWrap:
7340 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true);7340 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, canon_type, true);
7341 case IrBinOpMult:7341 case IrBinOpMult:
7342 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false);7342 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, canon_type, false);
7343 case IrBinOpMultWrap:7343 case IrBinOpMultWrap:
7344 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true);7344 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, canon_type, true);
7345 case IrBinOpDiv:7345 case IrBinOpDiv:
7346 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false);7346 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, canon_type, false);
7347 case IrBinOpMod:7347 case IrBinOpMod:
7348 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false);7348 return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, canon_type, false);
7349 }7349 }
7350 zig_unreachable();7350 zig_unreachable();
7351}7351}
...@@ -7357,14 +7357,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -7357,14 +7357,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
7357 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);7357 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
7358 if (resolved_type->id == TypeTableEntryIdInvalid)7358 if (resolved_type->id == TypeTableEntryIdInvalid)
7359 return resolved_type;7359 return resolved_type;
7360 TypeTableEntry *canon_resolved_type = get_underlying_type(resolved_type);
7360 IrBinOp op_id = bin_op_instruction->op_id;7361 IrBinOp op_id = bin_op_instruction->op_id;
73617362
7362 if (resolved_type->id == TypeTableEntryIdInt ||7363 if (canon_resolved_type->id == TypeTableEntryIdInt ||
7363 resolved_type->id == TypeTableEntryIdNumLitInt)7364 canon_resolved_type->id == TypeTableEntryIdNumLitInt)
7364 {7365 {
7365 // int7366 // int
7366 } else if ((resolved_type->id == TypeTableEntryIdFloat ||7367 } else if ((canon_resolved_type->id == TypeTableEntryIdFloat ||
7367 resolved_type->id == TypeTableEntryIdNumLitFloat) &&7368 canon_resolved_type->id == TypeTableEntryIdNumLitFloat) &&
7368 (op_id == IrBinOpAdd ||7369 (op_id == IrBinOpAdd ||
7369 op_id == IrBinOpSub ||7370 op_id == IrBinOpSub ||
7370 op_id == IrBinOpMult ||7371 op_id == IrBinOpMult ||
...@@ -7398,7 +7399,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -7398,7 +7399,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
7398 bin_op_instruction->base.other = &bin_op_instruction->base;7399 bin_op_instruction->base.other = &bin_op_instruction->base;
73997400
7400 int err;7401 int err;
7401 if ((err = ir_eval_math_op(op1_val, resolved_type, op_id, op2_val, resolved_type, out_val))) {7402 if ((err = ir_eval_math_op(canon_resolved_type, op1_val, op_id, op2_val, out_val))) {
7402 if (err == ErrorDivByZero) {7403 if (err == ErrorDivByZero) {
7403 ir_add_error_node(ira, bin_op_instruction->base.source_node,7404 ir_add_error_node(ira, bin_op_instruction->base.source_node,
7404 buf_sprintf("division by zero is undefined"));7405 buf_sprintf("division by zero is undefined"));
test/cases/typedef.zig created+12
...@@ -0,0 +1,12 @@
1const assert = @import("std").debug.assert;
2
3type int = u8;
4
5fn add(a: int, b: int) -> int {
6 a + b
7}
8fn typedef() {
9 @setFnTest(this);
10
11 assert(add(12, 34) == 46);
12}
test/self_hosted.zig+1
...@@ -29,6 +29,7 @@ const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");...@@ -29,6 +29,7 @@ const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");
29const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");29const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");
30const test_this = @import("cases/this.zig");30const test_this = @import("cases/this.zig");
31const test_try = @import("cases/try.zig");31const test_try = @import("cases/try.zig");
32const test_typedef = @import("cases/typedef.zig");
32const test_undefined = @import("cases/undefined.zig");33const test_undefined = @import("cases/undefined.zig");
33const test_var_args = @import("cases/var_args.zig");34const test_var_args = @import("cases/var_args.zig");
34const test_while = @import("cases/while.zig");35const test_while = @import("cases/while.zig");