| ... | @@ -110,21 +110,22 @@ static void ir_ref_var(VariableTableEntry *var) { | ... | @@ -110,21 +110,22 @@ static void ir_ref_var(VariableTableEntry *var) { |
| 110 | var->ref_count += 1; | 110 | var->ref_count += 1; |
| 111 | } | 111 | } |
| 112 | | 112 | |
| 113 | static IrBasicBlock *ir_build_basic_block_raw(IrBuilder *irb, const char *name_hint) { | 113 | static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) { |
| 114 | IrBasicBlock *result = allocate<IrBasicBlock>(1); | 114 | IrBasicBlock *result = allocate<IrBasicBlock>(1); |
| | 115 | result->scope = scope; |
| 115 | result->name_hint = name_hint; | 116 | result->name_hint = name_hint; |
| 116 | result->debug_id = exec_next_debug_id(irb->exec); | 117 | result->debug_id = exec_next_debug_id(irb->exec); |
| 117 | return result; | 118 | return result; |
| 118 | } | 119 | } |
| 119 | | 120 | |
| 120 | static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint) { | 121 | static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) { |
| 121 | IrBasicBlock *result = ir_build_basic_block_raw(irb, name_hint); | 122 | IrBasicBlock *result = ir_create_basic_block(irb, scope, name_hint); |
| 122 | irb->exec->basic_block_list.append(result); | 123 | irb->exec->basic_block_list.append(result); |
| 123 | return result; | 124 | return result; |
| 124 | } | 125 | } |
| 125 | | 126 | |
| 126 | static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) { | 127 | static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) { |
| 127 | IrBasicBlock *new_bb = ir_build_basic_block_raw(irb, other_bb->name_hint); | 128 | IrBasicBlock *new_bb = ir_create_basic_block(irb, other_bb->scope, other_bb->name_hint); |
| 128 | ir_link_new_bb(new_bb, other_bb); | 129 | ir_link_new_bb(new_bb, other_bb); |
| 129 | return new_bb; | 130 | return new_bb; |
| 130 | } | 131 | } |
| ... | @@ -1240,19 +1241,21 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr | ... | @@ -1240,19 +1241,21 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr |
| 1240 | return new_instruction; | 1241 | return new_instruction; |
| 1241 | } | 1242 | } |
| 1242 | | 1243 | |
| 1243 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope *inner_scope, Scope *outer_scope, | 1244 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1244 | bool gen_error_defers, bool gen_maybe_defers) | 1245 | bool gen_error_defers, bool gen_maybe_defers) |
| 1245 | { | 1246 | { |
| 1246 | while (inner_scope != outer_scope) { | 1247 | while (inner_scope != outer_scope) { |
| | 1248 | assert(inner_scope); |
| 1247 | if (inner_scope->id == ScopeIdDefer) { | 1249 | if (inner_scope->id == ScopeIdDefer) { |
| 1248 | assert(inner_scope->source_node->type == NodeTypeDefer); | 1250 | AstNode *defer_node = inner_scope->source_node; |
| 1249 | ReturnKind defer_kind = inner_scope->source_node->data.defer.kind; | 1251 | assert(defer_node->type == NodeTypeDefer); |
| | 1252 | ReturnKind defer_kind = defer_node->data.defer.kind; |
| 1250 | if (defer_kind == ReturnKindUnconditional || | 1253 | if (defer_kind == ReturnKindUnconditional || |
| 1251 | (gen_error_defers && defer_kind == ReturnKindError) || | 1254 | (gen_error_defers && defer_kind == ReturnKindError) || |
| 1252 | (gen_maybe_defers && defer_kind == ReturnKindMaybe)) | 1255 | (gen_maybe_defers && defer_kind == ReturnKindMaybe)) |
| 1253 | { | 1256 | { |
| 1254 | AstNode *defer_expr_node = inner_scope->source_node->data.defer.expr; | 1257 | AstNode *defer_expr_node = defer_node->data.defer.expr; |
| 1255 | ir_gen_node(irb, defer_expr_node, parent_scope); | 1258 | ir_gen_node(irb, defer_expr_node, defer_node->data.defer.parent_scope); |
| 1256 | } | 1259 | } |
| 1257 | | 1260 | |
| 1258 | } | 1261 | } |
| ... | @@ -1263,7 +1266,8 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope * | ... | @@ -1263,7 +1266,8 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope * |
| 1263 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) { | 1266 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 1264 | assert(node->type == NodeTypeReturnExpr); | 1267 | assert(node->type == NodeTypeReturnExpr); |
| 1265 | | 1268 | |
| 1266 | if (!exec_fn_entry(irb->exec)) { | 1269 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| | 1270 | if (!fn_entry) { |
| 1267 | add_node_error(irb->codegen, node, buf_sprintf("return expression outside function definition")); | 1271 | add_node_error(irb->codegen, node, buf_sprintf("return expression outside function definition")); |
| 1268 | return irb->codegen->invalid_instruction; | 1272 | return irb->codegen->invalid_instruction; |
| 1269 | } | 1273 | } |
| ... | @@ -1279,6 +1283,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -1279,6 +1283,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) |
| 1279 | return_value = ir_build_const_void(irb, scope, node); | 1283 | return_value = ir_build_const_void(irb, scope, node); |
| 1280 | } | 1284 | } |
| 1281 | | 1285 | |
| | 1286 | Scope *outer_scope = fn_entry->child_scope; |
| | 1287 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); |
| 1282 | return ir_build_return(irb, scope, node, return_value); | 1288 | return ir_build_return(irb, scope, node, return_value); |
| 1283 | } | 1289 | } |
| 1284 | case ReturnKindError: | 1290 | case ReturnKindError: |
| ... | @@ -1385,7 +1391,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -1385,7 +1391,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 1385 | if (!return_value) | 1391 | if (!return_value) |
| 1386 | return_value = ir_build_const_void(irb, child_scope, block_node); | 1392 | return_value = ir_build_const_void(irb, child_scope, block_node); |
| 1387 | | 1393 | |
| 1388 | ir_gen_defers_for_block(irb, parent_scope, child_scope, outer_block_scope, false, false); | 1394 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false, false); |
| 1389 | | 1395 | |
| 1390 | return return_value; | 1396 | return return_value; |
| 1391 | } | 1397 | } |
| ... | @@ -1433,9 +1439,9 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node | ... | @@ -1433,9 +1439,9 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node |
| 1433 | IrBasicBlock *post_val1_block = irb->current_basic_block; | 1439 | IrBasicBlock *post_val1_block = irb->current_basic_block; |
| 1434 | | 1440 | |
| 1435 | // block for when val1 == false | 1441 | // block for when val1 == false |
| 1436 | IrBasicBlock *false_block = ir_build_basic_block(irb, "BoolOrFalse"); | 1442 | IrBasicBlock *false_block = ir_build_basic_block(irb, scope, "BoolOrFalse"); |
| 1437 | // block for when val1 == true (don't even evaluate the second part) | 1443 | // block for when val1 == true (don't even evaluate the second part) |
| 1438 | IrBasicBlock *true_block = ir_build_basic_block(irb, "BoolOrTrue"); | 1444 | IrBasicBlock *true_block = ir_build_basic_block(irb, scope, "BoolOrTrue"); |
| 1439 | | 1445 | |
| 1440 | ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline); | 1446 | ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline); |
| 1441 | | 1447 | |
| ... | @@ -1470,9 +1476,9 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -1470,9 +1476,9 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod |
| 1470 | IrBasicBlock *post_val1_block = irb->current_basic_block; | 1476 | IrBasicBlock *post_val1_block = irb->current_basic_block; |
| 1471 | | 1477 | |
| 1472 | // block for when val1 == true | 1478 | // block for when val1 == true |
| 1473 | IrBasicBlock *true_block = ir_build_basic_block(irb, "BoolAndTrue"); | 1479 | IrBasicBlock *true_block = ir_build_basic_block(irb, scope, "BoolAndTrue"); |
| 1474 | // block for when val1 == false (don't even evaluate the second part) | 1480 | // block for when val1 == false (don't even evaluate the second part) |
| 1475 | IrBasicBlock *false_block = ir_build_basic_block(irb, "BoolAndFalse"); | 1481 | IrBasicBlock *false_block = ir_build_basic_block(irb, scope, "BoolAndFalse"); |
| 1476 | | 1482 | |
| 1477 | ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline); | 1483 | ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline); |
| 1478 | | 1484 | |
| ... | @@ -1935,9 +1941,9 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -1935,9 +1941,9 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode |
| 1935 | AstNode *then_node = node->data.if_bool_expr.then_block; | 1941 | AstNode *then_node = node->data.if_bool_expr.then_block; |
| 1936 | AstNode *else_node = node->data.if_bool_expr.else_node; | 1942 | AstNode *else_node = node->data.if_bool_expr.else_node; |
| 1937 | | 1943 | |
| 1938 | IrBasicBlock *then_block = ir_build_basic_block(irb, "Then"); | 1944 | IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "Then"); |
| 1939 | IrBasicBlock *else_block = ir_build_basic_block(irb, "Else"); | 1945 | IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "Else"); |
| 1940 | IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf"); | 1946 | IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "EndIf"); |
| 1941 | | 1947 | |
| 1942 | bool is_inline = ir_should_inline(irb) || node->data.if_bool_expr.is_inline; | 1948 | bool is_inline = ir_should_inline(irb) || node->data.if_bool_expr.is_inline; |
| 1943 | ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_inline); | 1949 | ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_inline); |
| ... | @@ -2124,11 +2130,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -2124,11 +2130,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 2124 | | 2130 | |
| 2125 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; | 2131 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; |
| 2126 | | 2132 | |
| 2127 | IrBasicBlock *cond_block = ir_build_basic_block(irb, "WhileCond"); | 2133 | IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond"); |
| 2128 | IrBasicBlock *body_block = ir_build_basic_block(irb, "WhileBody"); | 2134 | IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody"); |
| 2129 | IrBasicBlock *continue_block = continue_expr_node ? | 2135 | IrBasicBlock *continue_block = continue_expr_node ? |
| 2130 | ir_build_basic_block(irb, "WhileContinue") : cond_block; | 2136 | ir_build_basic_block(irb, scope, "WhileContinue") : cond_block; |
| 2131 | IrBasicBlock *end_block = ir_build_basic_block(irb, "WhileEnd"); | 2137 | IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd"); |
| 2132 | | 2138 | |
| 2133 | bool is_inline = ir_should_inline(irb) || node->data.while_expr.is_inline; | 2139 | bool is_inline = ir_should_inline(irb) || node->data.while_expr.is_inline; |
| 2134 | ir_build_br(irb, scope, node, cond_block, is_inline); | 2140 | ir_build_br(irb, scope, node, cond_block, is_inline); |
| ... | @@ -2219,10 +2225,10 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -2219,10 +2225,10 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 2219 | IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); | 2225 | IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); |
| 2220 | | 2226 | |
| 2221 | | 2227 | |
| 2222 | IrBasicBlock *cond_block = ir_build_basic_block(irb, "ForCond"); | 2228 | IrBasicBlock *cond_block = ir_build_basic_block(irb, child_scope, "ForCond"); |
| 2223 | IrBasicBlock *body_block = ir_build_basic_block(irb, "ForBody"); | 2229 | IrBasicBlock *body_block = ir_build_basic_block(irb, child_scope, "ForBody"); |
| 2224 | IrBasicBlock *end_block = ir_build_basic_block(irb, "ForEnd"); | 2230 | IrBasicBlock *end_block = ir_build_basic_block(irb, child_scope, "ForEnd"); |
| 2225 | IrBasicBlock *continue_block = ir_build_basic_block(irb, "ForContinue"); | 2231 | IrBasicBlock *continue_block = ir_build_basic_block(irb, child_scope, "ForContinue"); |
| 2226 | | 2232 | |
| 2227 | IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val); | 2233 | IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val); |
| 2228 | ir_build_br(irb, child_scope, node, cond_block, is_inline); | 2234 | ir_build_br(irb, child_scope, node, cond_block, is_inline); |
| ... | @@ -2404,9 +2410,9 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -2404,9 +2410,9 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 2404 | | 2410 | |
| 2405 | IrInstruction *is_nonnull_value = ir_build_test_null(irb, scope, node, expr_value); | 2411 | IrInstruction *is_nonnull_value = ir_build_test_null(irb, scope, node, expr_value); |
| 2406 | | 2412 | |
| 2407 | IrBasicBlock *then_block = ir_build_basic_block(irb, "MaybeThen"); | 2413 | IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen"); |
| 2408 | IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse"); | 2414 | IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse"); |
| 2409 | IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf"); | 2415 | IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "MaybeEndIf"); |
| 2410 | | 2416 | |
| 2411 | bool is_inline = ir_should_inline(irb) || node->data.if_var_expr.is_inline; | 2417 | bool is_inline = ir_should_inline(irb) || node->data.if_var_expr.is_inline; |
| 2412 | ir_build_cond_br(irb, scope, node, is_nonnull_value, then_block, else_block, is_inline); | 2418 | ir_build_cond_br(irb, scope, node, is_nonnull_value, then_block, else_block, is_inline); |
| ... | @@ -2506,8 +2512,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -2506,8 +2512,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 2506 | return target_value_ptr; | 2512 | return target_value_ptr; |
| 2507 | IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); | 2513 | IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); |
| 2508 | | 2514 | |
| 2509 | IrBasicBlock *else_block = ir_build_basic_block(irb, "SwitchElse"); | 2515 | IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "SwitchElse"); |
| 2510 | IrBasicBlock *end_block = ir_build_basic_block(irb, "SwitchEnd"); | 2516 | IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "SwitchEnd"); |
| 2511 | | 2517 | |
| 2512 | size_t prong_count = node->data.switch_expr.prongs.length; | 2518 | size_t prong_count = node->data.switch_expr.prongs.length; |
| 2513 | ZigList<IrInstructionSwitchBrCase> cases = {0}; | 2519 | ZigList<IrInstructionSwitchBrCase> cases = {0}; |
| ... | @@ -2586,8 +2592,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -2586,8 +2592,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 2586 | } | 2592 | } |
| 2587 | } | 2593 | } |
| 2588 | | 2594 | |
| 2589 | IrBasicBlock *range_block_yes = ir_build_basic_block(irb, "SwitchRangeYes"); | 2595 | IrBasicBlock *range_block_yes = ir_build_basic_block(irb, scope, "SwitchRangeYes"); |
| 2590 | IrBasicBlock *range_block_no = ir_build_basic_block(irb, "SwitchRangeNo"); | 2596 | IrBasicBlock *range_block_no = ir_build_basic_block(irb, scope, "SwitchRangeNo"); |
| 2591 | | 2597 | |
| 2592 | assert(ok_bit); | 2598 | assert(ok_bit); |
| 2593 | assert(last_item_node); | 2599 | assert(last_item_node); |
| ... | @@ -2602,7 +2608,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -2602,7 +2608,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 2602 | | 2608 | |
| 2603 | ir_set_cursor_at_end(irb, range_block_no); | 2609 | ir_set_cursor_at_end(irb, range_block_no); |
| 2604 | } else { | 2610 | } else { |
| 2605 | IrBasicBlock *prong_block = ir_build_basic_block(irb, "SwitchProng"); | 2611 | IrBasicBlock *prong_block = ir_build_basic_block(irb, scope, "SwitchProng"); |
| 2606 | IrInstruction *last_item_value = nullptr; | 2612 | IrInstruction *last_item_value = nullptr; |
| 2607 | | 2613 | |
| 2608 | for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { | 2614 | for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { |
| ... | @@ -2678,7 +2684,7 @@ static IrInstruction *ir_gen_label(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -2678,7 +2684,7 @@ static IrInstruction *ir_gen_label(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2678 | assert(node->type == NodeTypeLabel); | 2684 | assert(node->type == NodeTypeLabel); |
| 2679 | | 2685 | |
| 2680 | Buf *label_name = node->data.label.name; | 2686 | Buf *label_name = node->data.label.name; |
| 2681 | IrBasicBlock *label_block = ir_build_basic_block(irb, buf_ptr(label_name)); | 2687 | IrBasicBlock *label_block = ir_build_basic_block(irb, scope, buf_ptr(label_name)); |
| 2682 | LabelTableEntry *label = allocate<LabelTableEntry>(1); | 2688 | LabelTableEntry *label = allocate<LabelTableEntry>(1); |
| 2683 | label->decl_node = node; | 2689 | label->decl_node = node; |
| 2684 | label->bb = label_block; | 2690 | label->bb = label_block; |
| ... | @@ -2712,6 +2718,8 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { | ... | @@ -2712,6 +2718,8 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 2712 | goto_item->source_node = node; | 2718 | goto_item->source_node = node; |
| 2713 | goto_item->scope = scope; | 2719 | goto_item->scope = scope; |
| 2714 | | 2720 | |
| | 2721 | // we don't know if we need to generate defer expressions yet |
| | 2722 | // we do that later when we find out which label we're jumping to. |
| 2715 | return ir_build_unreachable(irb, scope, node); | 2723 | return ir_build_unreachable(irb, scope, node); |
| 2716 | } | 2724 | } |
| 2717 | | 2725 | |
| ... | @@ -2727,6 +2735,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -2727,6 +2735,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2727 | bool is_inline = ir_should_inline(irb) || node->data.break_expr.is_inline; | 2735 | bool is_inline = ir_should_inline(irb) || node->data.break_expr.is_inline; |
| 2728 | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); | 2736 | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); |
| 2729 | IrBasicBlock *dest_block = loop_stack_item->break_block; | 2737 | IrBasicBlock *dest_block = loop_stack_item->break_block; |
| | 2738 | ir_gen_defers_for_block(irb, scope, dest_block->scope, false, false); |
| 2730 | return ir_build_br(irb, scope, node, dest_block, is_inline); | 2739 | return ir_build_br(irb, scope, node, dest_block, is_inline); |
| 2731 | } | 2740 | } |
| 2732 | | 2741 | |
| ... | @@ -2742,6 +2751,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -2742,6 +2751,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod |
| 2742 | bool is_inline = ir_should_inline(irb) || node->data.continue_expr.is_inline; | 2751 | bool is_inline = ir_should_inline(irb) || node->data.continue_expr.is_inline; |
| 2743 | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); | 2752 | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); |
| 2744 | IrBasicBlock *dest_block = loop_stack_item->continue_block; | 2753 | IrBasicBlock *dest_block = loop_stack_item->continue_block; |
| | 2754 | ir_gen_defers_for_block(irb, scope, dest_block->scope, false, false); |
| 2745 | return ir_build_br(irb, scope, node, dest_block, is_inline); | 2755 | return ir_build_br(irb, scope, node, dest_block, is_inline); |
| 2746 | } | 2756 | } |
| 2747 | | 2757 | |
| ... | @@ -2761,6 +2771,16 @@ static IrInstruction *ir_gen_type_literal(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2761,6 +2771,16 @@ static IrInstruction *ir_gen_type_literal(IrBuilder *irb, Scope *scope, AstNode |
| 2761 | return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_type); | 2771 | return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_type); |
| 2762 | } | 2772 | } |
| 2763 | | 2773 | |
| | 2774 | static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| | 2775 | assert(node->type == NodeTypeDefer); |
| | 2776 | |
| | 2777 | ScopeDefer *defer_scope = create_defer_scope(node, parent_scope); |
| | 2778 | node->data.defer.child_scope = &defer_scope->base; |
| | 2779 | node->data.defer.parent_scope = parent_scope; |
| | 2780 | |
| | 2781 | return ir_build_const_void(irb, parent_scope, node); |
| | 2782 | } |
| | 2783 | |
| 2764 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, | 2784 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, |
| 2765 | LValPurpose lval) | 2785 | LValPurpose lval) |
| 2766 | { | 2786 | { |
| ... | @@ -2824,8 +2844,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -2824,8 +2844,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 2824 | return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval); | 2844 | return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval); |
| 2825 | case NodeTypeContinue: | 2845 | case NodeTypeContinue: |
| 2826 | return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); | 2846 | return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); |
| 2827 | case NodeTypeUnwrapErrorExpr: | | |
| 2828 | case NodeTypeDefer: | 2847 | case NodeTypeDefer: |
| | 2848 | return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval); |
| | 2849 | case NodeTypeUnwrapErrorExpr: |
| 2829 | case NodeTypeSliceExpr: | 2850 | case NodeTypeSliceExpr: |
| 2830 | case NodeTypeCharLiteral: | 2851 | case NodeTypeCharLiteral: |
| 2831 | case NodeTypeZeroesLiteral: | 2852 | case NodeTypeZeroesLiteral: |
| ... | @@ -2864,9 +2885,11 @@ static bool ir_goto_pass2(IrBuilder *irb) { | ... | @@ -2864,9 +2885,11 @@ static bool ir_goto_pass2(IrBuilder *irb) { |
| 2864 | for (size_t i = 0; i < irb->exec->goto_list.length; i += 1) { | 2885 | for (size_t i = 0; i < irb->exec->goto_list.length; i += 1) { |
| 2865 | IrGotoItem *goto_item = &irb->exec->goto_list.at(i); | 2886 | IrGotoItem *goto_item = &irb->exec->goto_list.at(i); |
| 2866 | AstNode *source_node = goto_item->source_node; | 2887 | AstNode *source_node = goto_item->source_node; |
| 2867 | size_t instruction_index = goto_item->instruction_index; | 2888 | |
| 2868 | IrInstruction **slot = &goto_item->bb->instruction_list.at(instruction_index); | 2889 | // Since a goto will always end a basic block, we move the "current instruction" |
| 2869 | IrInstruction *old_instruction = *slot; | 2890 | // index back to over the placeholder unreachable instruction and begin overwriting |
| | 2891 | irb->current_basic_block = goto_item->bb; |
| | 2892 | irb->current_basic_block->instruction_list.resize(goto_item->instruction_index); |
| 2870 | | 2893 | |
| 2871 | Buf *label_name = source_node->data.goto_expr.name; | 2894 | Buf *label_name = source_node->data.goto_expr.name; |
| 2872 | LabelTableEntry *label = find_label(irb->exec, goto_item->scope, label_name); | 2895 | LabelTableEntry *label = find_label(irb->exec, goto_item->scope, label_name); |
| ... | @@ -2878,9 +2901,8 @@ static bool ir_goto_pass2(IrBuilder *irb) { | ... | @@ -2878,9 +2901,8 @@ static bool ir_goto_pass2(IrBuilder *irb) { |
| 2878 | label->used = true; | 2901 | label->used = true; |
| 2879 | | 2902 | |
| 2880 | bool is_inline = ir_should_inline(irb) || source_node->data.goto_expr.is_inline; | 2903 | bool is_inline = ir_should_inline(irb) || source_node->data.goto_expr.is_inline; |
| 2881 | IrInstruction *new_instruction = ir_create_br(irb, goto_item->scope, source_node, label->bb, is_inline); | 2904 | ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false, false); |
| 2882 | new_instruction->ref_count = old_instruction->ref_count; | 2905 | ir_build_br(irb, goto_item->scope, source_node, label->bb, is_inline); |
| 2883 | *slot = new_instruction; | | |
| 2884 | } | 2906 | } |
| 2885 | | 2907 | |
| 2886 | for (size_t i = 0; i < irb->exec->all_labels.length; i += 1) { | 2908 | for (size_t i = 0; i < irb->exec->all_labels.length; i += 1) { |
| ... | @@ -2905,7 +2927,7 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutabl | ... | @@ -2905,7 +2927,7 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutabl |
| 2905 | irb->codegen = codegen; | 2927 | irb->codegen = codegen; |
| 2906 | irb->exec = ir_executable; | 2928 | irb->exec = ir_executable; |
| 2907 | | 2929 | |
| 2908 | irb->current_basic_block = ir_build_basic_block(irb, "Entry"); | 2930 | irb->current_basic_block = ir_build_basic_block(irb, scope, "Entry"); |
| 2909 | // Entry block gets a reference because we enter it to begin. | 2931 | // Entry block gets a reference because we enter it to begin. |
| 2910 | ir_ref_bb(irb->current_basic_block); | 2932 | ir_ref_bb(irb->current_basic_block); |
| 2911 | | 2933 | |
| ... | @@ -7803,29 +7825,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -7803,29 +7825,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7803 | // } | 7825 | // } |
| 7804 | //} | 7826 | //} |
| 7805 | // | 7827 | // |
| 7806 | //static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, | | |
| 7807 | // TypeTableEntry *expected_type, AstNode *node) | | |
| 7808 | //{ | | |
| 7809 | // if (!parent_context->fn_entry) { | | |
| 7810 | // add_node_error(g, node, buf_sprintf("defer expression outside function definition")); | | |
| 7811 | // return g->builtin_types.entry_invalid; | | |
| 7812 | // } | | |
| 7813 | // | | |
| 7814 | // if (!node->data.defer.expr) { | | |
| 7815 | // add_node_error(g, node, buf_sprintf("defer expects an expression")); | | |
| 7816 | // return g->builtin_types.entry_void; | | |
| 7817 | // } | | |
| 7818 | // | | |
| 7819 | // node->data.defer.child_block = new_block_context(node, parent_context); | | |
| 7820 | // | | |
| 7821 | // TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr, | | |
| 7822 | // node->data.defer.expr); | | |
| 7823 | // validate_voided_expr(g, node->data.defer.expr, resolved_type); | | |
| 7824 | // | | |
| 7825 | // return g->builtin_types.entry_void; | | |
| 7826 | //} | | |
| 7827 | // | | |
| 7828 | // | | |
| 7829 | //static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, | 7828 | //static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, |
| 7830 | // BlockContext *context, AstNode *node, Buf *err_name) | 7829 | // BlockContext *context, AstNode *node, Buf *err_name) |
| 7831 | //{ | 7830 | //{ |
| ... | @@ -7849,38 +7848,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -7849,38 +7848,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7849 | // } | 7848 | // } |
| 7850 | //} | 7849 | //} |
| 7851 | // | 7850 | // |
| 7852 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { | | |
| 7853 | // size_t result = 0; | | |
| 7854 | // while (inner_block != outer_block) { | | |
| 7855 | // if (inner_block->node->type == NodeTypeDefer && | | |
| 7856 | // (inner_block->node->data.defer.kind == ReturnKindError || | | |
| 7857 | // inner_block->node->data.defer.kind == ReturnKindMaybe)) | | |
| 7858 | // { | | |
| 7859 | // result += 1; | | |
| 7860 | // } | | |
| 7861 | // inner_block = inner_block->parent; | | |
| 7862 | // } | | |
| 7863 | // return result; | | |
| 7864 | //} | | |
| 7865 | | 7851 | |
| 7866 | | 7852 | |
| 7867 | //static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) { | | |
| 7868 | // BlockContext *defer_inner_block = source_node->block_context; | | |
| 7869 | // BlockContext *defer_outer_block = irb->node->block_context; | | |
| 7870 | // if (rk == ReturnKnowledgeUnknown) { | | |
| 7871 | // if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { | | |
| 7872 | // // generate branching code that checks the return value and generates defers | | |
| 7873 | // // if the return value is error | | |
| 7874 | // zig_panic("TODO"); | | |
| 7875 | // } | | |
| 7876 | // } else if (rk != ReturnKnowledgeSkipDefers) { | | |
| 7877 | // ir_gen_defers_for_block(irb, defer_inner_block, defer_outer_block, | | |
| 7878 | // rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); | | |
| 7879 | // } | | |
| 7880 | // | | |
| 7881 | // return ir_build_return(irb, source_node, value); | | |
| 7882 | //} | | |
| 7883 | // | | |
| 7884 | //static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) { | 7853 | //static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) { |
| 7885 | // assert(node->type == NodeTypeFnCallExpr); | 7854 | // assert(node->type == NodeTypeFnCallExpr); |
| 7886 | // assert(g->generate_error_name_table); | 7855 | // assert(g->generate_error_name_table); |
| ... | @@ -8400,21 +8369,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -8400,21 +8369,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8400 | // return phi; | 8369 | // return phi; |
| 8401 | //} | 8370 | //} |
| 8402 | // | 8371 | // |
| 8403 | //static void gen_defers_for_block(CodeGen *g, BlockContext *inner_block, BlockContext *outer_block, | | |
| 8404 | // bool gen_error_defers, bool gen_maybe_defers) | | |
| 8405 | //{ | | |
| 8406 | // while (inner_block != outer_block) { | | |
| 8407 | // if (inner_block->node->type == NodeTypeDefer && | | |
| 8408 | // ((inner_block->node->data.defer.kind == ReturnKindUnconditional) || | | |
| 8409 | // (gen_error_defers && inner_block->node->data.defer.kind == ReturnKindError) || | | |
| 8410 | // (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) | | |
| 8411 | // { | | |
| 8412 | // gen_expr(g, inner_block->node->data.defer.expr); | | |
| 8413 | // } | | |
| 8414 | // inner_block = inner_block->parent; | | |
| 8415 | // } | | |
| 8416 | //} | | |
| 8417 | // | | |
| 8418 | //static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { | 8372 | //static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { |
| 8419 | // assert(node->type == NodeTypeReturnExpr); | 8373 | // assert(node->type == NodeTypeReturnExpr); |
| 8420 | // AstNode *param_node = node->data.return_expr.expr; | 8374 | // AstNode *param_node = node->data.return_expr.expr; |
| ... | @@ -8529,30 +8483,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -8529,30 +8483,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8529 | // zig_unreachable(); | 8483 | // zig_unreachable(); |
| 8530 | //} | 8484 | //} |
| 8531 | // | 8485 | // |
| 8532 | //static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { | | |
| 8533 | // assert(block_node->type == NodeTypeBlock); | | |
| 8534 | // | | |
| 8535 | // LLVMValueRef return_value = nullptr; | | |
| 8536 | // for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { | | |
| 8537 | // AstNode *statement_node = block_node->data.block.statements.at(i); | | |
| 8538 | // return_value = gen_expr(g, statement_node); | | |
| 8539 | // } | | |
| 8540 | // | | |
| 8541 | // bool end_unreachable = implicit_return_type && implicit_return_type->id == TypeTableEntryIdUnreachable; | | |
| 8542 | // if (end_unreachable) { | | |
| 8543 | // return nullptr; | | |
| 8544 | // } | | |
| 8545 | // | | |
| 8546 | // gen_defers_for_block(g, block_node->data.block.nested_block, block_node->data.block.child_block, | | |
| 8547 | // false, false); | | |
| 8548 | // | | |
| 8549 | // if (implicit_return_type) { | | |
| 8550 | // return gen_return(g, block_node, return_value, ReturnKnowledgeSkipDefers); | | |
| 8551 | // } else { | | |
| 8552 | // return return_value; | | |
| 8553 | // } | | |
| 8554 | //} | | |
| 8555 | // | | |
| 8556 | //static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, | 8486 | //static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, |
| 8557 | // bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr) | 8487 | // bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr) |
| 8558 | //{ | 8488 | //{ |
| ... | @@ -8691,37 +8621,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -8691,37 +8621,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8691 | // } | 8621 | // } |
| 8692 | //} | 8622 | //} |
| 8693 | // | 8623 | // |
| 8694 | //static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value, ReturnKnowledge rk) { | | |
| 8695 | // BlockContext *defer_inner_block = source_node->block_context; | | |
| 8696 | // BlockContext *defer_outer_block = source_node->block_context->fn_entry->fn_def_node->block_context; | | |
| 8697 | // if (rk == ReturnKnowledgeUnknown) { | | |
| 8698 | // if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { | | |
| 8699 | // // generate branching code that checks the return value and generates defers | | |
| 8700 | // // if the return value is error | | |
| 8701 | // zig_panic("TODO"); | | |
| 8702 | // } | | |
| 8703 | // } else if (rk != ReturnKnowledgeSkipDefers) { | | |
| 8704 | // gen_defers_for_block(g, defer_inner_block, defer_outer_block, | | |
| 8705 | // rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); | | |
| 8706 | // } | | |
| 8707 | // | | |
| 8708 | // TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | | |
| 8709 | // bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern; | | |
| 8710 | // if (handle_is_ptr(return_type)) { | | |
| 8711 | // if (is_extern) { | | |
| 8712 | // LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, ""); | | |
| 8713 | // LLVMBuildRet(g->builder, by_val_value); | | |
| 8714 | // } else { | | |
| 8715 | // assert(g->cur_ret_ptr); | | |
| 8716 | // gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type); | | |
| 8717 | // LLVMBuildRetVoid(g->builder); | | |
| 8718 | // } | | |
| 8719 | // } else { | | |
| 8720 | // LLVMBuildRet(g->builder, value); | | |
| 8721 | // } | | |
| 8722 | // return nullptr; | | |
| 8723 | //} | | |
| 8724 | // | | |
| 8725 | //static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { | 8624 | //static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 8726 | // AstNode *init_expr = node->data.variable_declaration.expr; | 8625 | // AstNode *init_expr = node->data.variable_declaration.expr; |
| 8727 | // if (node->data.variable_declaration.is_const && init_expr) { | 8626 | // if (node->data.variable_declaration.is_const && init_expr) { |
| ... | @@ -8763,17 +8662,3 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -8763,17 +8662,3 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8763 | // } | 8662 | // } |
| 8764 | // zig_unreachable(); | 8663 | // zig_unreachable(); |
| 8765 | //} | 8664 | //} |
| 8766 | // | | |
| 8767 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { | | |
| 8768 | // size_t result = 0; | | |
| 8769 | // while (inner_block != outer_block) { | | |
| 8770 | // if (inner_block->node->type == NodeTypeDefer && | | |
| 8771 | // (inner_block->node->data.defer.kind == ReturnKindError || | | |
| 8772 | // inner_block->node->data.defer.kind == ReturnKindMaybe)) | | |
| 8773 | // { | | |
| 8774 | // result += 1; | | |
| 8775 | // } | | |
| 8776 | // inner_block = inner_block->parent; | | |
| 8777 | // } | | |
| 8778 | // return result; | | |
| 8779 | //} | | |