authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-22 09:35:07-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-22 09:35:07-05:00
logba8af0f1e281fc7e56a8f4eb6f3974efc6ed043d
tree09dfe2192b5b5623dfb74f47303422fb2efee506
parented962d9d21c451ed2e0ff125d6817f3c71827154

IR: fix missing implicit casts in init expressions

and implement runtime struct init instruction

5 files changed, 91 insertions(+), 65 deletions(-)

src/codegen.cpp+16-2
...@@ -2171,6 +2171,20 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir...@@ -2171,6 +2171,20 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir
2171 return tmp_struct_ptr;2171 return tmp_struct_ptr;
2172}2172}
21732173
2174static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) {
2175 for (size_t i = 0; i < instruction->field_count; i += 1) {
2176 IrInstructionStructInitField *field = &instruction->fields[i];
2177 TypeStructField *type_struct_field = field->type_struct_field;
2178 if (!type_has_bits(type_struct_field->type_entry))
2179 continue;
2180
2181 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, "");
2182 LLVMValueRef value = ir_llvm_value(g, field->value);
2183 gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry, type_struct_field->type_entry);
2184 }
2185 return instruction->tmp_ptr;
2186}
2187
2174static void set_debug_location(CodeGen *g, IrInstruction *instruction) {2188static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
2175 AstNode *source_node = instruction->source_node;2189 AstNode *source_node = instruction->source_node;
2176 Scope *scope = instruction->scope;2190 Scope *scope = instruction->scope;
...@@ -2307,12 +2321,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2307,12 +2321,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2307 return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);2321 return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
2308 case IrInstructionIdInitEnum:2322 case IrInstructionIdInitEnum:
2309 return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);2323 return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
2324 case IrInstructionIdStructInit:
2325 return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
2310 case IrInstructionIdSwitchVar:2326 case IrInstructionIdSwitchVar:
2311 zig_panic("TODO render switch var instruction to LLVM");2327 zig_panic("TODO render switch var instruction to LLVM");
2312 case IrInstructionIdContainerInitList:2328 case IrInstructionIdContainerInitList:
2313 zig_panic("TODO render container init list instruction to LLVM");2329 zig_panic("TODO render container init list instruction to LLVM");
2314 case IrInstructionIdStructInit:
2315 zig_panic("TODO render struct init to LLVM");
2316 }2330 }
2317 zig_unreachable();2331 zig_unreachable();
2318}2332}
src/ir.cpp+26-19
...@@ -8431,8 +8431,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -8431,8 +8431,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
84318431
8432 IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count);8432 IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count);
84338433
8434 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);8434 bool is_comptime = ir_should_inline(&ira->new_irb);
8435 bool outside_fn = (fn_entry == nullptr);
84368435
8437 ConstExprValue const_val = {};8436 ConstExprValue const_val = {};
8438 const_val.special = ConstValSpecialStatic;8437 const_val.special = ConstValSpecialStatic;
...@@ -8456,6 +8455,10 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -8456,6 +8455,10 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
8456 if (type_field->type_entry->id == TypeTableEntryIdInvalid)8455 if (type_field->type_entry->id == TypeTableEntryIdInvalid)
8457 return ira->codegen->builtin_types.entry_invalid;8456 return ira->codegen->builtin_types.entry_invalid;
84588457
8458 IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
8459 if (casted_field_value == ira->codegen->invalid_instruction)
8460 return ira->codegen->builtin_types.entry_invalid;
8461
8459 size_t field_index = type_field->src_index;8462 size_t field_index = type_field->src_index;
8460 AstNode *existing_assign_node = field_assign_nodes[field_index];8463 AstNode *existing_assign_node = field_assign_nodes[field_index];
8461 if (existing_assign_node) {8464 if (existing_assign_node) {
...@@ -8465,19 +8468,19 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -8465,19 +8468,19 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
8465 }8468 }
8466 field_assign_nodes[field_index] = field->source_node;8469 field_assign_nodes[field_index] = field->source_node;
84678470
8468 new_fields[field_index].value = field_value;8471 new_fields[field_index].value = casted_field_value;
8469 new_fields[field_index].type_struct_field = type_field;8472 new_fields[field_index].type_struct_field = type_field;
84708473
8471 if (const_val.special == ConstValSpecialStatic) {8474 if (const_val.special == ConstValSpecialStatic) {
8472 if (outside_fn || field_value->static_value.special != ConstValSpecialRuntime) {8475 if (is_comptime || casted_field_value->static_value.special != ConstValSpecialRuntime) {
8473 ConstExprValue *field_val = ir_resolve_const(ira, field_value, UndefOk);8476 ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
8474 if (!field_val)8477 if (!field_val)
8475 return ira->codegen->builtin_types.entry_invalid;8478 return ira->codegen->builtin_types.entry_invalid;
84768479
8477 const_val.data.x_struct.fields[field_index] = *field_val;8480 const_val.data.x_struct.fields[field_index] = *field_val;
8478 const_val.depends_on_compile_var = const_val.depends_on_compile_var || field_val->depends_on_compile_var;8481 const_val.depends_on_compile_var = const_val.depends_on_compile_var || field_val->depends_on_compile_var;
8479 } else {8482 } else {
8480 first_non_const_instruction = field_value;8483 first_non_const_instruction = casted_field_value;
8481 const_val.special = ConstValSpecialRuntime;8484 const_val.special = ConstValSpecialRuntime;
8482 }8485 }
8483 }8486 }
...@@ -8500,7 +8503,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -8500,7 +8503,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
8500 return container_type;8503 return container_type;
8501 }8504 }
85028505
8503 if (outside_fn) {8506 if (is_comptime) {
8504 ir_add_error_node(ira, first_non_const_instruction->source_node,8507 ir_add_error_node(ira, first_non_const_instruction->source_node,
8505 buf_sprintf("unable to evaluate constant expression"));8508 buf_sprintf("unable to evaluate constant expression"));
8506 return ira->codegen->builtin_types.entry_invalid;8509 return ira->codegen->builtin_types.entry_invalid;
...@@ -8513,7 +8516,9 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -8513,7 +8516,9 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
8513 return container_type;8516 return container_type;
8514}8517}
85158518
8516static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) {8519static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
8520 IrInstructionContainerInitList *instruction)
8521{
8517 IrInstruction *container_type_value = instruction->container_type->other;8522 IrInstruction *container_type_value = instruction->container_type->other;
8518 if (container_type_value->type_entry->id == TypeTableEntryIdInvalid)8523 if (container_type_value->type_entry->id == TypeTableEntryIdInvalid)
8519 return ira->codegen->builtin_types.entry_invalid;8524 return ira->codegen->builtin_types.entry_invalid;
...@@ -8527,7 +8532,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira...@@ -8527,7 +8532,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
8527 bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;8532 bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
85288533
8529 if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) {8534 if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) {
8530 return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var);8535 return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
8536 0, nullptr, depends_on_compile_var);
8531 } else if (is_slice(container_type)) {8537 } else if (is_slice(container_type)) {
8532 TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;8538 TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
8533 assert(pointer_type->id == TypeTableEntryIdPointer);8539 assert(pointer_type->id == TypeTableEntryIdPointer);
...@@ -8539,8 +8545,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira...@@ -8539,8 +8545,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
8539 const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);8545 const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);
8540 const_val.data.x_array.size = elem_count;8546 const_val.data.x_array.size = elem_count;
85418547
8542 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);8548 bool is_comptime = ir_should_inline(&ira->new_irb);
8543 bool outside_fn = (fn_entry == nullptr);
85448549
8545 IrInstruction **new_items = allocate<IrInstruction *>(elem_count);8550 IrInstruction **new_items = allocate<IrInstruction *>(elem_count);
85468551
...@@ -8551,18 +8556,22 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira...@@ -8551,18 +8556,22 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
8551 if (arg_value->type_entry->id == TypeTableEntryIdInvalid)8556 if (arg_value->type_entry->id == TypeTableEntryIdInvalid)
8552 return ira->codegen->builtin_types.entry_invalid;8557 return ira->codegen->builtin_types.entry_invalid;
85538558
8554 new_items[i] = arg_value;8559 IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
8560 if (casted_arg == ira->codegen->invalid_instruction)
8561 return ira->codegen->builtin_types.entry_invalid;
8562
8563 new_items[i] = casted_arg;
85558564
8556 if (const_val.special == ConstValSpecialStatic) {8565 if (const_val.special == ConstValSpecialStatic) {
8557 if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) {8566 if (is_comptime || casted_arg->static_value.special != ConstValSpecialRuntime) {
8558 ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad);8567 ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
8559 if (!elem_val)8568 if (!elem_val)
8560 return ira->codegen->builtin_types.entry_invalid;8569 return ira->codegen->builtin_types.entry_invalid;
85618570
8562 const_val.data.x_array.elements[i] = *elem_val;8571 const_val.data.x_array.elements[i] = *elem_val;
8563 const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var;8572 const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var;
8564 } else {8573 } else {
8565 first_non_const_instruction = arg_value;8574 first_non_const_instruction = casted_arg;
8566 const_val.special = ConstValSpecialRuntime;8575 const_val.special = ConstValSpecialRuntime;
8567 }8576 }
8568 }8577 }
...@@ -8575,7 +8584,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira...@@ -8575,7 +8584,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
8575 return fixed_size_array_type;8584 return fixed_size_array_type;
8576 }8585 }
85778586
8578 if (outside_fn) {8587 if (is_comptime) {
8579 ir_add_error_node(ira, first_non_const_instruction->source_node,8588 ir_add_error_node(ira, first_non_const_instruction->source_node,
8580 buf_sprintf("unable to evaluate constant expression"));8589 buf_sprintf("unable to evaluate constant expression"));
8581 return ira->codegen->builtin_types.entry_invalid;8590 return ira->codegen->builtin_types.entry_invalid;
...@@ -8602,10 +8611,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira...@@ -8602,10 +8611,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
8602 return ira->codegen->builtin_types.entry_invalid;8611 return ira->codegen->builtin_types.entry_invalid;
8603 }8612 }
8604 } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) {8613 } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) {
8605 // TODO I wrote this commit message when I had some sake
8606 // might be worth re-examining sober
8607 if (elem_count != 1) {8614 if (elem_count != 1) {
8608 ir_add_error(ira, &instruction->base, buf_sprintf("expected 1 elment"));8615 ir_add_error(ira, &instruction->base, buf_sprintf("enum initialization requires exactly one element"));
8609 return ira->codegen->builtin_types.entry_invalid;8616 return ira->codegen->builtin_types.entry_invalid;
8610 }8617 }
8611 ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad);8618 ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad);
test/cases/struct_contains_slice_of_itself.zig deleted-44
...@@ -1,44 +0,0 @@
1const assert = @import("std").debug.assert;
2
3struct Node {
4 payload: i32,
5 children: []Node,
6}
7
8fn structContainsSliceOfItself() {
9 @setFnTest(this, true);
10
11 var nodes = []Node {
12 Node {
13 .payload = 1,
14 .children = []Node{},
15 },
16 Node {
17 .payload = 2,
18 .children = []Node{},
19 },
20 Node {
21 .payload = 3,
22 .children = []Node{
23 Node {
24 .payload = 31,
25 .children = []Node{},
26 },
27 Node {
28 .payload = 32,
29 .children = []Node{},
30 },
31 },
32 },
33 };
34 const root = Node {
35 .payload = 1234,
36 .children = nodes[0...],
37 };
38 assert(root.payload == 1234);
39 assert(root.children[0].payload == 1);
40 assert(root.children[1].payload == 2);
41 assert(root.children[2].payload == 3);
42 assert(root.children[2].children[0].payload == 31);
43 assert(root.children[2].children[1].payload == 32);
44}
test/cases3/struct_contains_slice_of_itself.zig created+48
...@@ -0,0 +1,48 @@
1const Node = struct {
2 payload: i32,
3 children: []Node,
4};
5
6fn structContainsSliceOfItself() {
7 @setFnTest(this);
8
9 var nodes = []Node {
10 Node {
11 .payload = 1,
12 .children = []Node{},
13 },
14 Node {
15 .payload = 2,
16 .children = []Node{},
17 },
18 Node {
19 .payload = 3,
20 .children = []Node{
21 Node {
22 .payload = 31,
23 .children = []Node{},
24 },
25 Node {
26 .payload = 32,
27 .children = []Node{},
28 },
29 },
30 },
31 };
32 const root = Node {
33 .payload = 1234,
34 .children = nodes[0...],
35 };
36 assert(root.payload == 1234);
37 assert(root.children[0].payload == 1);
38 assert(root.children[1].payload == 2);
39 assert(root.children[2].payload == 3);
40 assert(root.children[2].children[0].payload == 31);
41 assert(root.children[2].children[1].payload == 32);
42}
43
44// TODO const assert = @import("std").debug.assert;
45fn assert(ok: bool) {
46 if (!ok)
47 @unreachable();
48}
test/self_hosted3.zig+1
...@@ -20,3 +20,4 @@ const test_struct = @import("cases3/struct.zig");...@@ -20,3 +20,4 @@ const test_struct = @import("cases3/struct.zig");
20const test_switch = @import("cases3/switch.zig");20const test_switch = @import("cases3/switch.zig");
21const test_this = @import("cases3/this.zig");21const test_this = @import("cases3/this.zig");
22const test_while = @import("cases3/while.zig");22const test_while = @import("cases3/while.zig");
23const test_struct_contains_slice_of_itself = @import("cases3/struct_contains_slice_of_itself.zig");