Commit 4664f793dc

Andrew Kelley <superjoe30@gmail.com>
2016-12-26 08:36:04
IR: pass enumToInt test
1 parent 1b5d187
src/all_types.hpp
@@ -429,14 +429,12 @@ enum CastOp {
     CastOpNoop, // fn call expr is a cast, but does nothing
     CastOpPtrToInt,
     CastOpIntToPtr,
-    CastOpWidenOrShorten,
     CastOpErrToInt,
     CastOpIntToFloat,
     CastOpFloatToInt,
     CastOpBoolToInt,
     CastOpResizeSlice,
     CastOpIntToEnum,
-    CastOpEnumToInt,
     CastOpBytesToSlice,
 };
 
@@ -1454,6 +1452,7 @@ enum IrInstructionId {
     IrInstructionIdTestComptime,
     IrInstructionIdInitEnum,
     IrInstructionIdPointerReinterpret,
+    IrInstructionIdWidenOrShorten,
 };
 
 struct IrInstruction {
@@ -2096,6 +2095,12 @@ struct IrInstructionPointerReinterpret {
     IrInstruction *ptr;
 };
 
+struct IrInstructionWidenOrShorten {
+    IrInstruction base;
+
+    IrInstruction *target;
+};
+
 enum LValPurpose {
     LValPurposeNone,
     LValPurposeAssign,
src/codegen.cpp
@@ -973,9 +973,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
             return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
         case CastOpIntToPtr:
             return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
-        case CastOpWidenOrShorten:
-            return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
-                actual_type, wanted_type, expr_val);
         case CastOpResizeSlice:
             {
                 assert(cast_instruction->tmp_ptr);
@@ -1086,9 +1083,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
         case CastOpIntToEnum:
             return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
                     actual_type, wanted_type->data.enumeration.tag_type, expr_val);
-        case CastOpEnumToInt:
-            return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
-                    actual_type->data.enumeration.tag_type, wanted_type, expr_val);
     }
     zig_unreachable();
 }
@@ -1101,6 +1095,24 @@ static LLVMValueRef ir_render_pointer_reinterpret(CodeGen *g, IrExecutable *exec
     return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
 }
 
+static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
+        IrInstructionWidenOrShorten *instruction)
+{
+    TypeTableEntry *actual_type = instruction->target->value.type;
+    // TODO instead of this logic, use the Noop instruction to change the type from
+    // enum_tag to the underlying int type
+    TypeTableEntry *int_type;
+    if (actual_type->id == TypeTableEntryIdEnum) {
+        TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type;
+        assert(tag_type->id == TypeTableEntryIdEnumTag);
+        int_type = tag_type->data.enum_tag.int_type;
+    } else {
+        int_type = actual_type;
+    }
+    LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
+    return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), int_type,
+            instruction->base.value.type, target_val);
+}
 
 static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
         IrInstructionUnreachable *unreachable_instruction)
@@ -2309,6 +2321,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
         case IrInstructionIdPointerReinterpret:
             return ir_render_pointer_reinterpret(g, executable, (IrInstructionPointerReinterpret *)instruction);
+        case IrInstructionIdWidenOrShorten:
+            return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
         case IrInstructionIdSwitchVar:
             zig_panic("TODO render switch var instruction to LLVM");
         case IrInstructionIdContainerInitList:
src/ir.cpp
@@ -455,6 +455,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPointerReinterpr
     return IrInstructionIdPointerReinterpret;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
+    return IrInstructionIdWidenOrShorten;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -1883,6 +1887,18 @@ static IrInstruction *ir_build_pointer_reinterpret(IrBuilder *irb, Scope *scope,
     return &instruction->base;
 }
 
+static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        IrInstruction *target)
+{
+    IrInstructionWidenOrShorten *instruction = ir_build_instruction<IrInstructionWidenOrShorten>(
+            irb, scope, source_node);
+    instruction->target = target;
+
+    ir_ref_instruction(target);
+
+    return &instruction->base;
+}
+
 static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
     results[ReturnKindUnconditional] = 0;
     results[ReturnKindError] = 0;
@@ -4638,7 +4654,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
         case CastOpNoCast:
             zig_unreachable();
         case CastOpNoop:
-        case CastOpWidenOrShorten:
             *const_val = *other_val;
             const_val->type = new_type;
             break;
@@ -4684,10 +4699,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
                 const_val->special = ConstValSpecialStatic;
                 break;
             }
-        case CastOpEnumToInt:
-            bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag);
-            const_val->special = ConstValSpecialStatic;
-            break;
     }
 }
 static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
@@ -5181,6 +5192,50 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
     return result;
 }
 
+static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *target, TypeTableEntry *wanted_type)
+{
+    assert(wanted_type->id == TypeTableEntryIdInt);
+
+    if (instr_is_comptime(target)) {
+        ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+        if (!val)
+            return ira->codegen->invalid_instruction;
+        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+                source_instr->source_node, wanted_type, val->depends_on_compile_var);
+        init_const_unsigned_negative(&result->value, wanted_type, val->data.x_enum.tag, false);
+        return result;
+    }
+
+    IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, target);
+    result->value.type = wanted_type;
+    return result;
+}
+
+static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *target, TypeTableEntry *wanted_type)
+{
+    assert(wanted_type->id == TypeTableEntryIdInt || wanted_type->id == TypeTableEntryIdFloat);
+
+    if (instr_is_comptime(target)) {
+        ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+        if (!val)
+            return ira->codegen->invalid_instruction;
+        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+                source_instr->source_node, wanted_type, val->depends_on_compile_var);
+        result->value = *val;
+        result->value.type = wanted_type;
+        return result;
+    }
+
+    IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, target);
+    result->value.type = wanted_type;
+    return result;
+}
+
+
 static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
     TypeTableEntry *wanted_type, IrInstruction *value)
 {
@@ -5233,7 +5288,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         (wanted_type_canon->id == TypeTableEntryIdFloat &&
         actual_type_canon->id == TypeTableEntryIdFloat))
     {
-        return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpWidenOrShorten, false);
+        return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
     }
 
     // explicit cast from int to float
@@ -5411,7 +5466,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         actual_type->id == TypeTableEntryIdEnum &&
         actual_type->data.enumeration.gen_field_count == 0)
     {
-        return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpEnumToInt, false);
+        return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
     }
 
     // explicit cast from undefined to anything
@@ -9882,6 +9937,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
     switch (instruction->id) {
         case IrInstructionIdInvalid:
         case IrInstructionIdPointerReinterpret:
+        case IrInstructionIdWidenOrShorten:
         case IrInstructionIdStructInit:
         case IrInstructionIdStructFieldPtr:
         case IrInstructionIdEnumFieldPtr:
@@ -10188,6 +10244,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdTestComptime:
         case IrInstructionIdInitEnum:
         case IrInstructionIdPointerReinterpret:
+        case IrInstructionIdWidenOrShorten:
             return false;
         case IrInstructionIdAsm:
             {
src/ir_print.cpp
@@ -923,11 +923,17 @@ static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction)
 }
 
 static void ir_print_pointer_reinterpret(IrPrint *irp, IrInstructionPointerReinterpret *instruction) {
-    fprintf(irp->f, "(%s)(", buf_ptr(&instruction->base.value.type->name));
+    fprintf(irp->f, "@pointerReinterpret(");
     ir_print_other_instruction(irp, instruction->ptr);
     fprintf(irp->f, ")");
 }
 
+static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
+    fprintf(irp->f, "@widenOrShorten(");
+    ir_print_other_instruction(irp, instruction->target);
+    fprintf(irp->f, ")");
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -1170,6 +1176,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdPointerReinterpret:
             ir_print_pointer_reinterpret(irp, (IrInstructionPointerReinterpret *)instruction);
             break;
+        case IrInstructionIdWidenOrShorten:
+            ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
test/cases/enum_to_int.zig
@@ -1,31 +0,0 @@
-const assert = @import("std").debug.assert;
-
-enum Number {
-    Zero,
-    One,
-    Two,
-    Three,
-    Four,
-}
-
-fn enumToInt() {
-    @setFnTest(this, true);
-
-    shouldEqual(false, Number.Zero, 0);
-    shouldEqual(false, Number.One, 1);
-    shouldEqual(false, Number.Two, 2);
-    shouldEqual(false, Number.Three, 3);
-    shouldEqual(false, Number.Four, 4);
-
-    shouldEqual(true, Number.Zero, 0);
-    shouldEqual(true, Number.One, 1);
-    shouldEqual(true, Number.Two, 2);
-    shouldEqual(true, Number.Three, 3);
-    shouldEqual(true, Number.Four, 4);
-}
-
-fn shouldEqual(inline static_eval: bool, n: Number, expected: usize) {
-    @setFnStaticEval(this, static_eval);
-
-    assert(usize(n) == expected);
-}
test/cases3/enum.zig
@@ -73,6 +73,29 @@ const AnEnumWithPayload = enum {
 
 
 
+const Number = enum {
+    Zero,
+    One,
+    Two,
+    Three,
+    Four,
+};
+
+fn enumToInt() {
+    @setFnTest(this);
+
+    shouldEqual(Number.Zero, 0);
+    shouldEqual(Number.One, 1);
+    shouldEqual(Number.Two, 2);
+    shouldEqual(Number.Three, 3);
+    shouldEqual(Number.Four, 4);
+}
+
+fn shouldEqual(n: Number, expected: usize) {
+    assert(usize(n) == expected);
+}
+
+// TODO import from std
 fn assert(ok: bool) {
     if (!ok)
         @unreachable();