@@ -54,6 +54,7 @@ std::vector<var_idx_t> pre_compile_expr(AnyExprV v, CodeBlob& code, TypePtr targ
5454std::vector<var_idx_t > pre_compile_symbol (SrcLocation loc, const Symbol* sym, CodeBlob& code, LValContext* lval_ctx);
5555void process_any_statement (AnyV v, CodeBlob& code);
5656
57+ static AnyV stmt_before_immediate_return = nullptr ;
5758
5859// The goal of VarsModificationWatcher is to detect such cases: `return (x, x += y, x)`.
5960// Without any changes, ops will be { _Call $2 = +($0_x, $1_y); _Return $0_x, $2, $0_x } - incorrect
@@ -1236,6 +1237,9 @@ static std::vector<var_idx_t> process_match_expression(V<ast_match_expression> v
12361237 code.push_set_cur (if_op.block0 );
12371238 if (v->is_statement ()) {
12381239 pre_compile_expr (v_ith_arm->get_body (), code);
1240+ if (v == stmt_before_immediate_return) {
1241+ code.emplace_back (v_ith_arm->loc , Op::_Return);
1242+ }
12391243 } else {
12401244 std::vector<var_idx_t > arm_ir_idx = pre_compile_expr (v_ith_arm->get_body (), code, v->inferred_type );
12411245 code.emplace_back (v->loc , Op::_Let, result_ir_idx, std::move (arm_ir_idx));
@@ -1249,6 +1253,9 @@ static std::vector<var_idx_t> process_match_expression(V<ast_match_expression> v
12491253 auto v_last_arm = v->get_arm (n_arms - 1 );
12501254 if (v->is_statement ()) {
12511255 pre_compile_expr (v_last_arm->get_body (), code);
1256+ if (v == stmt_before_immediate_return) {
1257+ code.emplace_back (v_last_arm->loc , Op::_Return);
1258+ }
12521259 } else {
12531260 std::vector<var_idx_t > arm_ir_idx = pre_compile_expr (v_last_arm->get_body (), code, v->inferred_type );
12541261 code.emplace_back (v->loc , Op::_Let, result_ir_idx, std::move (arm_ir_idx));
@@ -1743,9 +1750,30 @@ std::vector<var_idx_t> pre_compile_expr(AnyExprV v, CodeBlob& code, TypePtr targ
17431750
17441751
17451752static void process_block_statement (V<ast_block_statement> v, CodeBlob& code) {
1746- for (AnyV item : v->get_items ()) {
1747- process_any_statement (item, code) ;
1753+ if ( v->empty ()) {
1754+ return ;
17481755 }
1756+
1757+ FunctionPtr cur_f = code.fun_ref ;
1758+ bool does_f_return_nothing = cur_f->inferred_return_type == TypeDataVoid::create () && !cur_f->does_return_self () && !cur_f->has_mutate_params ();
1759+ bool is_toplevel_block = v == cur_f->ast_root ->as <ast_function_declaration>()->get_body ();
1760+
1761+ // we want to optimize `match` and `if/else`: if it's the last statement, implicitly add "return" to every branch
1762+ // (to generate IFJMP instead of nested IF ELSE);
1763+ // a competent way is to do it at the IR level (building CST, etc.), it's impossible to tweak Ops for now;
1764+ // so, for every `f() { here }` of `... here; return;`, save it into a global, and handle within match/if
1765+ AnyV backup = stmt_before_immediate_return;
1766+ for (int i = 0 ; i < v->size () - 1 ; ++i) {
1767+ AnyV stmt = v->get_item (i);
1768+ AnyV next_stmt = v->get_item (i + 1 );
1769+ bool next_is_empty_return = next_stmt->kind == ast_return_statement && !next_stmt->as <ast_return_statement>()->has_return_value ();
1770+ stmt_before_immediate_return = next_is_empty_return && does_f_return_nothing ? stmt : nullptr ;
1771+ process_any_statement (stmt, code);
1772+ }
1773+ AnyV last_stmt = v->get_item (v->size () - 1 );
1774+ stmt_before_immediate_return = is_toplevel_block && does_f_return_nothing ? last_stmt : nullptr ;
1775+ process_any_statement (last_stmt, code);
1776+ stmt_before_immediate_return = backup;
17491777}
17501778
17511779static void process_assert_statement (V<ast_assert_statement> v, CodeBlob& code) {
@@ -1817,9 +1845,15 @@ static void process_if_statement(V<ast_if_statement> v, CodeBlob& code) {
18171845 Op& if_op = code.emplace_back (v->loc , Op::_If, std::move (cond));
18181846 code.push_set_cur (if_op.block0 );
18191847 process_any_statement (v->get_if_body (), code);
1848+ if (v == stmt_before_immediate_return) {
1849+ code.emplace_back (v->get_if_body ()->loc_end , Op::_Return);
1850+ }
18201851 code.close_pop_cur (v->get_if_body ()->loc_end );
18211852 code.push_set_cur (if_op.block1 );
18221853 process_any_statement (v->get_else_body (), code);
1854+ if (v == stmt_before_immediate_return) {
1855+ code.emplace_back (v->get_else_body ()->loc_end , Op::_Return);
1856+ }
18231857 code.close_pop_cur (v->get_else_body ()->loc_end );
18241858 if (v->is_ifnot ) {
18251859 std::swap (if_op.block0 , if_op.block1 );
@@ -1978,9 +2012,7 @@ static void convert_function_body_to_CodeBlob(FunctionPtr fun_ref, FunctionBodyC
19782012 blob->in_var_cnt = blob->var_cnt ;
19792013 tolk_assert (blob->var_cnt == total_arg_width);
19802014
1981- for (AnyV item : v_body->get_items ()) {
1982- process_any_statement (item, *blob);
1983- }
2015+ process_block_statement (v_body, *blob);
19842016 append_implicit_return_statement (v_body->loc_end , *blob);
19852017
19862018 blob->close_blk (v_body->loc_end );
0 commit comments