authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-22 13:22:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-22 13:22:40-07:00
log431170d981edf1eba790cefe0f27a6142634ea1d
tree67f8d09417dd0bb151f0b22ac9fa52e90f2664aa
parent437e9b954d8a47a1acb6aa5327c6473ab8d9267c

codegen: fix struct pointer field access


5 files changed, 101 insertions(+), 24 deletions(-)

doc/targets.md created+11
...@@ -0,0 +1,11 @@
1# How to Add Support For More Targets
2
3Create bootstrap code in std/bootstrap.zig and add conditional compilation
4logic. This code is responsible for the real executable entry point, calling
5main(argc, argv, env) and making the exit syscall when main returns.
6
7How to pass a byvalue struct parameter in the C calling convention is
8target-specific. Add logic for how to do function prototypes and function calls
9for the target when an exported or external function has a byvalue struct.
10
11Write the target-specific code in std.zig.
example/structs/structs.zig+11-5
...@@ -2,7 +2,7 @@ export executable "structs";...@@ -2,7 +2,7 @@ export executable "structs";
22
3use "std.zig";3use "std.zig";
44
5export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {5pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
6 var foo : Foo;6 var foo : Foo;
77
8 foo.a = foo.a + 1;8 foo.a = foo.a + 1;
...@@ -30,10 +30,14 @@ struct Foo {...@@ -30,10 +30,14 @@ struct Foo {
30}30}
3131
32struct Node {32struct Node {
33 val: i32,33 val: Val,
34 next: &Node,34 next: &Node,
35}35}
3636
37struct Val {
38 x: i32,
39}
40
37fn test_foo(foo : Foo) {41fn test_foo(foo : Foo) {
38 if !foo.b {42 if !foo.b {
39 print_str("BAD\n");43 print_str("BAD\n");
...@@ -46,13 +50,15 @@ fn modify_foo(foo : &Foo) {...@@ -46,13 +50,15 @@ fn modify_foo(foo : &Foo) {
4650
47fn test_point_to_self() {51fn test_point_to_self() {
48 var root : Node;52 var root : Node;
49 root.val = 1;53 root.val.x = 1;
5054
51 var node : Node;55 var node : Node;
52 node.next = &root;56 node.next = &root;
53 node.val = 2;57 node.val.x = 2;
58
59 root.next = &node;
5460
55 if node.next.val != 1 {61 if node.next.next.next.val.x != 1 {
56 print_str("BAD\n");62 print_str("BAD\n");
57 }63 }
58}64}
src/analyze.cpp+5-1
...@@ -273,10 +273,14 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_...@@ -273,10 +273,14 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_
273static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type) {273static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type) {
274 assert(struct_type->id == TypeTableEntryIdStruct);274 assert(struct_type->id == TypeTableEntryIdStruct);
275275
276 if (struct_type->data.structure.fields) {
277 // we already resolved this type. skip
278 return;
279 }
280
276 AstNode *decl_node = struct_type->data.structure.decl_node;281 AstNode *decl_node = struct_type->data.structure.decl_node;
277282
278 assert(struct_type->di_type);283 assert(struct_type->di_type);
279 assert(!struct_type->data.structure.fields);
280284
281 int field_count = decl_node->data.struct_decl.fields.length;285 int field_count = decl_node->data.struct_decl.fields.length;
282 struct_type->data.structure.field_count = field_count;286 struct_type->data.structure.field_count = field_count;
src/codegen.cpp+51-18
...@@ -63,6 +63,8 @@ void codegen_set_libc_path(CodeGen *g, Buf *libc_path) {...@@ -63,6 +63,8 @@ void codegen_set_libc_path(CodeGen *g, Buf *libc_path) {
63}63}
6464
65static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);65static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
66static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
67static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
66 68
6769
68static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {70static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
...@@ -192,6 +194,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -192,6 +194,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
192static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {194static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
193 assert(node->type == NodeTypeArrayAccessExpr);195 assert(node->type == NodeTypeArrayAccessExpr);
194196
197 // TODO gen_lvalue
195 LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);198 LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);
196 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);199 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);
197200
...@@ -209,15 +212,34 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {...@@ -209,15 +212,34 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
209static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {212static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
210 assert(node->type == NodeTypeFieldAccessExpr);213 assert(node->type == NodeTypeFieldAccessExpr);
211214
212 //TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);215 AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
213 LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
214 assert(struct_ptr);
215216
216 /*217 LLVMValueRef struct_ptr;
217 if (struct_type->id == TypeTableEntryIdPointer) {218 if (struct_expr_node->type == NodeTypeSymbol) {
218 zig_panic("TODO pointer field struct access");219 VariableTableEntry *var = find_variable(struct_expr_node->codegen_node->expr_node.block_context,
220 &struct_expr_node->data.symbol);
221 assert(var);
222
223 if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) {
224 add_debug_source_node(g, node);
225 struct_ptr = LLVMBuildLoad(g->builder, var->value_ref, "");
226 } else {
227 struct_ptr = var->value_ref;
228 }
229 } else if (struct_expr_node->type == NodeTypeFieldAccessExpr) {
230 struct_ptr = gen_field_access_expr(g, struct_expr_node, true);
231 TypeTableEntry *field_type = get_expr_type(struct_expr_node);
232 if (field_type->id == TypeTableEntryIdPointer) {
233 // we have a double pointer so we must dereference it once
234 add_debug_source_node(g, node);
235 struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, "");
236 }
237 } else {
238 struct_ptr = gen_expr(g, struct_expr_node);
219 }239 }
220 */240
241 assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
242 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
221243
222 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;244 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
223245
...@@ -229,15 +251,20 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou...@@ -229,15 +251,20 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
229 return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");251 return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
230}252}
231253
232static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {254static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
233 assert(node->type == NodeTypeArrayAccessExpr);255 assert(node->type == NodeTypeArrayAccessExpr);
234256
235 LLVMValueRef ptr = gen_array_ptr(g, node);257 LLVMValueRef ptr = gen_array_ptr(g, node);
236 add_debug_source_node(g, node);258
237 return LLVMBuildLoad(g->builder, ptr, "");259 if (is_lvalue) {
260 return ptr;
261 } else {
262 add_debug_source_node(g, node);
263 return LLVMBuildLoad(g->builder, ptr, "");
264 }
238}265}
239266
240static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {267static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
241 assert(node->type == NodeTypeFieldAccessExpr);268 assert(node->type == NodeTypeFieldAccessExpr);
242269
243 TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);270 TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);
...@@ -255,21 +282,26 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {...@@ -255,21 +282,26 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
255 {282 {
256 TypeTableEntry *type_entry;283 TypeTableEntry *type_entry;
257 LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);284 LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
258 return LLVMBuildLoad(g->builder, ptr, "");285 if (is_lvalue) {
286 return ptr;
287 } else {
288 add_debug_source_node(g, node);
289 return LLVMBuildLoad(g->builder, ptr, "");
290 }
259 } else {291 } else {
260 zig_panic("gen_field_access_expr bad struct type");292 zig_panic("gen_field_access_expr bad struct type");
261 }293 }
262}294}
263295
264static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *parent_node, AstNode *node,296static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
265 TypeTableEntry **out_type_entry)297 TypeTableEntry **out_type_entry)
266{298{
267 LLVMValueRef target_ref;299 LLVMValueRef target_ref;
268300
269 if (node->type == NodeTypeSymbol) {301 if (node->type == NodeTypeSymbol) {
270 VariableTableEntry *var = find_variable(parent_node->codegen_node->expr_node.block_context,302 VariableTableEntry *var = find_variable(expr_node->codegen_node->expr_node.block_context,
271 &node->data.symbol);303 &node->data.symbol);
272304 assert(var);
273 // semantic checking ensures no variables are constant305 // semantic checking ensures no variables are constant
274 assert(!var->is_const);306 assert(!var->is_const);
275307
...@@ -631,6 +663,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -631,6 +663,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
631 AstNode *lhs_node = node->data.bin_op_expr.op1;663 AstNode *lhs_node = node->data.bin_op_expr.op1;
632664
633 TypeTableEntry *op1_type;665 TypeTableEntry *op1_type;
666
634 LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);667 LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
635668
636 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);669 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
...@@ -957,9 +990,9 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -957,9 +990,9 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
957 case NodeTypeFnCallExpr:990 case NodeTypeFnCallExpr:
958 return gen_fn_call_expr(g, node);991 return gen_fn_call_expr(g, node);
959 case NodeTypeArrayAccessExpr:992 case NodeTypeArrayAccessExpr:
960 return gen_array_access_expr(g, node);993 return gen_array_access_expr(g, node, false);
961 case NodeTypeFieldAccessExpr:994 case NodeTypeFieldAccessExpr:
962 return gen_field_access_expr(g, node);995 return gen_field_access_expr(g, node, false);
963 case NodeTypeUnreachable:996 case NodeTypeUnreachable:
964 add_debug_source_node(g, node);997 add_debug_source_node(g, node);
965 return LLVMBuildUnreachable(g->builder);998 return LLVMBuildUnreachable(g->builder);
...@@ -1153,7 +1186,7 @@ static void do_code_gen(CodeGen *g) {...@@ -1153,7 +1186,7 @@ static void do_code_gen(CodeGen *g) {
1153 assert(proto_node->type == NodeTypeFnProto);1186 assert(proto_node->type == NodeTypeFnProto);
1154 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;1187 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
11551188
1156 LLVMTypeRef ret_type = fn_proto_type_from_type_node(g, fn_proto->return_type);1189 LLVMTypeRef ret_type = get_type_for_type_node(g, fn_proto->return_type)->type_ref;
1157 int param_count = count_non_void_params(g, &fn_proto->params);1190 int param_count = count_non_void_params(g, &fn_proto->params);
1158 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);1191 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
1159 int gen_param_index = 0;1192 int gen_param_index = 0;
test/run_tests.cpp+23
...@@ -573,6 +573,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -573,6 +573,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
573 if foo.c != 100 {573 if foo.c != 100 {
574 print_str("BAD\n");574 print_str("BAD\n");
575 }575 }
576 test_point_to_self();
576 print_str("OK\n");577 print_str("OK\n");
577 return 0;578 return 0;
578}579}
...@@ -588,6 +589,28 @@ fn test_foo(foo : Foo) {...@@ -588,6 +589,28 @@ fn test_foo(foo : Foo) {
588}589}
589fn test_mutation(foo : &Foo) {590fn test_mutation(foo : &Foo) {
590 foo.c = 100;591 foo.c = 100;
592}
593struct Node {
594 val: Val,
595 next: &Node,
596}
597
598struct Val {
599 x: i32,
600}
601fn test_point_to_self() {
602 var root : Node;
603 root.val.x = 1;
604
605 var node : Node;
606 node.next = &root;
607 node.val.x = 2;
608
609 root.next = &node;
610
611 if node.next.next.next.val.x != 1 {
612 print_str("BAD\n");
613 }
591}614}
592 )SOURCE", "OK\n");615 )SOURCE", "OK\n");
593616