Commit e00eec1c29

Andrew Kelley <superjoe30@gmail.com>
2017-02-03 18:09:13
typedefs work for binary math operations
1 parent aae1685
Changed files (4)
src/codegen.cpp
@@ -816,6 +816,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
     IrInstruction *op2 = bin_op_instruction->op2;
 
     assert(op1->value.type == op2->value.type);
+    TypeTableEntry *canon_type = get_underlying_type(op1->value.type);
 
     bool want_debug_safety = bin_op_instruction->safety_check_on &&
         ir_want_debug_safety(g, &bin_op_instruction->base);
@@ -837,22 +838,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
         case IrBinOpCmpGreaterThan:
         case IrBinOpCmpLessOrEq:
         case IrBinOpCmpGreaterOrEq:
-            if (op1->value.type->id == TypeTableEntryIdFloat) {
+            if (canon_type->id == TypeTableEntryIdFloat) {
                 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
                 return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");
-            } else if (op1->value.type->id == TypeTableEntryIdInt) {
-                LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->value.type->data.integral.is_signed);
+            } else if (canon_type->id == TypeTableEntryIdInt) {
+                LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, canon_type->data.integral.is_signed);
                 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
-            } else if (op1->value.type->id == TypeTableEntryIdEnum) {
-                if (op1->value.type->data.enumeration.gen_field_count == 0) {
+            } else if (canon_type->id == TypeTableEntryIdEnum) {
+                if (canon_type->data.enumeration.gen_field_count == 0) {
                     LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
                     return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
                 } else {
                     zig_unreachable();
                 }
-            } else if (op1->value.type->id == TypeTableEntryIdPureError ||
-                    op1->value.type->id == TypeTableEntryIdPointer ||
-                    op1->value.type->id == TypeTableEntryIdBool)
+            } else if (canon_type->id == TypeTableEntryIdPureError ||
+                    canon_type->id == TypeTableEntryIdPointer ||
+                    canon_type->id == TypeTableEntryIdBool)
             {
                 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
                 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
@@ -861,15 +862,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
             }
         case IrBinOpAdd:
         case IrBinOpAddWrap:
-            if (op1->value.type->id == TypeTableEntryIdFloat) {
+            if (canon_type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
-            } else if (op1->value.type->id == TypeTableEntryIdInt) {
+            } else if (canon_type->id == TypeTableEntryIdInt) {
                 bool is_wrapping = (op_id == IrBinOpAddWrap);
                 if (is_wrapping) {
                     return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_op(g, op1->value.type, AddSubMulAdd, op1_value, op2_value);
-                } else if (op1->value.type->data.integral.is_signed) {
+                    return gen_overflow_op(g, canon_type, AddSubMulAdd, op1_value, op2_value);
+                } else if (canon_type->data.integral.is_signed) {
                     return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
@@ -886,36 +887,36 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
         case IrBinOpBitShiftLeft:
         case IrBinOpBitShiftLeftWrap:
             {
-                assert(op1->value.type->id == TypeTableEntryIdInt);
+                assert(canon_type->id == TypeTableEntryIdInt);
                 bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
                 if (is_wrapping) {
                     return LLVMBuildShl(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_shl_op(g, op1->value.type, op1_value, op2_value);
-                } else if (op1->value.type->data.integral.is_signed) {
+                    return gen_overflow_shl_op(g, canon_type, op1_value, op2_value);
+                } else if (canon_type->data.integral.is_signed) {
                     return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
                 } else {
                     return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
                 }
             }
         case IrBinOpBitShiftRight:
-            assert(op1->value.type->id == TypeTableEntryIdInt);
-            if (op1->value.type->data.integral.is_signed) {
+            assert(canon_type->id == TypeTableEntryIdInt);
+            if (canon_type->data.integral.is_signed) {
                 return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
             } else {
                 return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
             }
         case IrBinOpSub:
         case IrBinOpSubWrap:
-            if (op1->value.type->id == TypeTableEntryIdFloat) {
+            if (canon_type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
-            } else if (op1->value.type->id == TypeTableEntryIdInt) {
+            } else if (canon_type->id == TypeTableEntryIdInt) {
                 bool is_wrapping = (op_id == IrBinOpSubWrap);
                 if (is_wrapping) {
                     return LLVMBuildSub(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_op(g, op1->value.type, AddSubMulSub, op1_value, op2_value);
-                } else if (op1->value.type->data.integral.is_signed) {
+                    return gen_overflow_op(g, canon_type, AddSubMulSub, op1_value, op2_value);
+                } else if (canon_type->data.integral.is_signed) {
                     return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
@@ -925,15 +926,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
             }
         case IrBinOpMult:
         case IrBinOpMultWrap:
-            if (op1->value.type->id == TypeTableEntryIdFloat) {
+            if (canon_type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
-            } else if (op1->value.type->id == TypeTableEntryIdInt) {
+            } else if (canon_type->id == TypeTableEntryIdInt) {
                 bool is_wrapping = (op_id == IrBinOpMultWrap);
                 if (is_wrapping) {
                     return LLVMBuildMul(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_op(g, op1->value.type, AddSubMulMul, op1_value, op2_value);
-                } else if (op1->value.type->data.integral.is_signed) {
+                    return gen_overflow_op(g, canon_type, AddSubMulMul, op1_value, op2_value);
+                } else if (canon_type->data.integral.is_signed) {
                     return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
@@ -942,13 +943,13 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
                 zig_unreachable();
             }
         case IrBinOpDiv:
-            return gen_div(g, want_debug_safety, op1_value, op2_value, op1->value.type, false);
+            return gen_div(g, want_debug_safety, op1_value, op2_value, canon_type, false);
         case IrBinOpMod:
-            if (op1->value.type->id == TypeTableEntryIdFloat) {
+            if (canon_type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
             } else {
-                assert(op1->value.type->id == TypeTableEntryIdInt);
-                if (op1->value.type->data.integral.is_signed) {
+                assert(canon_type->id == TypeTableEntryIdInt);
+                if (canon_type->data.integral.is_signed) {
                     return LLVMBuildSRem(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildURem(g->builder, op1_value, op2_value, "");
src/ir.cpp
@@ -7302,8 +7302,8 @@ static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
     return 0;
 }
 
-static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
-        IrBinOp op_id, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
+static int ir_eval_math_op(TypeTableEntry *canon_type, ConstExprValue *op1_val,
+        IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val)
 {
     switch (op_id) {
         case IrBinOpInvalid:
@@ -7319,33 +7319,33 @@ static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
         case IrBinOpArrayMult:
             zig_unreachable();
         case IrBinOpBinOr:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, canon_type, false);
         case IrBinOpBinXor:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, canon_type, false);
         case IrBinOpBinAnd:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, canon_type, false);
         case IrBinOpBitShiftLeft:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, canon_type, false);
         case IrBinOpBitShiftLeftWrap:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, canon_type, true);
         case IrBinOpBitShiftRight:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, canon_type, false);
         case IrBinOpAdd:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, canon_type, false);
         case IrBinOpAddWrap:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, canon_type, true);
         case IrBinOpSub:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, canon_type, false);
         case IrBinOpSubWrap:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, canon_type, true);
         case IrBinOpMult:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, canon_type, false);
         case IrBinOpMultWrap:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, canon_type, true);
         case IrBinOpDiv:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, canon_type, false);
         case IrBinOpMod:
-            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false);
+            return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, canon_type, false);
     }
     zig_unreachable();
 }
@@ -7357,14 +7357,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
     TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
     if (resolved_type->id == TypeTableEntryIdInvalid)
         return resolved_type;
+    TypeTableEntry *canon_resolved_type = get_underlying_type(resolved_type);
     IrBinOp op_id = bin_op_instruction->op_id;
 
-    if (resolved_type->id == TypeTableEntryIdInt ||
-        resolved_type->id == TypeTableEntryIdNumLitInt)
+    if (canon_resolved_type->id == TypeTableEntryIdInt ||
+        canon_resolved_type->id == TypeTableEntryIdNumLitInt)
     {
         // int
-    } else if ((resolved_type->id == TypeTableEntryIdFloat ||
-                resolved_type->id == TypeTableEntryIdNumLitFloat) &&
+    } else if ((canon_resolved_type->id == TypeTableEntryIdFloat ||
+                canon_resolved_type->id == TypeTableEntryIdNumLitFloat) &&
         (op_id == IrBinOpAdd ||
             op_id == IrBinOpSub ||
             op_id == IrBinOpMult ||
@@ -7398,7 +7399,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
         bin_op_instruction->base.other = &bin_op_instruction->base;
 
         int err;
-        if ((err = ir_eval_math_op(op1_val, resolved_type, op_id, op2_val, resolved_type, out_val))) {
+        if ((err = ir_eval_math_op(canon_resolved_type, op1_val, op_id, op2_val, out_val))) {
             if (err == ErrorDivByZero) {
                 ir_add_error_node(ira, bin_op_instruction->base.source_node,
                         buf_sprintf("division by zero is undefined"));
test/cases/typedef.zig
@@ -0,0 +1,12 @@
+const assert = @import("std").debug.assert;
+
+type int = u8;
+
+fn add(a: int, b: int) -> int {
+    a + b
+}
+fn typedef() {
+    @setFnTest(this);
+
+    assert(add(12, 34) == 46);
+}
test/self_hosted.zig
@@ -29,6 +29,7 @@ const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");
 const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");
 const test_this = @import("cases/this.zig");
 const test_try = @import("cases/try.zig");
+const test_typedef = @import("cases/typedef.zig");
 const test_undefined = @import("cases/undefined.zig");
 const test_var_args = @import("cases/var_args.zig");
 const test_while = @import("cases/while.zig");