authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 22:55:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 22:55:29-07:00
logbd77bc749a1b38ef754fdd5b7e14a8228cb6f72c
tree1cc38a744572519ef574fcd21bb9a3a6d18772d7
parent0f02e29a2b7a975407c7f3b4ed742f886e0c1add

structs are working


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

example/structs/structs.zig-2
......@@ -2,8 +2,6 @@ export executable "structs";
22
33use "std.zig";
44
5// Note: this example is not working because codegen is confused about
6// how byvalue structs which are in memory on the stack work
75export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
86 let mut foo : Foo;
97
src/analyze.cpp+43-39
......@@ -758,6 +758,47 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
758758 zig_unreachable();
759759}
760760
761static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
762 TypeTableEntry *expected_type, AstNode *node)
763{
764 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type);
765 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
766
767 if (wanted_type->id == TypeTableEntryIdInvalid ||
768 actual_type->id == TypeTableEntryIdInvalid)
769 {
770 return g->builtin_types.entry_invalid;
771 }
772
773 CastNode *cast_node = &node->codegen_node->data.cast_node;
774
775 // special casing this for now, TODO think about casting and do a general solution
776 if (wanted_type == g->builtin_types.entry_isize &&
777 actual_type->id == TypeTableEntryIdPointer)
778 {
779 cast_node->op = CastOpPtrToInt;
780 return wanted_type;
781 } else if (wanted_type->id == TypeTableEntryIdInt &&
782 actual_type->id == TypeTableEntryIdInt)
783 {
784 cast_node->op = CastOpIntWidenOrShorten;
785 return wanted_type;
786 } else if (wanted_type == g->builtin_types.entry_string &&
787 actual_type->id == TypeTableEntryIdArray &&
788 actual_type->data.array.child_type == g->builtin_types.entry_u8)
789 {
790 cast_node->op = CastOpArrayToString;
791 context->cast_expr_alloca_list.append(node);
792 return wanted_type;
793 } else {
794 add_node_error(g, node,
795 buf_sprintf("invalid cast from type '%s' to '%s'",
796 buf_ptr(&actual_type->name),
797 buf_ptr(&wanted_type->name)));
798 return g->builtin_types.entry_invalid;
799 }
800}
801
761802static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
762803 TypeTableEntry *expected_type, AstNode *node)
763804{
......@@ -1100,45 +1141,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
11001141 break;
11011142 }
11021143 case NodeTypeCastExpr:
1103 {
1104 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type);
1105 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr,
1106 node->data.cast_expr.expr);
1107
1108 if (wanted_type->id == TypeTableEntryIdInvalid ||
1109 actual_type->id == TypeTableEntryIdInvalid)
1110 {
1111 return_type = g->builtin_types.entry_invalid;
1112 break;
1113 }
1114
1115 CastNode *cast_node = &node->codegen_node->data.cast_node;
1116
1117 // special casing this for now, TODO think about casting and do a general solution
1118 if (wanted_type == g->builtin_types.entry_isize &&
1119 actual_type->id == TypeTableEntryIdPointer)
1120 {
1121 cast_node->op = CastOpPtrToInt;
1122 return_type = wanted_type;
1123 } else if (wanted_type->id == TypeTableEntryIdInt &&
1124 actual_type->id == TypeTableEntryIdInt)
1125 {
1126 cast_node->op = CastOpIntWidenOrShorten;
1127 return_type = wanted_type;
1128 } else if (wanted_type == g->builtin_types.entry_string &&
1129 actual_type->id == TypeTableEntryIdArray &&
1130 actual_type->data.array.child_type == g->builtin_types.entry_u8)
1131 {
1132 cast_node->op = CastOpArrayToString;
1133 return_type = wanted_type;
1134 } else {
1135 add_node_error(g, node,
1136 buf_sprintf("TODO handle cast from '%s' to '%s'",
1137 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
1138 return_type = g->builtin_types.entry_invalid;
1139 }
1140 break;
1141 }
1144 return_type = analyze_cast_expr(g, import, context, expected_type, node);
1145 break;
11421146 case NodeTypePrefixOpExpr:
11431147 switch (node->data.prefix_op_expr.prefix_op) {
11441148 case PrefixOpBoolNot:
src/analyze.hpp+4
......@@ -193,6 +193,7 @@ struct BlockContext {
193193 BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef
194194 BlockContext *parent; // nullptr when this is the root
195195 HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
196 ZigList<AstNode *> cast_expr_alloca_list;
196197 LLVMZigDIScope *di_scope;
197198};
198199
......@@ -244,6 +245,9 @@ enum CastOp {
244245
245246struct CastNode {
246247 CastOp op;
248 // if op is CastOpArrayToString, this will be a pointer to
249 // the string struct on the stack
250 LLVMValueRef ptr;
247251};
248252
249253struct CodeGenNode {
src/codegen.cpp+56-49
......@@ -59,30 +59,31 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
5959}
6060
6161static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
62
6263
63static LLVMTypeRef to_llvm_type(AstNode *type_node) {
64static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
6465 assert(type_node->type == NodeTypeType);
6566 assert(type_node->codegen_node);
6667 assert(type_node->codegen_node->data.type_node.entry);
67
68 return type_node->codegen_node->data.type_node.entry->type_ref;
68 return type_node->codegen_node->data.type_node.entry;
6969}
7070
71static LLVMZigDIType *to_llvm_debug_type(AstNode *type_node) {
72 assert(type_node->type == NodeTypeType);
73 assert(type_node->codegen_node);
74 assert(type_node->codegen_node->data.type_node.entry);
71static LLVMTypeRef fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
72 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
7573
76 return type_node->codegen_node->data.type_node.entry->di_type;
74 if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {
75 return get_pointer_to_type(g, type_entry, true)->type_ref;
76 } else {
77 return type_entry->type_ref;
78 }
7779}
7880
79static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
80 assert(type_node->type == NodeTypeType);
81 assert(type_node->codegen_node);
82 assert(type_node->codegen_node->data.type_node.entry);
83 return type_node->codegen_node->data.type_node.entry;
81static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) {
82 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
83 return type_entry->di_type;
8484}
8585
86
8687static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
8788 return get_type_for_type_node(g, type_node) == g->builtin_types.entry_unreachable;
8889}
......@@ -198,20 +199,6 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
198199 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
199200}
200201
201static LLVMValueRef gen_field_val(CodeGen *g, AstNode *node) {
202 assert(node->type == NodeTypeFieldAccessExpr);
203
204 LLVMValueRef struct_val = gen_expr(g, node->data.field_access_expr.struct_expr);
205 assert(struct_val);
206
207 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
208 assert(codegen_field_access->field_index >= 0);
209
210 add_debug_source_node(g, node);
211 return LLVMBuildExtractValue(g->builder, struct_val, codegen_field_access->field_index, "");
212}
213
214/*
215202static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
216203 assert(node->type == NodeTypeFieldAccessExpr);
217204
......@@ -223,9 +210,9 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
223210
224211 assert(codegen_field_access->field_index >= 0);
225212
213 add_debug_source_node(g, node);
226214 return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
227215}
228*/
229216
230217static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
231218 assert(node->type == NodeTypeArrayAccessExpr);
......@@ -249,11 +236,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
249236 zig_panic("gen_field_access_expr bad array field");
250237 }
251238 } else if (struct_type->id == TypeTableEntryIdStruct) {
252 /*
253239 LLVMValueRef ptr = gen_field_ptr(g, node);
254240 return LLVMBuildLoad(g->builder, ptr, "");
255 */
256 return gen_field_val(g, node);
257241 } else {
258242 zig_panic("gen_field_access_expr bad struct type");
259243 }
......@@ -311,14 +295,19 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
311295 }
312296 case CastOpArrayToString:
313297 {
314 LLVMValueRef struct_vals[] = {
315 expr_val,
316 LLVMConstInt(g->builtin_types.entry_usize->type_ref, actual_type->data.array.len, false)
317 };
318 unsigned field_count = g->builtin_types.entry_string->data.structure.field_count;
319 assert(field_count == 2);
320 return LLVMConstNamedStruct(g->builtin_types.entry_string->type_ref,
321 struct_vals, field_count);
298 assert(cast_node->ptr);
299
300 add_debug_source_node(g, node);
301
302 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, "");
303 LLVMBuildStore(g->builder, expr_val, ptr_ptr);
304
305 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, "");
306 LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
307 actual_type->data.array.len, false);
308 LLVMBuildStore(g->builder, len_val, len_ptr);
309
310 return cast_node->ptr;
322311 }
323312 }
324313 zig_unreachable();
......@@ -580,6 +569,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
580569 assert(array_type->id == TypeTableEntryIdArray);
581570 op1_type = array_type->data.array.child_type;
582571 target_ref = gen_array_ptr(g, lhs_node);
572 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
573 target_ref = gen_field_ptr(g, lhs_node);
583574 } else {
584575 zig_panic("bad assign target");
585576 }
......@@ -717,6 +708,7 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
717708static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
718709 assert(block_node->type == NodeTypeBlock);
719710
711 BlockContext *old_block_context = g->cur_block_context;
720712 g->cur_block_context = block_node->codegen_node->data.block_node.block_context;
721713
722714 LLVMValueRef return_value;
......@@ -726,6 +718,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
726718 }
727719
728720 if (implicit_return_type) {
721 add_debug_source_node(g, block_node);
729722 if (implicit_return_type == g->builtin_types.entry_void) {
730723 LLVMBuildRetVoid(g->builder);
731724 } else if (implicit_return_type != g->builtin_types.entry_unreachable) {
......@@ -733,6 +726,8 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
733726 }
734727 }
735728
729 g->cur_block_context = old_block_context;
730
736731 return return_value;
737732}
738733
......@@ -934,6 +929,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
934929 } else if (variable->is_ptr) {
935930 if (variable->type->id == TypeTableEntryIdArray) {
936931 return variable->value_ref;
932 } else if (variable->type->id == TypeTableEntryIdStruct) {
933 return variable->value_ref;
937934 } else {
938935 add_debug_source_node(g, node);
939936 return LLVMBuildLoad(g->builder, variable->value_ref, "");
......@@ -994,12 +991,12 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
994991 LLVMZigDIFile *di_file)
995992{
996993 LLVMZigDIType **types = allocate<LLVMZigDIType*>(1 + fn_proto->params.length);
997 types[0] = to_llvm_debug_type(fn_proto->return_type);
994 types[0] = to_llvm_debug_type(g, fn_proto->return_type);
998995 int types_len = fn_proto->params.length + 1;
999996 for (int i = 0; i < fn_proto->params.length; i += 1) {
1000997 AstNode *param_node = fn_proto->params.at(i);
1001998 assert(param_node->type == NodeTypeParamDecl);
1002 LLVMZigDIType *param_type = to_llvm_debug_type(param_node->data.param_decl.type);
999 LLVMZigDIType *param_type = to_llvm_debug_type(g, param_node->data.param_decl.type);
10031000 types[i + 1] = param_type;
10041001 }
10051002 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
......@@ -1026,7 +1023,7 @@ static void do_code_gen(CodeGen *g) {
10261023 assert(proto_node->type == NodeTypeFnProto);
10271024 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
10281025
1029 LLVMTypeRef ret_type = to_llvm_type(fn_proto->return_type);
1026 LLVMTypeRef ret_type = fn_proto_type_from_type_node(g, fn_proto->return_type);
10301027 int param_count = count_non_void_params(g, &fn_proto->params);
10311028 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
10321029 int gen_param_index = 0;
......@@ -1036,7 +1033,7 @@ static void do_code_gen(CodeGen *g) {
10361033 if (is_param_decl_type_void(g, param_node))
10371034 continue;
10381035 AstNode *type_node = param_node->data.param_decl.type;
1039 param_types[gen_param_index] = to_llvm_type(type_node);
1036 param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node);
10401037 gen_param_index += 1;
10411038 }
10421039 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);
......@@ -1061,8 +1058,8 @@ static void do_code_gen(CodeGen *g) {
10611058 }
10621059
10631060 // Generate function definitions.
1064 for (int i = 0; i < g->fn_defs.length; i += 1) {
1065 FnTableEntry *fn_table_entry = g->fn_defs.at(i);
1061 for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
1062 FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
10661063 ImportTableEntry *import = fn_table_entry->import_entry;
10671064 AstNode *fn_def_node = fn_table_entry->fn_def_node;
10681065 LLVMValueRef fn = fn_table_entry->fn_value;
......@@ -1101,8 +1098,8 @@ static void do_code_gen(CodeGen *g) {
11011098 LLVMGetParams(fn, params);
11021099
11031100 int non_void_index = 0;
1104 for (int i = 0; i < fn_proto->params.length; i += 1) {
1105 AstNode *param_decl = fn_proto->params.at(i);
1101 for (int param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
1102 AstNode *param_decl = fn_proto->params.at(param_i);
11061103 assert(param_decl->type == NodeTypeParamDecl);
11071104 if (is_param_decl_type_void(g, param_decl))
11081105 continue;
......@@ -1115,8 +1112,8 @@ static void do_code_gen(CodeGen *g) {
11151112
11161113 // Set up debug info for blocks and variables and
11171114 // allocate all local variables
1118 for (int i = 0; i < codegen_fn_def->all_block_contexts.length; i += 1) {
1119 BlockContext *block_context = codegen_fn_def->all_block_contexts.at(i);
1115 for (int bc_i = 0; bc_i < codegen_fn_def->all_block_contexts.length; bc_i += 1) {
1116 BlockContext *block_context = codegen_fn_def->all_block_contexts.at(bc_i);
11201117
11211118 if (block_context->parent) {
11221119 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder,
......@@ -1157,6 +1154,16 @@ static void do_code_gen(CodeGen *g) {
11571154 import->di_file, var->decl_node->line + 1,
11581155 var->type->di_type, !g->strip_debug_symbols, 0, arg_no);
11591156 }
1157
1158 // allocate structs which are the result of casts
1159 for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {
1160 AstNode *cast_expr_node = block_context->cast_expr_alloca_list.at(cea_i);
1161 assert(cast_expr_node->type == NodeTypeCastExpr);
1162 CastNode *cast_codegen = &cast_expr_node->codegen_node->data.cast_node;
1163 TypeTableEntry *type_entry = get_type_for_type_node(g, cast_expr_node->data.cast_expr.type);
1164 add_debug_source_node(g, cast_expr_node);
1165 cast_codegen->ptr = LLVMBuildAlloca(g->builder, type_entry->type_ref, "");
1166 }
11601167 }
11611168
11621169 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
test/run_tests.cpp+21
......@@ -477,6 +477,27 @@ export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
477477}
478478 )SOURCE", "OK\n");
479479
480 add_simple_case("structs", R"SOURCE(
481use "std.zig";
482
483export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
484 let mut foo : Foo;
485 foo.a = foo.a + 1;
486 foo.b = foo.a == 1;
487 test_foo(foo);
488 return 0;
489}
490struct Foo {
491 a : i32,
492 b : bool,
493 c : f32,
494}
495fn test_foo(foo : Foo) {
496 if foo.b {
497 print_str("OK\n" as string);
498 }
499}
500 )SOURCE", "OK\n");
480501}
481502
482503static void add_compile_failure_test_cases(void) {