authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-23 03:19:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-23 03:19:22-07:00
loge21369a1539063773734432993bc2c23680f0913
treeb48333c170245c8e95f7dd75bcef81a84d4dc9f2
parentebd7aeb5411c8dba35d6898524928d7ee905c06b

codegen: support byvalue struct assignment


5 files changed, 77 insertions(+), 7 deletions(-)

example/structs/structs.zig+16
...@@ -19,6 +19,8 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -19,6 +19,8 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
1919
20 test_point_to_self();20 test_point_to_self();
2121
22 test_byval_assign();
23
22 print_str("OK\n");24 print_str("OK\n");
23 return 0;25 return 0;
24}26}
...@@ -62,3 +64,17 @@ fn test_point_to_self() {...@@ -62,3 +64,17 @@ fn test_point_to_self() {
62 print_str("BAD\n");64 print_str("BAD\n");
63 }65 }
64}66}
67
68fn test_byval_assign() {
69 var foo1 : Foo;
70 var foo2 : Foo;
71
72 foo1.a = 1234;
73
74 if foo2.a != 0 { print_str("BAD\n"); }
75
76 foo2 = foo1;
77
78 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
79
80}
src/analyze.cpp+5-2
...@@ -276,8 +276,11 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE...@@ -276,8 +276,11 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
276 AstNode *decl_node = struct_type->data.structure.decl_node;276 AstNode *decl_node = struct_type->data.structure.decl_node;
277277
278 if (struct_type->data.structure.embedded_in_current) {278 if (struct_type->data.structure.embedded_in_current) {
279 add_node_error(g, decl_node,279 if (!struct_type->data.structure.reported_infinite_err) {
280 buf_sprintf("struct has infinite size"));280 struct_type->data.structure.reported_infinite_err = true;
281 add_node_error(g, decl_node,
282 buf_sprintf("struct has infinite size"));
283 }
281 return;284 return;
282 }285 }
283286
src/analyze.hpp+3
...@@ -43,9 +43,11 @@ struct TypeTableEntryStruct {...@@ -43,9 +43,11 @@ struct TypeTableEntryStruct {
43 bool is_packed;43 bool is_packed;
44 int field_count;44 int field_count;
45 TypeStructField *fields;45 TypeStructField *fields;
46 uint64_t size_bytes;
4647
47 // set this flag temporarily to detect infinite loops48 // set this flag temporarily to detect infinite loops
48 bool embedded_in_current;49 bool embedded_in_current;
50 bool reported_infinite_err;
49};51};
5052
51struct TypeTableEntryNumLit {53struct TypeTableEntryNumLit {
...@@ -201,6 +203,7 @@ struct CodeGen {...@@ -201,6 +203,7 @@ struct CodeGen {
201 bool verbose;203 bool verbose;
202 ErrColor err_color;204 ErrColor err_color;
203 ImportTableEntry *root_import;205 ImportTableEntry *root_import;
206 LLVMValueRef memcpy_fn_val;
204};207};
205208
206struct VariableTableEntry {209struct VariableTableEntry {
src/codegen.cpp+40-5
...@@ -666,15 +666,36 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -666,15 +666,36 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
666666
667 LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);667 LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
668668
669 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
670
669 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);671 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
670672
671 if (node->data.bin_op_expr.bin_op == BinOpTypeAssign) {673 if (op1_type->id == TypeTableEntryIdStruct) {
672 // value is ready as is674 assert(op2_type->id == TypeTableEntryIdStruct);
673 } else {675 assert(op1_type == op2_type);
676 assert(node->data.bin_op_expr.bin_op == BinOpTypeAssign);
677
678 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
679
680 add_debug_source_node(g, node);
681 LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, value, ptr_u8, "");
682 LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, target_ref, ptr_u8, "");
683
684 LLVMValueRef params[] = {
685 dest_ptr, // dest pointer
686 src_ptr, // source pointer
687 LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8), op1_type->size_in_bits / 8, false), // byte count
688 LLVMConstInt(LLVMInt32Type(), op1_type->align_in_bits / 8, false), // align in bits
689 LLVMConstNull(LLVMInt1Type()), // is volatile
690 };
691
692 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
693 }
694
695 if (node->data.bin_op_expr.bin_op != BinOpTypeAssign) {
674 add_debug_source_node(g, node->data.bin_op_expr.op1);696 add_debug_source_node(g, node->data.bin_op_expr.op1);
675 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");697 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
676698
677 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
678 value = gen_arithmetic_bin_op(g, left_value, value, op1_type, op2_type, node);699 value = gen_arithmetic_bin_op(g, left_value, value, op1_type, op2_type, node);
679 }700 }
680701
...@@ -1158,6 +1179,20 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {...@@ -1158,6 +1179,20 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {
1158static void do_code_gen(CodeGen *g) {1179static void do_code_gen(CodeGen *g) {
1159 assert(!g->errors.length);1180 assert(!g->errors.length);
11601181
1182 {
1183 LLVMTypeRef param_types[] = {
1184 LLVMPointerType(LLVMInt8Type(), 0),
1185 LLVMPointerType(LLVMInt8Type(), 0),
1186 LLVMIntType(g->pointer_size_bytes * 8),
1187 LLVMInt32Type(),
1188 LLVMInt1Type(),
1189 };
1190 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false);
1191 Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8);
1192 g->memcpy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1193 assert(LLVMGetIntrinsicID(g->memcpy_fn_val));
1194 }
1195
1161 // Generate module level variables1196 // Generate module level variables
1162 for (int i = 0; i < g->global_vars.length; i += 1) {1197 for (int i = 0; i < g->global_vars.length; i += 1) {
1163 VariableTableEntry *var = g->global_vars.at(i);1198 VariableTableEntry *var = g->global_vars.at(i);
...@@ -1379,7 +1414,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -1379,7 +1414,7 @@ static void define_builtin_types(CodeGen *g) {
1379 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);1414 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
1380 entry->type_ref = LLVMInt1Type();1415 entry->type_ref = LLVMInt1Type();
1381 buf_init_from_str(&entry->name, "bool");1416 buf_init_from_str(&entry->name, "bool");
1382 entry->size_in_bits = 1;1417 entry->size_in_bits = 8;
1383 entry->align_in_bits = 8;1418 entry->align_in_bits = 8;
1384 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),1419 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1385 entry->size_in_bits, entry->align_in_bits,1420 entry->size_in_bits, entry->align_in_bits,
test/run_tests.cpp+13
...@@ -574,6 +574,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -574,6 +574,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
574 print_str("BAD\n");574 print_str("BAD\n");
575 }575 }
576 test_point_to_self();576 test_point_to_self();
577 test_byval_assign();
577 print_str("OK\n");578 print_str("OK\n");
578 return 0;579 return 0;
579}580}
...@@ -611,6 +612,18 @@ fn test_point_to_self() {...@@ -611,6 +612,18 @@ fn test_point_to_self() {
611 if node.next.next.next.val.x != 1 {612 if node.next.next.next.val.x != 1 {
612 print_str("BAD\n");613 print_str("BAD\n");
613 }614 }
615}
616fn test_byval_assign() {
617 var foo1 : Foo;
618 var foo2 : Foo;
619
620 foo1.a = 1234;
621
622 if foo2.a != 0 { print_str("BAD\n"); }
623
624 foo2 = foo1;
625
626 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
614}627}
615 )SOURCE", "OK\n");628 )SOURCE", "OK\n");
616629