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";
22
33use "std.zig";
44
5export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
5pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
66 var foo : Foo;
77
88 foo.a = foo.a + 1;
......@@ -30,10 +30,14 @@ struct Foo {
3030}
3131
3232struct Node {
33 val: i32,
33 val: Val,
3434 next: &Node,
3535}
3636
37struct Val {
38 x: i32,
39}
40
3741fn test_foo(foo : Foo) {
3842 if !foo.b {
3943 print_str("BAD\n");
......@@ -46,13 +50,15 @@ fn modify_foo(foo : &Foo) {
4650
4751fn test_point_to_self() {
4852 var root : Node;
49 root.val = 1;
53 root.val.x = 1;
5054
5155 var node : Node;
5256 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 {
5662 print_str("BAD\n");
5763 }
5864}
src/analyze.cpp+5-1
......@@ -273,10 +273,14 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_
273273static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type) {
274274 assert(struct_type->id == TypeTableEntryIdStruct);
275275
276 if (struct_type->data.structure.fields) {
277 // we already resolved this type. skip
278 return;
279 }
280
276281 AstNode *decl_node = struct_type->data.structure.decl_node;
277282
278283 assert(struct_type->di_type);
279 assert(!struct_type->data.structure.fields);
280284
281285 int field_count = decl_node->data.struct_decl.fields.length;
282286 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) {
6363}
6464
6565static 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);
6668
6769
6870static 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) {
192194static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
193195 assert(node->type == NodeTypeArrayAccessExpr);
194196
197 // TODO gen_lvalue
195198 LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);
196199 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) {
209212static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
210213 assert(node->type == NodeTypeFieldAccessExpr);
211214
212 //TypeTableEntry *struct_type = get_expr_type(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);
215 AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
215216
216 /*
217 if (struct_type->id == TypeTableEntryIdPointer) {
218 zig_panic("TODO pointer field struct access");
217 LLVMValueRef struct_ptr;
218 if (struct_expr_node->type == NodeTypeSymbol) {
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);
219239 }
220 */
240
241 assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
242 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
221243
222244 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
229251 return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
230252}
231253
232static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
254static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
233255 assert(node->type == NodeTypeArrayAccessExpr);
234256
235257 LLVMValueRef ptr = gen_array_ptr(g, node);
236 add_debug_source_node(g, node);
237 return LLVMBuildLoad(g->builder, ptr, "");
258
259 if (is_lvalue) {
260 return ptr;
261 } else {
262 add_debug_source_node(g, node);
263 return LLVMBuildLoad(g->builder, ptr, "");
264 }
238265}
239266
240static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
267static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
241268 assert(node->type == NodeTypeFieldAccessExpr);
242269
243270 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) {
255282 {
256283 TypeTableEntry *type_entry;
257284 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 }
259291 } else {
260292 zig_panic("gen_field_access_expr bad struct type");
261293 }
262294}
263295
264static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *parent_node, AstNode *node,
296static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
265297 TypeTableEntry **out_type_entry)
266298{
267299 LLVMValueRef target_ref;
268300
269301 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,
271303 &node->data.symbol);
272
304 assert(var);
273305 // semantic checking ensures no variables are constant
274306 assert(!var->is_const);
275307
......@@ -631,6 +663,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
631663 AstNode *lhs_node = node->data.bin_op_expr.op1;
632664
633665 TypeTableEntry *op1_type;
666
634667 LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
635668
636669 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) {
957990 case NodeTypeFnCallExpr:
958991 return gen_fn_call_expr(g, node);
959992 case NodeTypeArrayAccessExpr:
960 return gen_array_access_expr(g, node);
993 return gen_array_access_expr(g, node, false);
961994 case NodeTypeFieldAccessExpr:
962 return gen_field_access_expr(g, node);
995 return gen_field_access_expr(g, node, false);
963996 case NodeTypeUnreachable:
964997 add_debug_source_node(g, node);
965998 return LLVMBuildUnreachable(g->builder);
......@@ -1153,7 +1186,7 @@ static void do_code_gen(CodeGen *g) {
11531186 assert(proto_node->type == NodeTypeFnProto);
11541187 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;
11571190 int param_count = count_non_void_params(g, &fn_proto->params);
11581191 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
11591192 int gen_param_index = 0;
test/run_tests.cpp+23
......@@ -573,6 +573,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
573573 if foo.c != 100 {
574574 print_str("BAD\n");
575575 }
576 test_point_to_self();
576577 print_str("OK\n");
577578 return 0;
578579}
......@@ -588,6 +589,28 @@ fn test_foo(foo : Foo) {
588589}
589590fn test_mutation(foo : &Foo) {
590591 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 }
591614}
592615 )SOURCE", "OK\n");
593616