authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-21 21:49:05-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-21 21:49:05-05:00
log9b616820370c08a97d95805ca31eae5f8ca554f3
tree02156ccb1d8a72c747a08b4312820e5ab649cdfa
parent1f6dacbb2f9a91a20309b271a31e781f11f81819

IR: implement runtime enum init and switch on enum with variable


5 files changed, 90 insertions(+), 19 deletions(-)

src/analyze.cpp+2
...@@ -749,6 +749,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -749,6 +749,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
749 // next, loop over the parameters again and compute debug information749 // next, loop over the parameters again and compute debug information
750 // and codegen information750 // and codegen information
751 if (!skip_debug_info) {751 if (!skip_debug_info) {
752 ensure_complete_type(g, fn_type_id->return_type);
752 bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type);753 bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type);
753 // +1 for maybe making the first argument the return value754 // +1 for maybe making the first argument the return value
754 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);755 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);
...@@ -2534,6 +2535,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -2534,6 +2535,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
2534 case TypeTableEntryIdErrorUnion:2535 case TypeTableEntryIdErrorUnion:
2535 return type_has_bits(type_entry->data.error.child_type);2536 return type_has_bits(type_entry->data.error.child_type);
2536 case TypeTableEntryIdEnum:2537 case TypeTableEntryIdEnum:
2538 assert(type_entry->data.enumeration.complete);
2537 return type_entry->data.enumeration.gen_field_count != 0;2539 return type_entry->data.enumeration.gen_field_count != 0;
2538 case TypeTableEntryIdMaybe:2540 case TypeTableEntryIdMaybe:
2539 return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&2541 return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
src/codegen.cpp+32-10
...@@ -645,7 +645,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef...@@ -645,7 +645,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
645 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");645 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
646}646}
647647
648static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node,648static LLVMValueRef gen_assign_raw(CodeGen *g,
649 LLVMValueRef target_ref, LLVMValueRef value,649 LLVMValueRef target_ref, LLVMValueRef value,
650 TypeTableEntry *op1_type, TypeTableEntry *op2_type)650 TypeTableEntry *op1_type, TypeTableEntry *op2_type)
651{651{
...@@ -698,8 +698,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -698,8 +698,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
698 LLVMBuildRet(g->builder, by_val_value);698 LLVMBuildRet(g->builder, by_val_value);
699 } else {699 } else {
700 assert(g->cur_ret_ptr);700 assert(g->cur_ret_ptr);
701 gen_assign_raw(g, return_instruction->base.source_node, g->cur_ret_ptr, value,701 gen_assign_raw(g, g->cur_ret_ptr, value, return_type, return_instruction->value->type_entry);
702 return_type, return_instruction->value->type_entry);
703 LLVMBuildRetVoid(g->builder);702 LLVMBuildRetVoid(g->builder);
704 }703 }
705 } else {704 } else {
...@@ -1232,8 +1231,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,...@@ -1232,8 +1231,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
1232 want_zeroes = true;1231 want_zeroes = true;
12331232
1234 if (have_init_expr) {1233 if (have_init_expr) {
1235 gen_assign_raw(g, init_value->source_node, var->value_ref,1234 gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->type, init_value->type_entry);
1236 ir_llvm_value(g, init_value), var->type, init_value->type_entry);
1237 } else {1235 } else {
1238 bool ignore_uninit = false;1236 bool ignore_uninit = false;
1239 // handle runtime stack allocation1237 // handle runtime stack allocation
...@@ -2078,8 +2076,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I...@@ -2078,8 +2076,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
2078 assert(instruction->tmp_ptr);2076 assert(instruction->tmp_ptr);
20792077
2080 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");2078 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
2081 gen_assign_raw(g, instruction->base.source_node, val_ptr, payload_val, child_type, instruction->value->type_entry);2079 gen_assign_raw(g, val_ptr, payload_val, child_type, instruction->value->type_entry);
2082
2083 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");2080 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
2084 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);2081 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
20852082
...@@ -2125,7 +2122,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa...@@ -2125,7 +2122,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
2125 LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);2122 LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
21262123
2127 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");2124 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
2128 gen_assign_raw(g, instruction->base.source_node, payload_ptr, payload_val, child_type, instruction->value->type_entry);2125 gen_assign_raw(g, payload_ptr, payload_val, child_type, instruction->value->type_entry);
21292126
2130 return instruction->tmp_ptr;2127 return instruction->tmp_ptr;
2131}2128}
...@@ -2145,7 +2142,30 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI...@@ -2145,7 +2142,30 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
2145}2142}
21462143
2147static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {2144static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
2148 zig_panic("TODO ir_render_init_enum");2145 TypeTableEntry *enum_type = instruction->enum_type;
2146 uint32_t value = instruction->field->value;
2147 LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
2148 LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false);
2149
2150 if (enum_type->data.enumeration.gen_field_count == 0)
2151 return tag_value;
2152
2153 LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
2154
2155 LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_gen_tag_index, "");
2156 LLVMBuildStore(g->builder, tag_value, tag_field_ptr);
2157
2158 TypeTableEntry *union_val_type = instruction->field->type_entry;
2159 if (type_has_bits(union_val_type)) {
2160 LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value);
2161 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_gen_union_index, "");
2162 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
2163 LLVMPointerType(union_val_type->type_ref, 0), "");
2164
2165 gen_assign_raw(g, bitcasted_union_field_ptr, new_union_val, union_val_type, union_val_type);
2166 }
2167
2168 return tmp_struct_ptr;
2149}2169}
21502170
2151static void set_debug_location(CodeGen *g, IrInstruction *instruction) {2171static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
...@@ -2750,7 +2770,9 @@ static void do_code_gen(CodeGen *g) {...@@ -2750,7 +2770,9 @@ static void do_code_gen(CodeGen *g) {
27502770
2751 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {2771 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
2752 // nothing to do2772 // nothing to do
2753 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {2773 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer ||
2774 fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn)
2775 {
2754 ZigLLVMAddNonNullAttr(fn_val, 0);2776 ZigLLVMAddNonNullAttr(fn_val, 0);
2755 } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&2777 } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
2756 !fn_type->data.fn.fn_type_id.is_extern)2778 !fn_type->data.fn.fn_type_id.is_extern)
src/ir.cpp+39-7
...@@ -4324,6 +4324,13 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction,...@@ -4324,6 +4324,13 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction,
4324 return ir_add_error_node(ira, source_instruction->source_node, msg);4324 return ir_add_error_node(ira, source_instruction->source_node, msg);
4325}4325}
43264326
4327static void ir_add_typedef_err_note(IrAnalyze *ira, ErrorMsg *msg, TypeTableEntry *type_entry) {
4328 if (type_entry->id == TypeTableEntryIdTypeDecl) {
4329 // requires tracking source_node in the typedecl type
4330 zig_panic("TODO add error note about typedecls");
4331 }
4332}
4333
4327static IrInstruction *ir_exec_const_result(IrExecutable *exec) {4334static IrInstruction *ir_exec_const_result(IrExecutable *exec) {
4328 if (exec->basic_block_list.length != 1)4335 if (exec->basic_block_list.length != 1)
4329 return nullptr;4336 return nullptr;
...@@ -5451,8 +5458,7 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst...@@ -5451,8 +5458,7 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
5451 if (value->type_entry->id == TypeTableEntryIdInvalid)5458 if (value->type_entry->id == TypeTableEntryIdInvalid)
5452 return ira->codegen->builtin_types.entry_invalid;5459 return ira->codegen->builtin_types.entry_invalid;
54535460
5454 bool is_inline = ir_should_inline(&ira->new_irb);5461 if (instr_is_comptime(value)) {
5455 if (is_inline || instr_is_comptime(value)) {
5456 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);5462 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
5457 if (!val)5463 if (!val)
5458 return ira->codegen->builtin_types.entry_invalid;5464 return ira->codegen->builtin_types.entry_invalid;
...@@ -8223,7 +8229,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -8223,7 +8229,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
8223 case TypeTableEntryIdUnion:8229 case TypeTableEntryIdUnion:
8224 case TypeTableEntryIdBlock:8230 case TypeTableEntryIdBlock:
8225 case TypeTableEntryIdBoundFn:8231 case TypeTableEntryIdBoundFn:
8226 ir_add_error_node(ira, switch_target_instruction->base.source_node,8232 ir_add_error(ira, &switch_target_instruction->base,
8227 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));8233 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
8228 // TODO if this is a typedecl, add error note showing the declaration of the type decl8234 // TODO if this is a typedecl, add error note showing the declaration of the type decl
8229 return ira->codegen->builtin_types.entry_invalid;8235 return ira->codegen->builtin_types.entry_invalid;
...@@ -8231,10 +8237,36 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -8231,10 +8237,36 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
8231 zig_unreachable();8237 zig_unreachable();
8232}8238}
82338239
8234static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,8240static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstructionSwitchVar *instruction) {
8235 IrInstructionSwitchVar *switch_var_instruction)8241 IrInstruction *target_value_ptr = instruction->target_value_ptr->other;
8236{8242 if (target_value_ptr->type_entry->id == TypeTableEntryIdInvalid)
8237 zig_panic("TODO switch var analyze");8243 return ira->codegen->builtin_types.entry_invalid;
8244
8245 IrInstruction *prong_value = instruction->prong_value->other;
8246 if (prong_value->type_entry->id == TypeTableEntryIdInvalid)
8247 return ira->codegen->builtin_types.entry_invalid;
8248
8249 assert(target_value_ptr->type_entry->id == TypeTableEntryIdPointer);
8250 TypeTableEntry *target_type = target_value_ptr->type_entry->data.pointer.child_type;
8251 if (target_type->id == TypeTableEntryIdEnum) {
8252 ConstExprValue *prong_val = ir_resolve_const(ira, prong_value, UndefBad);
8253 if (!prong_val)
8254 return ira->codegen->builtin_types.entry_invalid;
8255
8256 TypeEnumField *field = &target_type->data.enumeration.fields[prong_val->data.x_bignum.data.x_uint];
8257 if (instr_is_comptime(target_value_ptr)) {
8258 zig_panic("TODO comptime switch var");
8259 }
8260
8261 ir_build_enum_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field);
8262 return get_pointer_to_type(ira->codegen, field->type_entry,
8263 target_value_ptr->type_entry->data.pointer.is_const);
8264 } else {
8265 ErrorMsg *msg = ir_add_error(ira, &instruction->base,
8266 buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name)));
8267 ir_add_typedef_err_note(ira, msg, target_type);
8268 return ira->codegen->builtin_types.entry_invalid;
8269 }
8238}8270}
82398271
8240static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) {8272static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) {
src/ir_print.cpp+2-2
...@@ -919,9 +919,9 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst...@@ -919,9 +919,9 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
919}919}
920920
921static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) {921static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) {
922 fprintf(irp->f, "%s.%s { ", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name));922 fprintf(irp->f, "%s.%s {", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name));
923 ir_print_other_instruction(irp, instruction->init_value);923 ir_print_other_instruction(irp, instruction->init_value);
924 fprintf(irp->f, "{");924 fprintf(irp->f, "}");
925}925}
926926
927static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {927static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
test/cases3/enum.zig+15
...@@ -12,6 +12,16 @@ fn enumType() {...@@ -12,6 +12,16 @@ fn enumType() {
12 assert(@sizeOf(Foo) == expected_foo_size);12 assert(@sizeOf(Foo) == expected_foo_size);
13 assert(@sizeOf(Bar) == 1);13 assert(@sizeOf(Bar) == 1);
14}14}
15
16fn enumAsReturnValue () {
17 @setFnTest(this);
18
19 switch (returnAnInt(13)) {
20 Foo.One => |value| assert(value == 13),
21 else => @unreachable(),
22 }
23}
24
15const Point = struct {25const Point = struct {
16 x: u64,26 x: u64,
17 y: u64,27 y: u64,
...@@ -28,6 +38,11 @@ const Bar = enum {...@@ -28,6 +38,11 @@ const Bar = enum {
28 D,38 D,
29};39};
3040
41fn returnAnInt(x: i32) -> Foo {
42 Foo.One { x }
43}
44
45
31fn assert(ok: bool) {46fn assert(ok: bool) {
32 if (!ok)47 if (!ok)
33 @unreachable();48 @unreachable();