Skip to content

Commit 1bffc82

Browse files
authored
feat(compiler)!: Early return (#1464)
1 parent bd5403f commit 1bffc82

36 files changed

+619
-30
lines changed

compiler/src/codegen/compcore.re

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2815,6 +2815,14 @@ let do_backpatches = (wasm_mod, env, backpatches) => {
28152815
);
28162816
};
28172817

2818+
let current_function = ref(None);
2819+
let get_current_function = () => {
2820+
switch (current_function^) {
2821+
| Some(func) => func
2822+
| None => failwith("No current function set")
2823+
};
2824+
};
2825+
let set_current_function = func => current_function := Some(func);
28182826
let loop_stack = ref([]: list((string, string)));
28192827

28202828
let rec compile_store = (wasm_mod, env, binds) => {
@@ -3151,6 +3159,24 @@ and compile_instr = (wasm_mod, env, instr) =>
31513159
Expression.Const.make(wasm_mod, const_void()),
31523160
);
31533161
| MError(err, args) => call_error_handler(wasm_mod, env, err, args)
3162+
| MReturn(value) =>
3163+
let current_function = get_current_function();
3164+
let value =
3165+
Option.fold(
3166+
~none=Expression.Const.make(wasm_mod, const_void()),
3167+
~some=compile_instr(wasm_mod, env),
3168+
value,
3169+
);
3170+
Expression.Return.make(
3171+
wasm_mod,
3172+
cleanup_locals(
3173+
wasm_mod,
3174+
env,
3175+
value,
3176+
current_function.args,
3177+
current_function.return_type,
3178+
),
3179+
);
31543180
| MArityOp(_) => failwith("NYI: (compile_instr): MArityOp")
31553181
| MTagOp(_) => failwith("NYI: (compile_instr): MTagOp")
31563182
};
@@ -3325,9 +3351,10 @@ let compile_function =
33253351
~preamble=?,
33263352
wasm_mod,
33273353
env,
3328-
{id, args, return_type, stack_size, body: body_instrs, func_loc},
3354+
{id, args, return_type, stack_size, body: body_instrs, func_loc} as func,
33293355
) => {
33303356
sources := [];
3357+
set_current_function(func);
33313358
let arity = List.length(args);
33323359
let func_name =
33333360
switch (name) {

compiler/src/codegen/mashtree.re

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ and instr_desc =
426426
| MFor(option(block), option(block), block)
427427
| MContinue
428428
| MBreak
429+
| MReturn(option(instr))
429430
| MSwitch(immediate, list((int32, block)), block, Types.allocation_type) /* value, branches, default, return type */
430431
| MPrim0(prim0)
431432
| MPrim1(prim1, immediate)

compiler/src/codegen/transl_anf.re

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ module RegisterAllocation = {
233233
)
234234
| MContinue => MContinue
235235
| MBreak => MBreak
236+
| MReturn(v) => MReturn(Option.map(apply_allocations(ty, allocs), v))
236237
| MSwitch(v, bs, d, ty) =>
237238
MSwitch(
238239
apply_allocation_to_imm(v),
@@ -322,6 +323,7 @@ let run_register_allocation = (instrs: list(Mashtree.instr)) => {
322323
| MPrim0(_)
323324
| MContinue
324325
| MBreak => []
326+
| MReturn(v) => Option.fold(~none=[], ~some=live_locals, v)
325327
| MSwitch(v, bs, d, ty) =>
326328
imm_live_local(v)
327329
@ List.concat(List.map(((_, b)) => block_live_locals(b), bs))
@@ -787,6 +789,7 @@ let rec compile_comp = (~id=?, env, c) => {
787789
)
788790
| CContinue => MContinue
789791
| CBreak => MBreak
792+
| CReturn(e) => MReturn(Option.map(compile_comp(env), e))
790793
| CPrim0(p0) => MPrim0(p0)
791794
| CPrim1(Box, arg)
792795
| CPrim1(BoxBind, arg) => MAllocate(MBox(compile_imm(env, arg)))

compiler/src/formatting/debug.re

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ let debug_expression = (expr: Parsetree.expression) => {
7676
print_loc("PExpFor", expr.pexp_loc)
7777
| PExpContinue => print_loc("PExpContinue", expr.pexp_loc)
7878
| PExpBreak => print_loc("PExpBreak", expr.pexp_loc)
79+
| PExpReturn(expression) => print_loc("PExpReturn", expr.pexp_loc)
7980
| PExpConstraint(expression, parsed_type) =>
8081
print_loc("PExpConstraint", expr.pexp_loc)
8182
| PExpLambda(patterns, expression) =>

compiler/src/formatting/format.re

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,23 @@ and print_expression_inner =
34733473
]);
34743474
| PExpContinue => Doc.text("continue")
34753475
| PExpBreak => Doc.text("break")
3476+
| PExpReturn(expr) =>
3477+
Doc.concat([
3478+
Doc.text("return"),
3479+
switch (expr) {
3480+
| Some(expr) =>
3481+
Doc.concat([
3482+
Doc.space,
3483+
print_expression(
3484+
~expression_parent=GenericExpression,
3485+
~original_source,
3486+
~comments,
3487+
expr,
3488+
),
3489+
])
3490+
| None => Doc.nil
3491+
},
3492+
])
34763493
| PExpConstraint(expression, parsed_type) =>
34773494
let comments_in_expression =
34783495
Comment_utils.get_comments_inside_location(

compiler/src/middle_end/analyze_free_vars.re

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ module FreeVarsArg: Anf_iterator.IterArgument = {
6060
Ident.Set.union(cond, Ident.Set.union(inc, body));
6161
| CContinue
6262
| CBreak => Ident.Set.empty
63+
| CReturn(expr) =>
64+
Option.fold(~none=Ident.Set.empty, ~some=comp_free_vars, expr)
6365
| CSwitch(arg, branches, _) =>
6466
List.fold_left(
6567
(acc, (_, b)) => Ident.Set.union(anf_free_vars(b), acc),

compiler/src/middle_end/analyze_purity.re

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ module PurityArg: Anf_iterator.IterArgument = {
122122
&& Option.fold(~none=true, ~some=anf_expression_purity_internal, inc)
123123
&& anf_expression_purity_internal(body)
124124
| CContinue
125-
| CBreak => false
125+
| CBreak
126+
| CReturn(_) => false
126127
| CSwitch(_, branches, _) =>
127128
let branches_purities =
128129
List.map(

compiler/src/middle_end/analyze_tail_calls.re

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ let rec analyze_comp_expression =
5454
push_tail_call(analyses);
5555
};
5656
false;
57+
// An explicit return is definitionally in tail position
58+
| CReturn(Some(e)) => analyze_comp_expression(true, e)
59+
| CReturn(None)
5760
| CBoxAssign(_)
5861
| CAssign(_)
5962
| CLocalAssign(_)

compiler/src/middle_end/anf_helper.re

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,14 @@ module Comp = {
168168
~env?,
169169
CBreak,
170170
);
171+
let return = (~loc=?, ~attributes=?, ~env=?, ret) =>
172+
mk(
173+
~loc?,
174+
~attributes?,
175+
~allocation_type=Unmanaged(WasmI32),
176+
~env?,
177+
CReturn(ret),
178+
);
171179
let switch_ =
172180
(
173181
~loc=?,

compiler/src/middle_end/anf_helper.rei

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ module Comp: {
263263
let break:
264264
(~loc: loc=?, ~attributes: attributes=?, ~env: env=?, unit) =>
265265
comp_expression;
266+
let return:
267+
(
268+
~loc: loc=?,
269+
~attributes: attributes=?,
270+
~env: env=?,
271+
option(comp_expression)
272+
) =>
273+
comp_expression;
266274
let switch_:
267275
(
268276
~loc: loc=?,

0 commit comments

Comments
 (0)