From 66a83d87383cd8de62898171b6665cb1d70af231 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Dec 2016 16:34:18 -0500 Subject: [PATCH] IR: pass intToEnum test --- src/all_types.hpp | 8 ++++++- src/codegen.cpp | 24 +++++++++++++++++---- src/ir.cpp | 51 ++++++++++++++++++++++++++++++++++---------- src/ir_print.cpp | 9 ++++++++ test/cases/enum.zig | 17 +++++++++++++++ test/self_hosted.zig | 17 --------------- 6 files changed, 93 insertions(+), 33 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 360ffa3cba..9c8a02f1aa 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -437,7 +437,6 @@ enum CastOp { CastOpFloatToInt, CastOpBoolToInt, CastOpResizeSlice, - CastOpIntToEnum, CastOpBytesToSlice, }; @@ -1458,6 +1457,7 @@ enum IrInstructionId { IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, IrInstructionIdPtrToInt, + IrInstructionIdIntToEnum, }; struct IrInstruction { @@ -2118,6 +2118,12 @@ struct IrInstructionIntToPtr { IrInstruction *target; }; +struct IrInstructionIntToEnum { + IrInstruction base; + + IrInstruction *target; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/codegen.cpp b/src/codegen.cpp index cf737fc7c3..070ad98a7c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1075,10 +1075,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, assert(wanted_type->id == TypeTableEntryIdInt); assert(actual_type->id == TypeTableEntryIdBool); return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); - - 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); } zig_unreachable(); } @@ -1122,6 +1118,24 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, ""); } +static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) { + TypeTableEntry *wanted_type = instruction->base.value.type; + assert(wanted_type->id == TypeTableEntryIdEnum); + TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type; + TypeTableEntry *wanted_int_type; + if (tag_type->id == TypeTableEntryIdEnumTag) { + wanted_int_type = tag_type->data.enum_tag.int_type; + } else if (tag_type->id == TypeTableEntryIdInt) { + wanted_int_type = tag_type; + } else { + zig_unreachable(); + } + + LLVMValueRef target_val = ir_llvm_value(g, instruction->target); + return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), + instruction->target->value.type, wanted_int_type, target_val); +} + static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable, IrInstructionUnreachable *unreachable_instruction) { @@ -2359,6 +2373,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_ptr_to_int(g, executable, (IrInstructionPtrToInt *)instruction); case IrInstructionIdIntToPtr: return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction); + case IrInstructionIdIntToEnum: + return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction); case IrInstructionIdContainerInitList: return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); case IrInstructionIdSwitchVar: diff --git a/src/ir.cpp b/src/ir.cpp index c964f5536b..d58c813f3e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -468,6 +468,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToPtr *) { return IrInstructionIdIntToPtr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) { + return IrInstructionIdIntToEnum; +} + template static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1932,6 +1936,18 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *target) +{ + IrInstructionIntToEnum *instruction = ir_build_instruction( + 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; @@ -4720,16 +4736,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); const_val->special = ConstValSpecialStatic; break; - case CastOpIntToEnum: - { - uint64_t value = other_val->data.x_bignum.data.x_uint; - assert(new_type->id == TypeTableEntryIdEnum); - assert(value < new_type->data.enumeration.src_field_count); - const_val->data.x_enum.tag = value; - const_val->data.x_enum.payload = NULL; - const_val->special = ConstValSpecialStatic; - break; - } } } static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, @@ -5311,6 +5317,27 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc return result; } +static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *target, TypeTableEntry *wanted_type) +{ + assert(wanted_type->id == TypeTableEntryIdEnum); + + 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.data.x_enum.tag = val->data.x_bignum.data.x_uint; + return result; + } + + IrInstruction *result = ir_build_int_to_enum(&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) { @@ -5533,7 +5560,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->id == TypeTableEntryIdEnum && wanted_type->data.enumeration.gen_field_count == 0) { - return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToEnum, false); + return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type); } // explicit cast from enum type with no payload to integer @@ -10016,6 +10043,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi case IrInstructionIdWidenOrShorten: case IrInstructionIdIntToPtr: case IrInstructionIdPtrToInt: + case IrInstructionIdIntToEnum: case IrInstructionIdStructInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: @@ -10325,6 +10353,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: case IrInstructionIdIntToPtr: + case IrInstructionIdIntToEnum: return false; case IrInstructionIdAsm: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index ebbcf6feae..eb95a2681e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -952,6 +952,12 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction fprintf(irp->f, ")"); } +static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) { + fprintf(irp->f, "@intToEnum("); + 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) { @@ -1203,6 +1209,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdIntToPtr: ir_print_int_to_ptr(irp, (IrInstructionIntToPtr *)instruction); break; + case IrInstructionIdIntToEnum: + ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/cases/enum.zig b/test/cases/enum.zig index 649a502cb9..5d8ce4a321 100644 --- a/test/cases/enum.zig +++ b/test/cases/enum.zig @@ -96,6 +96,23 @@ fn shouldEqual(n: Number, expected: usize) { } +fn intToEnum() { + @setFnTest(this); + + testIntToEnumEval(3); +} +fn testIntToEnumEval(x: i32) { + assert(IntToEnumNumber(x) == IntToEnumNumber.Three); +} +const IntToEnumNumber = enum { + Zero, + One, + Two, + Three, + Four, +}; + + // TODO import from std fn assert(ok: bool) { if (!ok) diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 539d14a446..54219270d8 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -80,20 +80,3 @@ fn castSliceToU8Slice() { assert(bytes[10] == @maxValue(u8)); assert(bytes[11] == @maxValue(u8)); } - -// TODO not passing -fn intToEnum() { - @setFnTest(this); - - testIntToEnumEval(3); -} -fn testIntToEnumEval(x: i32) { - assert(IntToEnumNumber(x) == IntToEnumNumber.Three); -} -const IntToEnumNumber = enum { - Zero, - One, - Two, - Three, - Four, -};