authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-22 18:05:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-22 18:05:22-07:00
log1158bc3eadd8127301f96ecb9bcbb04cf04156b8
tree8887fad0da5bc92e1098268ce9efe8617d950f67
parent7bd9c8238626998f8016086762483114e5c58f70

support statically initialized structs


4 files changed, 80 insertions(+), 34 deletions(-)

src/all_types.hpp+7-1
...@@ -45,6 +45,10 @@ struct ConstEnumValue {...@@ -45,6 +45,10 @@ struct ConstEnumValue {
45 ConstExprValue *payload;45 ConstExprValue *payload;
46};46};
4747
48struct ConstStructValue {
49 ConstExprValue **fields;
50};
51
48struct ConstExprValue {52struct ConstExprValue {
49 bool ok; // true if constant expression evalution worked53 bool ok; // true if constant expression evalution worked
50 bool depends_on_compile_var;54 bool depends_on_compile_var;
...@@ -56,6 +60,7 @@ struct ConstExprValue {...@@ -56,6 +60,7 @@ struct ConstExprValue {
56 TypeTableEntry *x_type;60 TypeTableEntry *x_type;
57 ConstExprValue *x_maybe;61 ConstExprValue *x_maybe;
58 ConstEnumValue x_enum;62 ConstEnumValue x_enum;
63 ConstStructValue x_struct;
59 } data;64 } data;
60};65};
6166
...@@ -721,7 +726,8 @@ struct TypeStructField {...@@ -721,7 +726,8 @@ struct TypeStructField {
721struct TypeTableEntryStruct {726struct TypeTableEntryStruct {
722 AstNode *decl_node;727 AstNode *decl_node;
723 bool is_packed;728 bool is_packed;
724 uint32_t field_count;729 uint32_t src_field_count;
730 uint32_t gen_field_count;
725 TypeStructField *fields;731 TypeStructField *fields;
726 uint64_t size_bytes;732 uint64_t size_bytes;
727 bool is_invalid; // true if any fields are invalid733 bool is_invalid; // true if any fields are invalid
src/analyze.cpp+29-20
...@@ -34,6 +34,8 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -34,6 +34,8 @@ static AstNode *first_executing_node(AstNode *node) {
34 return first_executing_node(node->data.field_access_expr.struct_expr);34 return first_executing_node(node->data.field_access_expr.struct_expr);
35 case NodeTypeSwitchRange:35 case NodeTypeSwitchRange:
36 return first_executing_node(node->data.switch_range.start);36 return first_executing_node(node->data.switch_range.start);
37 case NodeTypeContainerInitExpr:
38 return first_executing_node(node->data.container_init_expr.type);
37 case NodeTypeRoot:39 case NodeTypeRoot:
38 case NodeTypeRootExportDecl:40 case NodeTypeRootExportDecl:
39 case NodeTypeFnProto:41 case NodeTypeFnProto:
...@@ -69,7 +71,6 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -69,7 +71,6 @@ static AstNode *first_executing_node(AstNode *node) {
69 case NodeTypeForExpr:71 case NodeTypeForExpr:
70 case NodeTypeSwitchExpr:72 case NodeTypeSwitchExpr:
71 case NodeTypeSwitchProng:73 case NodeTypeSwitchProng:
72 case NodeTypeContainerInitExpr:
73 case NodeTypeArrayType:74 case NodeTypeArrayType:
74 return node;75 return node;
75 }76 }
...@@ -303,7 +304,8 @@ static void unknown_size_array_type_common_init(CodeGen *g, TypeTableEntry *chil...@@ -303,7 +304,8 @@ static void unknown_size_array_type_common_init(CodeGen *g, TypeTableEntry *chil
303 entry->align_in_bits = g->pointer_size_bytes * 8;304 entry->align_in_bits = g->pointer_size_bytes * 8;
304 entry->data.structure.is_packed = false;305 entry->data.structure.is_packed = false;
305 entry->data.structure.is_unknown_size_array = true;306 entry->data.structure.is_unknown_size_array = true;
306 entry->data.structure.field_count = element_count;307 entry->data.structure.src_field_count = element_count;
308 entry->data.structure.gen_field_count = element_count;
307 entry->data.structure.fields = allocate<TypeStructField>(element_count);309 entry->data.structure.fields = allocate<TypeStructField>(element_count);
308 entry->data.structure.fields[0].name = buf_create_from_str("ptr");310 entry->data.structure.fields[0].name = buf_create_from_str("ptr");
309 entry->data.structure.fields[0].type_entry = pointer_type;311 entry->data.structure.fields[0].type_entry = pointer_type;
...@@ -764,7 +766,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE...@@ -764,7 +766,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
764766
765 int field_count = decl_node->data.struct_decl.fields.length;767 int field_count = decl_node->data.struct_decl.fields.length;
766768
767 struct_type->data.structure.field_count = field_count;769 struct_type->data.structure.src_field_count = field_count;
768 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);770 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
769771
770 // we possibly allocate too much here since gen_field_count can be lower than field_count.772 // we possibly allocate too much here since gen_field_count can be lower than field_count.
...@@ -823,6 +825,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE...@@ -823,6 +825,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
823 }825 }
824 struct_type->data.structure.embedded_in_current = false;826 struct_type->data.structure.embedded_in_current = false;
825827
828 struct_type->data.structure.gen_field_count = gen_field_index;
829
826 if (!struct_type->data.structure.is_invalid) {830 if (!struct_type->data.structure.is_invalid) {
827831
828 LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_index, false);832 LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_index, false);
...@@ -1083,6 +1087,9 @@ static void add_global_const_expr(CodeGen *g, Expr *expr) {...@@ -1083,6 +1087,9 @@ static void add_global_const_expr(CodeGen *g, Expr *expr) {
1083}1087}
10841088
1085static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) {1089static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) {
1090 if (other_type->id == TypeTableEntryIdInvalid) {
1091 return false;
1092 }
1086 Expr *expr = get_resolved_expr(literal_node);1093 Expr *expr = get_resolved_expr(literal_node);
1087 ConstExprValue *const_val = &expr->const_val;1094 ConstExprValue *const_val = &expr->const_val;
1088 assert(const_val->ok);1095 assert(const_val->ok);
...@@ -1438,16 +1445,6 @@ static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {...@@ -1438,16 +1445,6 @@ static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {
1438 return nullptr;1445 return nullptr;
1439}1446}
14401447
1441static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {
1442 for (uint32_t i = 0; i < struct_type->data.structure.field_count; i += 1) {
1443 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
1444 if (buf_eql_buf(type_struct_field->name, name)) {
1445 return type_struct_field;
1446 }
1447 }
1448 return nullptr;
1449}
1450
1451static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,1448static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1452 AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name)1449 AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name)
1453{1450{
...@@ -1484,12 +1481,11 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp...@@ -1484,12 +1481,11 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp
1484 return enum_type;1481 return enum_type;
1485}1482}
14861483
1487static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name, int *index) {1484static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
1488 assert(type_entry->id == TypeTableEntryIdStruct);1485 assert(type_entry->id == TypeTableEntryIdStruct);
1489 for (uint32_t i = 0; i < type_entry->data.structure.field_count; i += 1) {1486 for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
1490 TypeStructField *field = &type_entry->data.structure.fields[i];1487 TypeStructField *field = &type_entry->data.structure.fields[i];
1491 if (buf_eql_buf(field->name, name)) {1488 if (buf_eql_buf(field->name, name)) {
1492 *index = i;
1493 return field;1489 return field;
1494 }1490 }
1495 }1491 }
...@@ -1530,16 +1526,18 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry...@@ -1530,16 +1526,18 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
15301526
15311527
1532 int expr_field_count = container_init_expr->entries.length;1528 int expr_field_count = container_init_expr->entries.length;
1533 int actual_field_count = container_type->data.structure.field_count;1529 int actual_field_count = container_type->data.structure.src_field_count;
15341530
1535 int *field_use_counts = allocate<int>(actual_field_count);1531 int *field_use_counts = allocate<int>(actual_field_count);
1532 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
1533 const_val->ok = true;
1534 const_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count);
1536 for (int i = 0; i < expr_field_count; i += 1) {1535 for (int i = 0; i < expr_field_count; i += 1) {
1537 AstNode *val_field_node = container_init_expr->entries.at(i);1536 AstNode *val_field_node = container_init_expr->entries.at(i);
1538 assert(val_field_node->type == NodeTypeStructValueField);1537 assert(val_field_node->type == NodeTypeStructValueField);
15391538
1540 int field_index;
1541 TypeStructField *type_field = find_struct_type_field(container_type,1539 TypeStructField *type_field = find_struct_type_field(container_type,
1542 &val_field_node->data.struct_val_field.name, &field_index);1540 &val_field_node->data.struct_val_field.name);
15431541
1544 if (!type_field) {1542 if (!type_field) {
1545 add_node_error(g, val_field_node,1543 add_node_error(g, val_field_node,
...@@ -1548,6 +1546,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry...@@ -1548,6 +1546,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
1548 continue;1546 continue;
1549 }1547 }
15501548
1549 int field_index = type_field->src_index;
1551 field_use_counts[field_index] += 1;1550 field_use_counts[field_index] += 1;
1552 if (field_use_counts[field_index] > 1) {1551 if (field_use_counts[field_index] > 1) {
1553 add_node_error(g, val_field_node, buf_sprintf("duplicate field"));1552 add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
...@@ -1558,6 +1557,16 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry...@@ -1558,6 +1557,16 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
15581557
1559 analyze_expression(g, import, context, type_field->type_entry,1558 analyze_expression(g, import, context, type_field->type_entry,
1560 val_field_node->data.struct_val_field.expr);1559 val_field_node->data.struct_val_field.expr);
1560
1561 if (const_val->ok) {
1562 ConstExprValue *field_val =
1563 &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
1564 if (field_val->ok) {
1565 const_val->data.x_struct.fields[field_index] = field_val;
1566 } else {
1567 const_val->ok = false;
1568 }
1569 }
1561 }1570 }
15621571
1563 for (int i = 0; i < actual_field_count; i += 1) {1572 for (int i = 0; i < actual_field_count; i += 1) {
...@@ -1634,7 +1643,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -1634,7 +1643,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
1634 TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?1643 TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?
1635 struct_type : struct_type->data.pointer.child_type;1644 struct_type : struct_type->data.pointer.child_type;
16361645
1637 node->data.field_access_expr.type_struct_field = get_struct_field(bare_struct_type, field_name);1646 node->data.field_access_expr.type_struct_field = find_struct_type_field(bare_struct_type, field_name);
1638 if (node->data.field_access_expr.type_struct_field) {1647 if (node->data.field_access_expr.type_struct_field) {
1639 return node->data.field_access_expr.type_struct_field->type_entry;1648 return node->data.field_access_expr.type_struct_field->type_entry;
1640 } else {1649 } else {
src/codegen.cpp+26-13
...@@ -1527,13 +1527,13 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {...@@ -1527,13 +1527,13 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
1527 if (type_entry->id == TypeTableEntryIdStruct) {1527 if (type_entry->id == TypeTableEntryIdStruct) {
1528 assert(node->data.container_init_expr.kind == ContainerInitKindStruct);1528 assert(node->data.container_init_expr.kind == ContainerInitKindStruct);
15291529
1530 int field_count = type_entry->data.structure.field_count;1530 int src_field_count = type_entry->data.structure.src_field_count;
1531 assert(field_count == node->data.container_init_expr.entries.length);1531 assert(src_field_count == node->data.container_init_expr.entries.length);
15321532
1533 StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;1533 StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
1534 LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;1534 LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
15351535
1536 for (int i = 0; i < field_count; i += 1) {1536 for (int i = 0; i < src_field_count; i += 1) {
1537 AstNode *field_node = node->data.container_init_expr.entries.at(i);1537 AstNode *field_node = node->data.container_init_expr.entries.at(i);
1538 assert(field_node->type == NodeTypeStructValueField);1538 assert(field_node->type == NodeTypeStructValueField);
1539 TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;1539 TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
...@@ -2109,7 +2109,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE...@@ -2109,7 +2109,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
2109 };2109 };
2110 return LLVMConstStruct(fields, 2, false);2110 return LLVMConstStruct(fields, 2, false);
2111 } else if (type_entry->id == TypeTableEntryIdStruct) {2111 } else if (type_entry->id == TypeTableEntryIdStruct) {
2112 zig_panic("TODO");2112 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
2113 for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
2114 TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
2115 fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
2116 const_val->data.x_struct.fields[i]);
2117 }
2118 return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
2113 } else if (type_entry->id == TypeTableEntryIdArray) {2119 } else if (type_entry->id == TypeTableEntryIdArray) {
2114 zig_panic("TODO");2120 zig_panic("TODO");
2115 } else if (type_entry->id == TypeTableEntryIdEnum) {2121 } else if (type_entry->id == TypeTableEntryIdEnum) {
...@@ -2142,10 +2148,10 @@ static void gen_const_globals(CodeGen *g) {...@@ -2142,10 +2148,10 @@ static void gen_const_globals(CodeGen *g) {
2142 TypeTableEntry *type_entry = expr->type_entry;2148 TypeTableEntry *type_entry = expr->type_entry;
21432149
2144 if (handle_is_ptr(type_entry)) {2150 if (handle_is_ptr(type_entry)) {
2145 LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, "");
2146 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
2147 LLVMValueRef init_val = gen_const_val(g, type_entry, const_val);2151 LLVMValueRef init_val = gen_const_val(g, type_entry, const_val);
2152 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), "");
2148 LLVMSetInitializer(global_value, init_val);2153 LLVMSetInitializer(global_value, init_val);
2154 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
2149 LLVMSetGlobalConstant(global_value, true);2155 LLVMSetGlobalConstant(global_value, true);
2150 LLVMSetUnnamedAddr(global_value, true);2156 LLVMSetUnnamedAddr(global_value, true);
2151 expr->const_llvm_val = global_value;2157 expr->const_llvm_val = global_value;
...@@ -2171,15 +2177,22 @@ static void do_code_gen(CodeGen *g) {...@@ -2171,15 +2177,22 @@ static void do_code_gen(CodeGen *g) {
2171 }2177 }
21722178
2173 // TODO if the global is exported, set external linkage2179 // TODO if the global is exported, set external linkage
2174 LLVMValueRef global_value = LLVMAddGlobal(g->module, var->type->type_ref, "");2180 LLVMValueRef init_val;
2175 LLVMSetLinkage(global_value, LLVMPrivateLinkage);2181
21762182 assert(var->decl_node);
2177 if (var->is_const) {2183 assert(var->decl_node->type == NodeTypeVariableDeclaration);
2178 LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr);2184 AstNode *expr_node = var->decl_node->data.variable_declaration.expr;
2179 LLVMSetInitializer(global_value, init_val);2185 if (expr_node) {
2186 Expr *expr = get_resolved_expr(expr_node);
2187 ConstExprValue *const_val = &expr->const_val;
2188 assert(const_val->ok);
2189 TypeTableEntry *type_entry = expr->type_entry;
2190 init_val = gen_const_val(g, type_entry, const_val);
2180 } else {2191 } else {
2181 LLVMSetInitializer(global_value, LLVMConstNull(var->type->type_ref));2192 init_val = LLVMConstNull(var->type->type_ref);
2182 }2193 }
2194 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), "");
2195 LLVMSetInitializer(global_value, init_val);
2183 LLVMSetGlobalConstant(global_value, var->is_const);2196 LLVMSetGlobalConstant(global_value, var->is_const);
2184 LLVMSetUnnamedAddr(global_value, true);2197 LLVMSetUnnamedAddr(global_value, true);
21852198
test/run_tests.cpp+18
...@@ -1226,6 +1226,24 @@ pub fn main(args: [][]u8) i32 => {...@@ -1226,6 +1226,24 @@ pub fn main(args: [][]u8) i32 => {
1226}1226}
1227 )SOURCE", "OK\n");1227 )SOURCE", "OK\n");
12281228
1229 add_simple_case("statically initialized struct", R"SOURCE(
1230import "std.zig";
1231struct Foo {
1232 x: i32,
1233 y: bool,
1234}
1235var foo = Foo { .x = 13, .y = true, };
1236pub fn main(args: [][]u8) i32 => {
1237 foo.x += 1;
1238 if (foo.x != 14) {
1239 print_str("BAD\n");
1240 }
1241
1242 print_str("OK\n");
1243 return 0;
1244}
1245 )SOURCE", "OK\n");
1246
1229}1247}
12301248
12311249