authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-24 18:34:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-24 18:34:50-07:00
log419652ee8ff709deae988603ecca2c335599d969
tree7678349497a842e64073df781fe241d3dae9c84d
parentca7b85b32e26acfd716c02047966254a34cd2237

ability to return structs byvalue from functions

closes #57

4 files changed, 191 insertions(+), 71 deletions(-)

src/all_types.hpp+6-1
...@@ -214,6 +214,9 @@ struct AstNodeParamDecl {...@@ -214,6 +214,9 @@ struct AstNodeParamDecl {
214214
215 // populated by semantic analyzer215 // populated by semantic analyzer
216 VariableTableEntry *variable;216 VariableTableEntry *variable;
217 bool is_byval;
218 int src_index;
219 int gen_index;
217};220};
218221
219struct AstNodeBlock {222struct AstNodeBlock {
...@@ -794,7 +797,8 @@ struct TypeTableEntryEnum {...@@ -794,7 +797,8 @@ struct TypeTableEntryEnum {
794};797};
795798
796struct TypeTableEntryFn {799struct TypeTableEntryFn {
797 TypeTableEntry *return_type;800 TypeTableEntry *src_return_type;
801 TypeTableEntry *gen_return_type;
798 TypeTableEntry **param_types;802 TypeTableEntry **param_types;
799 int src_param_count;803 int src_param_count;
800 LLVMTypeRef raw_type_ref;804 LLVMTypeRef raw_type_ref;
...@@ -989,6 +993,7 @@ struct CodeGen {...@@ -989,6 +993,7 @@ struct CodeGen {
989993
990 OutType out_type;994 OutType out_type;
991 FnTableEntry *cur_fn;995 FnTableEntry *cur_fn;
996 LLVMValueRef cur_ret_ptr;
992 // TODO remove this in favor of get_resolved_expr(expr_node)->context997 // TODO remove this in favor of get_resolved_expr(expr_node)->context
993 BlockContext *cur_block_context;998 BlockContext *cur_block_context;
994 ZigList<LLVMBasicBlockRef> break_block_stack;999 ZigList<LLVMBasicBlockRef> break_block_stack;
src/analyze.cpp+82-40
...@@ -424,6 +424,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -424,6 +424,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
424 AstNodeFnProto *fn_proto = &node->data.fn_proto;424 AstNodeFnProto *fn_proto = &node->data.fn_proto;
425425
426 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);426 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
427 fn_table_entry->type_entry = fn_type;
427 fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv;428 fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv;
428429
429 for (int i = 0; i < fn_proto->directives->length; i += 1) {430 for (int i = 0; i < fn_proto->directives->length; i += 1) {
...@@ -452,22 +453,18 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -452,22 +453,18 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
452 }453 }
453454
454 int src_param_count = node->data.fn_proto.params.length;455 int src_param_count = node->data.fn_proto.params.length;
455
456 fn_type->size_in_bits = g->pointer_size_bytes * 8;456 fn_type->size_in_bits = g->pointer_size_bytes * 8;
457 fn_type->align_in_bits = g->pointer_size_bytes * 8;457 fn_type->align_in_bits = g->pointer_size_bytes * 8;
458 fn_type->data.fn.src_param_count = src_param_count;458 fn_type->data.fn.src_param_count = src_param_count;
459 fn_type->data.fn.param_types = allocate<TypeTableEntry*>(src_param_count);459 fn_type->data.fn.param_types = allocate<TypeTableEntry*>(src_param_count);
460460
461 fn_table_entry->type_entry = fn_type;461 // first, analyze the parameters and return type in order they appear in
462462 // source code in order for error messages to be in the best order.
463 buf_resize(&fn_type->name, 0);463 buf_resize(&fn_type->name, 0);
464 const char *export_str = fn_table_entry->internal_linkage ? "" : "export ";464 const char *export_str = fn_table_entry->internal_linkage ? "" : "export ";
465 const char *inline_str = fn_table_entry->is_inline ? "inline " : "";465 const char *inline_str = fn_table_entry->is_inline ? "inline " : "";
466 const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";466 const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";
467 buf_appendf(&fn_type->name, "%s%s%sfn(", export_str, inline_str, naked_str);467 buf_appendf(&fn_type->name, "%s%s%sfn(", export_str, inline_str, naked_str);
468 int gen_param_count = 0;
469 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(src_param_count);
470 LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + src_param_count);
471 for (int i = 0; i < src_param_count; i += 1) {468 for (int i = 0; i < src_param_count; i += 1) {
472 AstNode *child = node->data.fn_proto.params.at(i);469 AstNode *child = node->data.fn_proto.params.at(i);
473 assert(child->type == NodeTypeParamDecl);470 assert(child->type == NodeTypeParamDecl);
...@@ -475,6 +472,54 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -475,6 +472,54 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
475 child->data.param_decl.type);472 child->data.param_decl.type);
476 fn_type->data.fn.param_types[i] = type_entry;473 fn_type->data.fn.param_types[i] = type_entry;
477474
475 const char *comma = (i == 0) ? "" : ", ";
476 buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->name));
477 }
478
479 TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
480 node->data.fn_proto.return_type);
481 fn_type->data.fn.src_return_type = return_type;
482 if (return_type->id == TypeTableEntryIdInvalid) {
483 fn_proto->skip = true;
484 }
485 fn_type->data.fn.is_var_args = fn_proto->is_var_args;
486 if (fn_proto->is_var_args) {
487 const char *comma = (src_param_count == 0) ? "" : ", ";
488 buf_appendf(&fn_type->name, "%s...", comma);
489 }
490
491 buf_appendf(&fn_type->name, ")");
492 if (return_type->id != TypeTableEntryIdVoid) {
493 buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name));
494 }
495
496
497 // next, loop over the parameters again and compute debug information
498 // and codegen information
499 bool first_arg_return = handle_is_ptr(return_type);
500 // +1 for maybe making the first argument the return value
501 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + src_param_count);
502 // +1 because 0 is the return type and +1 for maybe making first arg ret val
503 LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + src_param_count);
504 param_di_types[0] = return_type->di_type;
505 int gen_param_index = 0;
506 TypeTableEntry *gen_return_type;
507 if (first_arg_return) {
508 TypeTableEntry *gen_type = get_pointer_to_type(g, return_type, false);
509 gen_param_types[gen_param_index] = gen_type->type_ref;
510 gen_param_index += 1;
511 // after the gen_param_index += 1 because 0 is the return type
512 param_di_types[gen_param_index] = gen_type->di_type;
513 gen_return_type = g->builtin_types.entry_void;
514 } else {
515 gen_return_type = return_type;
516 }
517 fn_type->data.fn.gen_return_type = gen_return_type;
518 for (int i = 0; i < src_param_count; i += 1) {
519 AstNode *child = node->data.fn_proto.params.at(i);
520 assert(child->type == NodeTypeParamDecl);
521 TypeTableEntry *type_entry = fn_type->data.fn.param_types[i];
522
478 if (type_entry->id == TypeTableEntryIdUnreachable) {523 if (type_entry->id == TypeTableEntryIdUnreachable) {
479 add_node_error(g, child->data.param_decl.type,524 add_node_error(g, child->data.param_decl.type,
480 buf_sprintf("parameter of type 'unreachable' not allowed"));525 buf_sprintf("parameter of type 'unreachable' not allowed"));
...@@ -483,39 +528,29 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -483,39 +528,29 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
483 fn_proto->skip = true;528 fn_proto->skip = true;
484 }529 }
485530
531 child->data.param_decl.src_index = i;
532 child->data.param_decl.gen_index = -1;
533
486 if (!fn_proto->skip && type_entry->size_in_bits > 0) {534 if (!fn_proto->skip && type_entry->size_in_bits > 0) {
487 const char *comma = (gen_param_count == 0) ? "" : ", ";
488 buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->name));
489535
490 TypeTableEntry *gen_type = handle_is_ptr(type_entry) ?536 TypeTableEntry *gen_type;
491 get_pointer_to_type(g, type_entry, true) : type_entry;537 if (handle_is_ptr(type_entry)) {
492 gen_param_types[gen_param_count] = gen_type->type_ref;538 gen_type = get_pointer_to_type(g, type_entry, true);
539 child->data.param_decl.is_byval = true;
540 } else {
541 gen_type = type_entry;
542 }
543 gen_param_types[gen_param_index] = gen_type->type_ref;
544 child->data.param_decl.gen_index = gen_param_index;
493545
494 gen_param_count += 1;546 gen_param_index += 1;
495547
496 // after the gen_param_count += 1 because 0 is the return type548 // after the gen_param_index += 1 because 0 is the return type
497 param_di_types[gen_param_count] = gen_type->di_type;549 param_di_types[gen_param_index] = gen_type->di_type;
498 }550 }
499 }551 }
500552
501 fn_type->data.fn.gen_param_count = gen_param_count;553 fn_type->data.fn.gen_param_count = gen_param_index;
502 fn_type->data.fn.is_var_args = fn_proto->is_var_args;
503 if (fn_proto->is_var_args) {
504 const char *comma = (gen_param_count == 0) ? "" : ", ";
505 buf_appendf(&fn_type->name, "%s...", comma);
506 }
507
508 TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
509 node->data.fn_proto.return_type);
510 fn_type->data.fn.return_type = return_type;
511 if (return_type->id == TypeTableEntryIdInvalid) {
512 fn_proto->skip = true;
513 }
514
515 buf_appendf(&fn_type->name, ")");
516 if (return_type->id != TypeTableEntryIdVoid) {
517 buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name));
518 }
519554
520 if (fn_proto->skip) {555 if (fn_proto->skip) {
521 return;556 return;
...@@ -526,12 +561,11 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -526,12 +561,11 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
526 fn_type = table_entry->value;561 fn_type = table_entry->value;
527 fn_table_entry->type_entry = fn_type;562 fn_table_entry->type_entry = fn_type;
528 } else {563 } else {
529 fn_type->data.fn.raw_type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count,564 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
530 fn_type->data.fn.is_var_args);565 gen_param_types, gen_param_index, fn_type->data.fn.is_var_args);
531 fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);566 fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
532 param_di_types[0] = return_type->di_type;
533 fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,567 fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
534 param_di_types, gen_param_count + 1, 0);568 param_di_types, gen_param_index + 1, 0);
535569
536 import->fn_type_table.put(&fn_type->name, fn_type);570 import->fn_type_table.put(&fn_type->name, fn_type);
537 }571 }
...@@ -550,7 +584,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -550,7 +584,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
550 LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?584 LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
551 LLVMInternalLinkage : LLVMExternalLinkage);585 LLVMInternalLinkage : LLVMExternalLinkage);
552586
553 if (return_type->id == TypeTableEntryIdUnreachable) {587 if (gen_return_type->id == TypeTableEntryIdUnreachable) {
554 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);588 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
555 }589 }
556 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);590 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
...@@ -3320,7 +3354,13 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import,...@@ -3320,7 +3354,13 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import,
3320 analyze_expression(g, import, context, expected_param_type, child);3354 analyze_expression(g, import, context, expected_param_type, child);
3321 }3355 }
33223356
3323 return unwrapped_node_type(fn_proto->return_type);3357 TypeTableEntry *return_type = unwrapped_node_type(fn_proto->return_type);
3358
3359 if (handle_is_ptr(return_type)) {
3360 context->cast_alloca_list.append(node);
3361 }
3362
3363 return return_type;
3324}3364}
33253365
3326static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,3366static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -3417,7 +3457,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import...@@ -3417,7 +3457,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
34173457
3418 // function pointer3458 // function pointer
3419 if (invoke_type_entry->id == TypeTableEntryIdFn) {3459 if (invoke_type_entry->id == TypeTableEntryIdFn) {
3420 return invoke_type_entry->data.fn.return_type;3460 return invoke_type_entry->data.fn.src_return_type;
3421 } else {3461 } else {
3422 add_node_error(g, fn_ref_expr,3462 add_node_error(g, fn_ref_expr,
3423 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));3463 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
...@@ -3681,6 +3721,7 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,...@@ -3681,6 +3721,7 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
3681 } else {3721 } else {
3682 add_node_error(g, node->data.return_expr.expr,3722 add_node_error(g, node->data.return_expr.expr,
3683 buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));3723 buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));
3724 return g->builtin_types.entry_invalid;
3684 }3725 }
3685 }3726 }
3686 case ReturnKindMaybe:3727 case ReturnKindMaybe:
...@@ -4711,6 +4752,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -4711,6 +4752,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
4711 return type_entry->id == TypeTableEntryIdStruct ||4752 return type_entry->id == TypeTableEntryIdStruct ||
4712 (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) ||4753 (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) ||
4713 type_entry->id == TypeTableEntryIdMaybe ||4754 type_entry->id == TypeTableEntryIdMaybe ||
4714 type_entry->id == TypeTableEntryIdArray;4755 type_entry->id == TypeTableEntryIdArray ||
4756 (type_entry->id == TypeTableEntryIdErrorUnion && type_entry->data.error.child_type->size_in_bits > 0);
4715}4757}
47164758
src/codegen.cpp+82-30
...@@ -81,11 +81,6 @@ static TypeTableEntry *get_type_for_type_node(AstNode *node) {...@@ -81,11 +81,6 @@ static TypeTableEntry *get_type_for_type_node(AstNode *node) {
81 return const_val->data.x_type;81 return const_val->data.x_type;
82}82}
8383
84static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
85 assert(param_decl_node->type == NodeTypeParamDecl);
86 return get_type_for_type_node(param_decl_node->data.param_decl.type)->size_in_bits == 0;
87}
88
89static void add_debug_source_node(CodeGen *g, AstNode *node) {84static void add_debug_source_node(CodeGen *g, AstNode *node) {
90 if (!g->cur_block_context)85 if (!g->cur_block_context)
91 return;86 return;
...@@ -424,17 +419,22 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -424,17 +419,22 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
424 fn_type = get_expr_type(fn_ref_expr);419 fn_type = get_expr_type(fn_ref_expr);
425 }420 }
426421
427 int expected_param_count = fn_type->data.fn.src_param_count;422 TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type;
423 TypeTableEntry *gen_return_type = fn_type->data.fn.gen_return_type;
424
428 int fn_call_param_count = node->data.fn_call_expr.params.length;425 int fn_call_param_count = node->data.fn_call_expr.params.length;
429 int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0);426 bool first_arg_ret = handle_is_ptr(src_return_type);
427 int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0) + (first_arg_ret ? 1 : 0);
430 bool is_var_args = fn_type->data.fn.is_var_args;428 bool is_var_args = fn_type->data.fn.is_var_args;
431 assert((is_var_args && actual_param_count >= expected_param_count) ||
432 actual_param_count == expected_param_count);
433429
434 // don't really include void values430 // don't really include void values
435 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);431 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
436432
437 int gen_param_index = 0;433 int gen_param_index = 0;
434 if (first_arg_ret) {
435 gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr;
436 gen_param_index += 1;
437 }
438 if (struct_type) {438 if (struct_type) {
439 gen_param_values[gen_param_index] = gen_expr(g, first_param_expr);439 gen_param_values[gen_param_index] = gen_expr(g, first_param_expr);
440 gen_param_index += 1;440 gen_param_index += 1;
...@@ -454,8 +454,10 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -454,8 +454,10 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
454 LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,454 LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,
455 gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");455 gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
456456
457 if (fn_type->data.fn.return_type->id == TypeTableEntryIdUnreachable) {457 if (gen_return_type->id == TypeTableEntryIdUnreachable) {
458 return LLVMBuildUnreachable(g->builder);458 return LLVMBuildUnreachable(g->builder);
459 } else if (first_arg_ret) {
460 return node->data.fn_call_expr.tmp_ptr;
459 } else {461 } else {
460 return result;462 return result;
461 }463 }
...@@ -1236,21 +1238,60 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -1236,21 +1238,60 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
1236 zig_unreachable();1238 zig_unreachable();
1237}1239}
12381240
1241static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {
1242 TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.src_return_type;
1243 if (handle_is_ptr(return_type)) {
1244 assert(g->cur_ret_ptr);
1245 gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type);
1246 add_debug_source_node(g, source_node);
1247 return LLVMBuildRetVoid(g->builder);
1248 } else {
1249 add_debug_source_node(g, source_node);
1250 return LLVMBuildRet(g->builder, value);
1251 }
1252}
1253
1239static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {1254static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
1240 assert(node->type == NodeTypeReturnExpr);1255 assert(node->type == NodeTypeReturnExpr);
1241 AstNode *param_node = node->data.return_expr.expr;1256 AstNode *param_node = node->data.return_expr.expr;
1242 assert(param_node);1257 assert(param_node);
1258 LLVMValueRef value = gen_expr(g, param_node);
1259 TypeTableEntry *value_type = get_expr_type(param_node);
12431260
1244 switch (node->data.return_expr.kind) {1261 switch (node->data.return_expr.kind) {
1245 case ReturnKindUnconditional:1262 case ReturnKindUnconditional:
1263 return gen_return(g, node, value);
1264 case ReturnKindError:
1246 {1265 {
1247 LLVMValueRef value = gen_expr(g, param_node);1266 assert(value_type->id == TypeTableEntryIdErrorUnion);
1267 TypeTableEntry *child_type = value_type->data.error.child_type;
12481268
1249 add_debug_source_node(g, node);1269 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrReturnYes");
1250 return LLVMBuildRet(g->builder, value);1270 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrReturnNo");
1271
1272 LLVMPositionBuilderAtEnd(g->builder, return_block);
1273 if (child_type->size_in_bits > 0) {
1274 zig_panic("TODO write the error tag value to sret");
1275 add_debug_source_node(g, node);
1276 LLVMBuildRetVoid(g->builder);
1277 } else {
1278 add_debug_source_node(g, node);
1279 LLVMBuildRet(g->builder, value);
1280 }
1281
1282 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1283 if (child_type->size_in_bits > 0) {
1284 add_debug_source_node(g, node);
1285 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
1286 if (handle_is_ptr(child_type)) {
1287 return val_ptr;
1288 } else {
1289 return LLVMBuildLoad(g->builder, val_ptr, "");
1290 }
1291 } else {
1292 return nullptr;
1293 }
1251 }1294 }
1252 case ReturnKindError:
1253 zig_panic("TODO");
1254 case ReturnKindMaybe:1295 case ReturnKindMaybe:
1255 zig_panic("TODO");1296 zig_panic("TODO");
1256 }1297 }
...@@ -1386,13 +1427,8 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i...@@ -1386,13 +1427,8 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
1386 return_value = gen_expr(g, statement_node);1427 return_value = gen_expr(g, statement_node);
1387 }1428 }
13881429
1389 if (implicit_return_type) {1430 if (implicit_return_type && implicit_return_type->id != TypeTableEntryIdUnreachable) {
1390 add_debug_source_node(g, block_node);1431 gen_return(g, block_node, return_value);
1391 if (implicit_return_type->id == TypeTableEntryIdVoid) {
1392 LLVMBuildRetVoid(g->builder);
1393 } else if (implicit_return_type->id != TypeTableEntryIdUnreachable) {
1394 LLVMBuildRet(g->builder, return_value);
1395 }
1396 }1432 }
13971433
1398 g->cur_block_context = old_block_context;1434 g->cur_block_context = old_block_context;
...@@ -2257,25 +2293,35 @@ static void do_code_gen(CodeGen *g) {...@@ -2257,25 +2293,35 @@ static void do_code_gen(CodeGen *g) {
2257 assert(proto_node->type == NodeTypeFnProto);2293 assert(proto_node->type == NodeTypeFnProto);
2258 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;2294 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
22592295
2296 if (handle_is_ptr(fn_table_entry->type_entry->data.fn.src_return_type)) {
2297 LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
2298 LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
2299 }
2300
2260 // set parameter attributes2301 // set parameter attributes
2261 int gen_param_index = 0;
2262 for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) {2302 for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) {
2263 AstNode *param_node = fn_proto->params.at(param_decl_i);2303 AstNode *param_node = fn_proto->params.at(param_decl_i);
2264 assert(param_node->type == NodeTypeParamDecl);2304 assert(param_node->type == NodeTypeParamDecl);
2265 if (is_param_decl_type_void(g, param_node))2305
2306 int gen_index = param_node->data.param_decl.gen_index;
2307
2308 if (gen_index < 0) {
2266 continue;2309 continue;
2310 }
2311
2267 AstNode *type_node = param_node->data.param_decl.type;2312 AstNode *type_node = param_node->data.param_decl.type;
2268 TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);2313 TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);
2269 LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_param_index);2314 LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_index);
2270 bool param_is_noalias = param_node->data.param_decl.is_noalias;2315 bool param_is_noalias = param_node->data.param_decl.is_noalias;
2271 if (param_type->id == TypeTableEntryIdPointer && param_is_noalias) {2316 if (param_type->id == TypeTableEntryIdPointer && param_is_noalias) {
2272 LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);2317 LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
2273 } else if (param_type->id == TypeTableEntryIdPointer &&2318 }
2274 param_type->data.pointer.is_const)2319 if (param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) {
2275 {
2276 LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);2320 LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
2277 }2321 }
2278 gen_param_index += 1;2322 if (param_node->data.param_decl.is_byval) {
2323 LLVMAddAttribute(argument_val, LLVMByValAttribute);
2324 }
2279 }2325 }
22802326
2281 }2327 }
...@@ -2287,6 +2333,11 @@ static void do_code_gen(CodeGen *g) {...@@ -2287,6 +2333,11 @@ static void do_code_gen(CodeGen *g) {
2287 AstNode *fn_def_node = fn_table_entry->fn_def_node;2333 AstNode *fn_def_node = fn_table_entry->fn_def_node;
2288 LLVMValueRef fn = fn_table_entry->fn_value;2334 LLVMValueRef fn = fn_table_entry->fn_value;
2289 g->cur_fn = fn_table_entry;2335 g->cur_fn = fn_table_entry;
2336 if (handle_is_ptr(fn_table_entry->type_entry->data.fn.src_return_type)) {
2337 g->cur_ret_ptr = LLVMGetParam(fn, 0);
2338 } else {
2339 g->cur_ret_ptr = nullptr;
2340 }
22902341
2291 AstNode *proto_node = fn_table_entry->proto_node;2342 AstNode *proto_node = fn_table_entry->proto_node;
2292 assert(proto_node->type == NodeTypeFnProto);2343 assert(proto_node->type == NodeTypeFnProto);
...@@ -2368,8 +2419,9 @@ static void do_code_gen(CodeGen *g) {...@@ -2368,8 +2419,9 @@ static void do_code_gen(CodeGen *g) {
2368 AstNode *param_decl = fn_proto->params.at(param_i);2419 AstNode *param_decl = fn_proto->params.at(param_i);
2369 assert(param_decl->type == NodeTypeParamDecl);2420 assert(param_decl->type == NodeTypeParamDecl);
23702421
2371 if (is_param_decl_type_void(g, param_decl))2422 if (param_decl->data.param_decl.gen_index < 0) {
2372 continue;2423 continue;
2424 }
23732425
2374 VariableTableEntry *variable = param_decl->data.param_decl.variable;2426 VariableTableEntry *variable = param_decl->data.param_decl.variable;
23752427
test/run_tests.cpp+21
...@@ -1233,6 +1233,27 @@ pub fn main(args: [][]u8) %void => {...@@ -1233,6 +1233,27 @@ pub fn main(args: [][]u8) %void => {
1233 print_str("OK\n");1233 print_str("OK\n");
1234 return;1234 return;
1235 }1235 }
1236}
1237 )SOURCE", "OK\n");
1238
1239 add_simple_case("return struct byval from function", R"SOURCE(
1240import "std.zig";
1241struct Foo {
1242 x: i32,
1243 y: i32,
1244}
1245fn make_foo() Foo => {
1246 Foo {
1247 .x = 1234,
1248 .y = 5678,
1249 }
1250}
1251pub fn main(args: [][]u8) %void => {
1252 const foo = make_foo();
1253 if (foo.y != 5678) {
1254 print_str("BAD\n");
1255 }
1256 print_str("OK\n");
1236}1257}
1237 )SOURCE", "OK\n");1258 )SOURCE", "OK\n");
1238}1259}