authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-06 21:26:17-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-06 21:26:17-05:00
log6ed202ab16f42d73975e8a4508698857300c1b6f
tree35f75bca95b34a98f45f601568421c2ec763b83a
parent0c531d447df88ed6c46e759fbfc9d253d2650c22

IR: implement defer


8 files changed, 95 insertions(+), 189 deletions(-)

doc/langref.md+1-1
...@@ -87,7 +87,7 @@ BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression...@@ -87,7 +87,7 @@ BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression
8787
88ReturnExpression = option("%" | "?") "return" option(Expression)88ReturnExpression = option("%" | "?") "return" option(Expression)
8989
90Defer = option("%" | "?") "defer" option(Expression)90Defer = option("%" | "?") "defer" Expression
9191
92IfExpression = IfVarExpression | IfBoolExpression92IfExpression = IfVarExpression | IfBoolExpression
9393
src/all_types.hpp+2-1
...@@ -308,8 +308,8 @@ struct AstNodeDefer {...@@ -308,8 +308,8 @@ struct AstNodeDefer {
308 AstNode *expr;308 AstNode *expr;
309309
310 // temporary data used in IR generation310 // temporary data used in IR generation
311 // TODO populate during gen_defer
312 Scope *child_scope;311 Scope *child_scope;
312 Scope *parent_scope;
313};313};
314314
315struct AstNodeVariableDeclaration {315struct AstNodeVariableDeclaration {
...@@ -1333,6 +1333,7 @@ enum AtomicOrder {...@@ -1333,6 +1333,7 @@ enum AtomicOrder {
1333struct IrBasicBlock {1333struct IrBasicBlock {
1334 ZigList<IrInstruction *> instruction_list;1334 ZigList<IrInstruction *> instruction_list;
1335 IrBasicBlock *other;1335 IrBasicBlock *other;
1336 Scope *scope;
1336 const char *name_hint;1337 const char *name_hint;
1337 size_t debug_id;1338 size_t debug_id;
1338 size_t ref_count;1339 size_t ref_count;
src/analyze.cpp+2-2
...@@ -154,11 +154,11 @@ Scope *create_block_scope(AstNode *node, Scope *parent) {...@@ -154,11 +154,11 @@ Scope *create_block_scope(AstNode *node, Scope *parent) {
154 return &scope->base;154 return &scope->base;
155}155}
156156
157Scope *create_defer_scope(AstNode *node, Scope *parent) {157ScopeDefer *create_defer_scope(AstNode *node, Scope *parent) {
158 assert(node->type == NodeTypeDefer);158 assert(node->type == NodeTypeDefer);
159 ScopeDefer *scope = allocate<ScopeDefer>(1);159 ScopeDefer *scope = allocate<ScopeDefer>(1);
160 init_scope(&scope->base, ScopeIdDefer, node, parent);160 init_scope(&scope->base, ScopeIdDefer, node, parent);
161 return &scope->base;161 return scope;
162}162}
163163
164Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {164Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
src/analyze.hpp+1-1
...@@ -75,7 +75,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node);...@@ -75,7 +75,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node);
75AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index);75AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index);
7676
77Scope *create_block_scope(AstNode *node, Scope *parent);77Scope *create_block_scope(AstNode *node, Scope *parent);
78Scope *create_defer_scope(AstNode *node, Scope *parent);78ScopeDefer *create_defer_scope(AstNode *node, Scope *parent);
79Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);79Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
80Scope *create_cimport_scope(AstNode *node, Scope *parent);80Scope *create_cimport_scope(AstNode *node, Scope *parent);
81Scope *create_loop_scope(AstNode *node, Scope *parent);81Scope *create_loop_scope(AstNode *node, Scope *parent);
src/ast_render.cpp+5-2
...@@ -455,8 +455,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -455,8 +455,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
455 case NodeTypeReturnExpr:455 case NodeTypeReturnExpr:
456 {456 {
457 const char *return_str = return_string(node->data.return_expr.kind);457 const char *return_str = return_string(node->data.return_expr.kind);
458 fprintf(ar->f, "%s ", return_str);458 fprintf(ar->f, "%s", return_str);
459 render_node_grouped(ar, node->data.return_expr.expr);459 if (node->data.return_expr.expr) {
460 fprintf(ar->f, " ");
461 render_node_grouped(ar, node->data.return_expr.expr);
462 }
460 break;463 break;
461 }464 }
462 case NodeTypeDefer:465 case NodeTypeDefer:
src/ir.cpp+65-180
...@@ -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}
112112
113static IrBasicBlock *ir_build_basic_block_raw(IrBuilder *irb, const char *name_hint) {113static 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}
119120
120static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint) {121static 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}
125126
126static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {127static 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}
12421243
1243static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope *inner_scope, Scope *outer_scope,1244static 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 }
12571260
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 *
1263static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) {1266static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) {
1264 assert(node->type == NodeTypeReturnExpr);1267 assert(node->type == NodeTypeReturnExpr);
12651268
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 }
12811285
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);
13871393
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);
13891395
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;
14341440
1435 // block for when val1 == false1441 // 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");
14391445
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);
14411447
...@@ -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;
14711477
1472 // block for when val1 == true1478 // 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");
14761482
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);
14781484
...@@ -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;
19371943
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");
19411947
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
21242130
2125 AstNode *continue_expr_node = node->data.while_expr.continue_expr;2131 AstNode *continue_expr_node = node->data.while_expr.continue_expr;
21262132
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");
21322138
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);
22202226
22212227
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");
22262232
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 *
24042410
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);
24062412
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");
24102416
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);
25082514
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");
25112517
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 }
25882594
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");
25912597
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 *
26022608
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;
26072613
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);
26792685
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;
27142720
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}
27172725
...@@ -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}
27322741
...@@ -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}
27472757
...@@ -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}
27632773
2774static 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
2764static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,2784static 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);
28702893
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;
28792902
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 }
28852907
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;
29072929
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);
29112933
...@@ -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//}
78657851
78667852
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//}
src/parser.cpp+2-2
...@@ -1414,7 +1414,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {...@@ -1414,7 +1414,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
1414}1414}
14151415
1416/*1416/*
1417Defer = option("%" | "?") "defer" option(Expression)1417Defer = option("%" | "?") "defer" Expression
1418*/1418*/
1419static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {1419static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
1420 Token *token = &pc->tokens->at(*token_index);1420 Token *token = &pc->tokens->at(*token_index);
...@@ -1450,7 +1450,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {...@@ -1450,7 +1450,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
14501450
1451 AstNode *node = ast_create_node(pc, node_type, token);1451 AstNode *node = ast_create_node(pc, node_type, token);
1452 node->data.defer.kind = kind;1452 node->data.defer.kind = kind;
1453 node->data.defer.expr = ast_parse_expression(pc, token_index, false);1453 node->data.defer.expr = ast_parse_expression(pc, token_index, true);
14541454
1455 return node;1455 return node;
1456}1456}
test/self_hosted2.zig+17
...@@ -179,6 +179,22 @@ fn shortCircuit() {...@@ -179,6 +179,22 @@ fn shortCircuit() {
179 assert(hit_4);179 assert(hit_4);
180}180}
181181
182fn testGotoLeaveDeferScope(b: bool) {
183 var it_worked = false;
184
185 goto entry;
186exit:
187 if (it_worked) {
188 return;
189 }
190 @unreachable();
191entry:
192 defer it_worked = true;
193 if (it_worked) @unreachable();
194 if (b) goto exit;
195}
196
197
182198
183fn assert(ok: bool) {199fn assert(ok: bool) {
184 if (!ok)200 if (!ok)
...@@ -201,6 +217,7 @@ fn runAllTests() {...@@ -201,6 +217,7 @@ fn runAllTests() {
201 testFnWithInlineArgs();217 testFnWithInlineArgs();
202 testContinueInForLoop();218 testContinueInForLoop();
203 shortCircuit();219 shortCircuit();
220 testGotoLeaveDeferScope(true);
204}221}
205222
206export nakedcc fn _start() -> unreachable {223export nakedcc fn _start() -> unreachable {