authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-26 02:36:04-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-26 02:36:04-05:00
log4664f793dc3fed2254863a5b6efc302c095890cb
tree1c52e0597e181d09ebf199797894945de1eb25f4
parent1b5d1877aea6c0db7fbe6f56ffe4412ce2cffff7

IR: pass enumToInt test


6 files changed, 124 insertions(+), 47 deletions(-)

src/all_types.hpp+7-2
......@@ -429,14 +429,12 @@ enum CastOp {
429429 CastOpNoop, // fn call expr is a cast, but does nothing
430430 CastOpPtrToInt,
431431 CastOpIntToPtr,
432 CastOpWidenOrShorten,
433432 CastOpErrToInt,
434433 CastOpIntToFloat,
435434 CastOpFloatToInt,
436435 CastOpBoolToInt,
437436 CastOpResizeSlice,
438437 CastOpIntToEnum,
439 CastOpEnumToInt,
440438 CastOpBytesToSlice,
441439};
442440
......@@ -1454,6 +1452,7 @@ enum IrInstructionId {
14541452 IrInstructionIdTestComptime,
14551453 IrInstructionIdInitEnum,
14561454 IrInstructionIdPointerReinterpret,
1455 IrInstructionIdWidenOrShorten,
14571456};
14581457
14591458struct IrInstruction {
......@@ -2096,6 +2095,12 @@ struct IrInstructionPointerReinterpret {
20962095 IrInstruction *ptr;
20972096};
20982097
2098struct IrInstructionWidenOrShorten {
2099 IrInstruction base;
2100
2101 IrInstruction *target;
2102};
2103
20992104enum LValPurpose {
21002105 LValPurposeNone,
21012106 LValPurposeAssign,
src/codegen.cpp+20-6
......@@ -973,9 +973,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
973973 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
974974 case CastOpIntToPtr:
975975 return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
976 case CastOpWidenOrShorten:
977 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
978 actual_type, wanted_type, expr_val);
979976 case CastOpResizeSlice:
980977 {
981978 assert(cast_instruction->tmp_ptr);
......@@ -1086,9 +1083,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
10861083 case CastOpIntToEnum:
10871084 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
10881085 actual_type, wanted_type->data.enumeration.tag_type, expr_val);
1089 case CastOpEnumToInt:
1090 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
1091 actual_type->data.enumeration.tag_type, wanted_type, expr_val);
10921086 }
10931087 zig_unreachable();
10941088}
......@@ -1101,6 +1095,24 @@ static LLVMValueRef ir_render_pointer_reinterpret(CodeGen *g, IrExecutable *exec
11011095 return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
11021096}
11031097
1098static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
1099 IrInstructionWidenOrShorten *instruction)
1100{
1101 TypeTableEntry *actual_type = instruction->target->value.type;
1102 // TODO instead of this logic, use the Noop instruction to change the type from
1103 // enum_tag to the underlying int type
1104 TypeTableEntry *int_type;
1105 if (actual_type->id == TypeTableEntryIdEnum) {
1106 TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type;
1107 assert(tag_type->id == TypeTableEntryIdEnumTag);
1108 int_type = tag_type->data.enum_tag.int_type;
1109 } else {
1110 int_type = actual_type;
1111 }
1112 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
1113 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), int_type,
1114 instruction->base.value.type, target_val);
1115}
11041116
11051117static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
11061118 IrInstructionUnreachable *unreachable_instruction)
......@@ -2309,6 +2321,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
23092321 return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
23102322 case IrInstructionIdPointerReinterpret:
23112323 return ir_render_pointer_reinterpret(g, executable, (IrInstructionPointerReinterpret *)instruction);
2324 case IrInstructionIdWidenOrShorten:
2325 return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
23122326 case IrInstructionIdSwitchVar:
23132327 zig_panic("TODO render switch var instruction to LLVM");
23142328 case IrInstructionIdContainerInitList:
src/ir.cpp+64-7
......@@ -455,6 +455,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPointerReinterpr
455455 return IrInstructionIdPointerReinterpret;
456456}
457457
458static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
459 return IrInstructionIdWidenOrShorten;
460}
461
458462template<typename T>
459463static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
460464 T *special_instruction = allocate<T>(1);
......@@ -1883,6 +1887,18 @@ static IrInstruction *ir_build_pointer_reinterpret(IrBuilder *irb, Scope *scope,
18831887 return &instruction->base;
18841888}
18851889
1890static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,
1891 IrInstruction *target)
1892{
1893 IrInstructionWidenOrShorten *instruction = ir_build_instruction<IrInstructionWidenOrShorten>(
1894 irb, scope, source_node);
1895 instruction->target = target;
1896
1897 ir_ref_instruction(target);
1898
1899 return &instruction->base;
1900}
1901
18861902static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
18871903 results[ReturnKindUnconditional] = 0;
18881904 results[ReturnKindError] = 0;
......@@ -4638,7 +4654,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
46384654 case CastOpNoCast:
46394655 zig_unreachable();
46404656 case CastOpNoop:
4641 case CastOpWidenOrShorten:
46424657 *const_val = *other_val;
46434658 const_val->type = new_type;
46444659 break;
......@@ -4684,10 +4699,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
46844699 const_val->special = ConstValSpecialStatic;
46854700 break;
46864701 }
4687 case CastOpEnumToInt:
4688 bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag);
4689 const_val->special = ConstValSpecialStatic;
4690 break;
46914702 }
46924703}
46934704static 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
51815192 return result;
51825193}
51835194
5195static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
5196 IrInstruction *target, TypeTableEntry *wanted_type)
5197{
5198 assert(wanted_type->id == TypeTableEntryIdInt);
5199
5200 if (instr_is_comptime(target)) {
5201 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
5202 if (!val)
5203 return ira->codegen->invalid_instruction;
5204 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
5205 source_instr->source_node, wanted_type, val->depends_on_compile_var);
5206 init_const_unsigned_negative(&result->value, wanted_type, val->data.x_enum.tag, false);
5207 return result;
5208 }
5209
5210 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
5211 source_instr->source_node, target);
5212 result->value.type = wanted_type;
5213 return result;
5214}
5215
5216static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr,
5217 IrInstruction *target, TypeTableEntry *wanted_type)
5218{
5219 assert(wanted_type->id == TypeTableEntryIdInt || wanted_type->id == TypeTableEntryIdFloat);
5220
5221 if (instr_is_comptime(target)) {
5222 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
5223 if (!val)
5224 return ira->codegen->invalid_instruction;
5225 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
5226 source_instr->source_node, wanted_type, val->depends_on_compile_var);
5227 result->value = *val;
5228 result->value.type = wanted_type;
5229 return result;
5230 }
5231
5232 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
5233 source_instr->source_node, target);
5234 result->value.type = wanted_type;
5235 return result;
5236}
5237
5238
51845239static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
51855240 TypeTableEntry *wanted_type, IrInstruction *value)
51865241{
......@@ -5233,7 +5288,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
52335288 (wanted_type_canon->id == TypeTableEntryIdFloat &&
52345289 actual_type_canon->id == TypeTableEntryIdFloat))
52355290 {
5236 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpWidenOrShorten, false);
5291 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
52375292 }
52385293
52395294 // explicit cast from int to float
......@@ -5411,7 +5466,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
54115466 actual_type->id == TypeTableEntryIdEnum &&
54125467 actual_type->data.enumeration.gen_field_count == 0)
54135468 {
5414 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpEnumToInt, false);
5469 return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
54155470 }
54165471
54175472 // explicit cast from undefined to anything
......@@ -9882,6 +9937,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
98829937 switch (instruction->id) {
98839938 case IrInstructionIdInvalid:
98849939 case IrInstructionIdPointerReinterpret:
9940 case IrInstructionIdWidenOrShorten:
98859941 case IrInstructionIdStructInit:
98869942 case IrInstructionIdStructFieldPtr:
98879943 case IrInstructionIdEnumFieldPtr:
......@@ -10188,6 +10244,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1018810244 case IrInstructionIdTestComptime:
1018910245 case IrInstructionIdInitEnum:
1019010246 case IrInstructionIdPointerReinterpret:
10247 case IrInstructionIdWidenOrShorten:
1019110248 return false;
1019210249 case IrInstructionIdAsm:
1019310250 {
src/ir_print.cpp+10-1
......@@ -923,11 +923,17 @@ static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction)
923923}
924924
925925static void ir_print_pointer_reinterpret(IrPrint *irp, IrInstructionPointerReinterpret *instruction) {
926 fprintf(irp->f, "(%s)(", buf_ptr(&instruction->base.value.type->name));
926 fprintf(irp->f, "@pointerReinterpret(");
927927 ir_print_other_instruction(irp, instruction->ptr);
928928 fprintf(irp->f, ")");
929929}
930930
931static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
932 fprintf(irp->f, "@widenOrShorten(");
933 ir_print_other_instruction(irp, instruction->target);
934 fprintf(irp->f, ")");
935}
936
931937static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
932938 ir_print_prefix(irp, instruction);
933939 switch (instruction->id) {
......@@ -1170,6 +1176,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11701176 case IrInstructionIdPointerReinterpret:
11711177 ir_print_pointer_reinterpret(irp, (IrInstructionPointerReinterpret *)instruction);
11721178 break;
1179 case IrInstructionIdWidenOrShorten:
1180 ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
1181 break;
11731182 }
11741183 fprintf(irp->f, "\n");
11751184}
test/cases/enum_to_int.zig deleted-31
......@@ -1,31 +0,0 @@
1const assert = @import("std").debug.assert;
2
3enum Number {
4 Zero,
5 One,
6 Two,
7 Three,
8 Four,
9}
10
11fn enumToInt() {
12 @setFnTest(this, true);
13
14 shouldEqual(false, Number.Zero, 0);
15 shouldEqual(false, Number.One, 1);
16 shouldEqual(false, Number.Two, 2);
17 shouldEqual(false, Number.Three, 3);
18 shouldEqual(false, Number.Four, 4);
19
20 shouldEqual(true, Number.Zero, 0);
21 shouldEqual(true, Number.One, 1);
22 shouldEqual(true, Number.Two, 2);
23 shouldEqual(true, Number.Three, 3);
24 shouldEqual(true, Number.Four, 4);
25}
26
27fn shouldEqual(inline static_eval: bool, n: Number, expected: usize) {
28 @setFnStaticEval(this, static_eval);
29
30 assert(usize(n) == expected);
31}
test/cases3/enum.zig+23
......@@ -73,6 +73,29 @@ const AnEnumWithPayload = enum {
7373
7474
7575
76const Number = enum {
77 Zero,
78 One,
79 Two,
80 Three,
81 Four,
82};
83
84fn enumToInt() {
85 @setFnTest(this);
86
87 shouldEqual(Number.Zero, 0);
88 shouldEqual(Number.One, 1);
89 shouldEqual(Number.Two, 2);
90 shouldEqual(Number.Three, 3);
91 shouldEqual(Number.Four, 4);
92}
93
94fn shouldEqual(n: Number, expected: usize) {
95 assert(usize(n) == expected);
96}
97
98// TODO import from std
7699fn assert(ok: bool) {
77100 if (!ok)
78101 @unreachable();