authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-23 15:05:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-29 22:14:09-07:00
log1f7ec741fa5b1d9ba3826e06a8a8a0feec58876f
treeb74ec329f2e7e128087282adedcd37752b7cceaf
parent6149f7318986214a34b09347f28ba48b2a614fef

implement `?return` expression


5 files changed, 102 insertions(+), 3 deletions(-)

doc/codegen.md created+33
...@@ -0,0 +1,33 @@
1# Code Generation
2
3## Data Representation
4
5Every type has a "handle". If a type is a simple primitive type such as i32 or
6f64, the handle is "by value", meaning that we pass around the value itself when
7we refer to a value of that type.
8
9If a type is a container, error union, maybe type, slice, or array, then its
10handle is a pointer, and everywhere we refer to a value of this type we refer to
11a pointer.
12
13Parameters and return values are always passed as handles.
14
15Error union types are represented as:
16
17 struct {
18 error: u32,
19 payload: T,
20 }
21
22Maybe types are represented as:
23
24 struct {
25 payload: T,
26 is_non_null: u1,
27 }
28
29## Data Optimizations
30
31Maybe pointer types are special: the 0x0 pointer value is used to represent a
32null pointer. Thus, instead of the struct above, maybe pointer types are
33represented as a `usize` in codegen and the handle is by value.
src/analyze.cpp+28-1
...@@ -6271,7 +6271,34 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,...@@ -6271,7 +6271,34 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
6271 }6271 }
6272 }6272 }
6273 case ReturnKindMaybe:6273 case ReturnKindMaybe:
6274 zig_panic("TODO");6274 {
6275 TypeTableEntry *expected_maybe_type;
6276 if (expected_type) {
6277 expected_maybe_type = get_maybe_type(g, expected_type);
6278 } else {
6279 expected_maybe_type = nullptr;
6280 }
6281 TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type,
6282 node->data.return_expr.expr);
6283 if (resolved_type->id == TypeTableEntryIdInvalid) {
6284 return resolved_type;
6285 } else if (resolved_type->id == TypeTableEntryIdMaybe) {
6286 TypeTableEntry *return_type = context->fn_entry->type_entry->data.fn.fn_type_id.return_type;
6287 if (return_type->id != TypeTableEntryIdMaybe) {
6288 ErrorMsg *msg = add_node_error(g, node,
6289 buf_sprintf("?return statement in function with return type '%s'",
6290 buf_ptr(&return_type->name)));
6291 AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
6292 add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
6293 }
6294
6295 return resolved_type->data.maybe.child_type;
6296 } else {
6297 add_node_error(g, node->data.return_expr.expr,
6298 buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
6299 return g->builtin_types.entry_invalid;
6300 }
6301 }
6275 }6302 }
6276 zig_unreachable();6303 zig_unreachable();
6277}6304}
src/codegen.cpp+39-1
...@@ -2497,7 +2497,45 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {...@@ -2497,7 +2497,45 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
2497 }2497 }
2498 }2498 }
2499 case ReturnKindMaybe:2499 case ReturnKindMaybe:
2500 zig_panic("TODO");2500 {
2501 assert(value_type->id == TypeTableEntryIdMaybe);
2502 TypeTableEntry *child_type = value_type->data.maybe.child_type;
2503
2504 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn");
2505 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue");
2506
2507 set_debug_source_node(g, node);
2508 LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
2509 LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, "");
2510
2511 LLVMValueRef zero = LLVMConstNull(LLVMInt1Type());
2512 LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, "");
2513 LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
2514
2515 LLVMPositionBuilderAtEnd(g->builder, return_block);
2516 TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2517 assert(return_type->id == TypeTableEntryIdMaybe);
2518 if (handle_is_ptr(return_type)) {
2519 assert(g->cur_ret_ptr);
2520
2521 set_debug_source_node(g, node);
2522 LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, "");
2523 LLVMBuildStore(g->builder, zero, maybe_bit_ptr);
2524 LLVMBuildRetVoid(g->builder);
2525 } else {
2526 LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref);
2527 gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull);
2528 }
2529
2530 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2531 if (type_has_bits(child_type)) {
2532 set_debug_source_node(g, node);
2533 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
2534 return get_handle_value(g, node, val_ptr, child_type);
2535 } else {
2536 return nullptr;
2537 }
2538 }
2501 }2539 }
2502 zig_unreachable();2540 zig_unreachable();
2503}2541}
test/cases/return_type_type.zig+1-1
...@@ -11,7 +11,7 @@ pub struct SmallList(inline T: type, inline STATIC_SIZE: usize) {...@@ -11,7 +11,7 @@ pub struct SmallList(inline T: type, inline STATIC_SIZE: usize) {
11}11}
1212
13#attribute("test")13#attribute("test")
14fn function_with_return_type_type() {14fn functionWithReturnTypeType() {
15 var list: List(i32) = undefined;15 var list: List(i32) = undefined;
16 var list2: List(i32) = undefined;16 var list2: List(i32) = undefined;
17 list.length = 10;17 list.length = 10;
test/self_hosted.zig+1
...@@ -6,6 +6,7 @@ const other = @import("other.zig");...@@ -6,6 +6,7 @@ const other = @import("other.zig");
6const test_return_type_type = @import("cases/return_type_type.zig");6const test_return_type_type = @import("cases/return_type_type.zig");
7const test_zeroes = @import("cases/zeroes.zig");7const test_zeroes = @import("cases/zeroes.zig");
8const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig");8const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig");
9const test_maybe_return = @import("cases/maybe_return.zig");
910
10// normal comment11// normal comment
11/// this is a documentation comment12/// this is a documentation comment