diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-13 19:36:56 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-13 19:36:56 -0500 |
| commit | 647d13168a810936a778cc02e4cc99bd460c1f55 (patch) | |
| tree | c8c1f90b7bfc2fcb2c9369ad8636b39831b456af /src | |
| parent | 3f3630d7e349361116416dce36d2f69d7c3e318c (diff) | |
| download | zig-647d13168a810936a778cc02e4cc99bd460c1f55.tar.gz zig-647d13168a810936a778cc02e4cc99bd460c1f55.zip | |
IR: implement maybe return expression
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast_render.cpp | 2 | ||||
| -rw-r--r-- | src/ir.cpp | 146 | ||||
| -rw-r--r-- | src/ir_print.cpp | 2 |
3 files changed, 65 insertions, 85 deletions
diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 013408b4b7..e0a7bf6f31 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -759,7 +759,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, ": "); render_node_ungrouped(ar, var_decl->type); } - fprintf(ar->f, " = "); + fprintf(ar->f, " ?= "); render_node_grouped(ar, var_decl->expr); fprintf(ar->f, ") "); render_node_grouped(ar, node->data.if_var_expr.then_block); diff --git a/src/ir.cpp b/src/ir.cpp index 1ae05e4b64..b556b3b258 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1731,7 +1731,13 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o } } -static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) { +static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { + assert(basic_block); + + irb->current_basic_block = basic_block; +} + +static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypeReturnExpr); FnTableEntry *fn_entry = exec_fn_entry(irb->exec); @@ -1740,6 +1746,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) return irb->codegen->invalid_instruction; } + Scope *outer_scope = fn_entry->child_scope; + bool is_inline = ir_should_inline(irb); + AstNode *expr_node = node->data.return_expr.expr; switch (node->data.return_expr.kind) { case ReturnKindUnconditional: @@ -1747,28 +1756,46 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) IrInstruction *return_value; if (expr_node) { return_value = ir_gen_node(irb, expr_node, scope); + if (return_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; } else { return_value = ir_build_const_void(irb, scope, node); } - Scope *outer_scope = fn_entry->child_scope; + // TODO conditionally gen maybe defers and error defers ir_gen_defers_for_block(irb, scope, outer_scope, false, false); return ir_build_return(irb, scope, node, return_value); } case ReturnKindError: zig_panic("TODO gen IR for %%return"); case ReturnKindMaybe: - zig_panic("TODO gen IR for ?return"); + { + assert(expr_node); + IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); + if (maybe_val_ptr == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + IrInstruction *is_nonnull_val = ir_build_test_null(irb, scope, node, maybe_val_ptr); + + IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn"); + IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue"); + ir_build_cond_br(irb, scope, node, is_nonnull_val, continue_block, return_block, is_inline); + + ir_set_cursor_at_end(irb, return_block); + ir_gen_defers_for_block(irb, scope, outer_scope, false, true); + IrInstruction *null = ir_build_const_null(irb, scope, node); + ir_build_return(irb, scope, node, null); + + ir_set_cursor_at_end(irb, continue_block); + IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false); + if (lval != LValPurposeNone) + return unwrapped_ptr; + else + return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + } } zig_unreachable(); } -static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { - assert(basic_block); - - irb->current_basic_block = basic_block; -} - static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline) { @@ -3606,7 +3633,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeArrayAccessExpr: return ir_gen_array_access(irb, scope, node, lval); case NodeTypeReturnExpr: - return ir_lval_wrap(irb, scope, ir_gen_return(irb, scope, node), lval); + return ir_gen_return(irb, scope, node, lval); case NodeTypeFieldAccessExpr: return ir_gen_field_access(irb, scope, node, lval); case NodeTypeThisLiteral: @@ -3827,6 +3854,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n return ira->codegen->builtin_types.entry_invalid; } bool any_are_pure_error = (prev_inst->type_entry->id == TypeTableEntryIdPureError); + bool any_are_null = (prev_inst->type_entry->id == TypeTableEntryIdNullLit); for (size_t i = 1; i < instruction_count; i += 1) { IrInstruction *cur_inst = instructions[i]; TypeTableEntry *cur_type = cur_inst->type_entry; @@ -3836,9 +3864,15 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n } else if (prev_type->id == TypeTableEntryIdPureError) { prev_inst = cur_inst; continue; + } else if (prev_type->id == TypeTableEntryIdNullLit) { + prev_inst = cur_inst; + continue; } else if (cur_type->id == TypeTableEntryIdPureError) { any_are_pure_error = true; continue; + } else if (cur_type->id == TypeTableEntryIdNullLit) { + any_are_null = true; + continue; } else if (types_match_const_cast_only(prev_type, cur_type)) { continue; } else if (types_match_const_cast_only(cur_type, prev_type)) { @@ -3889,9 +3923,13 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n return ira->codegen->builtin_types.entry_invalid; } } else { - add_node_error(ira->codegen, source_node, + ErrorMsg *msg = add_node_error(ira->codegen, source_node, buf_sprintf("incompatible types: '%s' and '%s'", buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); + add_error_note(ira->codegen, msg, prev_inst->source_node, + buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); + add_error_note(ira->codegen, msg, cur_inst->source_node, + buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -3903,9 +3941,23 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n add_node_error(ira->codegen, source_node, buf_sprintf("unable to make error union out of number literal")); return ira->codegen->builtin_types.entry_invalid; + } else if (prev_inst->type_entry->id == TypeTableEntryIdNullLit) { + add_node_error(ira->codegen, source_node, + buf_sprintf("unable to make error union out of null literal")); + return ira->codegen->builtin_types.entry_invalid; } else { return get_error_type(ira->codegen, prev_inst->type_entry); } + } else if (any_are_null && prev_inst->type_entry->id != TypeTableEntryIdNullLit) { + if (prev_inst->type_entry->id == TypeTableEntryIdNumLitInt || + prev_inst->type_entry->id == TypeTableEntryIdNumLitFloat) + { + add_node_error(ira->codegen, source_node, + buf_sprintf("unable to make maybe out of number literal")); + return ira->codegen->builtin_types.entry_invalid; + } else { + return get_maybe_type(ira->codegen, prev_inst->type_entry); + } } else { return prev_inst->type_entry; } @@ -9053,16 +9105,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // TypeTableEntry *expected_type, AstNode *node) //{ -// if (!node->data.return_expr.expr) { -// node->data.return_expr.expr = create_ast_void_node(g, import, node); -// normalize_parent_ptrs(node); -// } -// // TypeTableEntry *expected_return_type = get_return_type(context); // // switch (node->data.return_expr.kind) { -// case ReturnKindUnconditional: -// zig_panic("TODO moved to ir.cpp"); // case ReturnKindError: // { // TypeTableEntry *expected_err_type; @@ -9093,34 +9138,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // return g->builtin_types.entry_invalid; // } // } -// case ReturnKindMaybe: -// { -// TypeTableEntry *expected_maybe_type; -// if (expected_type) { -// expected_maybe_type = get_maybe_type(g, expected_type); -// } else { -// expected_maybe_type = nullptr; -// } -// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type, -// node->data.return_expr.expr); -// if (resolved_type->id == TypeTableEntryIdInvalid) { -// return resolved_type; -// } else if (resolved_type->id == TypeTableEntryIdMaybe) { -// if (expected_return_type->id != TypeTableEntryIdMaybe) { -// ErrorMsg *msg = add_node_error(g, node, -// buf_sprintf("?return statement in function with return type '%s'", -// buf_ptr(&expected_return_type->name))); -// AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; -// add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); -// } -// -// return resolved_type->data.maybe.child_type; -// } else { -// add_node_error(g, node->data.return_expr.expr, -// buf_sprintf("expected maybe type, found '%s'", buf_ptr(&resolved_type->name))); -// return g->builtin_types.entry_invalid; -// } -// } // } // zig_unreachable(); //} @@ -9344,43 +9361,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // return nullptr; // } // } -// case ReturnKindMaybe: -// { -// assert(value_type->id == TypeTableEntryIdMaybe); -// TypeTableEntry *child_type = value_type->data.maybe.child_type; -// -// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn"); -// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue"); -// -// LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); -// LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, ""); -// -// LLVMValueRef zero = LLVMConstNull(LLVMInt1Type()); -// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, ""); -// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block); -// -// LLVMPositionBuilderAtEnd(g->builder, return_block); -// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; -// assert(return_type->id == TypeTableEntryIdMaybe); -// if (handle_is_ptr(return_type)) { -// assert(g->cur_ret_ptr); -// -// LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, ""); -// LLVMBuildStore(g->builder, zero, maybe_bit_ptr); -// LLVMBuildRetVoid(g->builder); -// } else { -// LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref); -// gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull); -// } -// -// LLVMPositionBuilderAtEnd(g->builder, continue_block); -// if (type_has_bits(child_type)) { -// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, ""); -// return get_handle_value(g, val_ptr, child_type); -// } else { -// return nullptr; -// } -// } // } // zig_unreachable(); //} diff --git a/src/ir_print.cpp b/src/ir_print.cpp index d00ba372b4..8f9001edbd 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -585,7 +585,7 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { static void ir_print_test_null(IrPrint *irp, IrInstructionTestNull *instruction) { fprintf(irp->f, "*"); ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, " == null"); + fprintf(irp->f, " != null"); } static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) { |
