From d91c5c7e46c1a0d9454ff01a6fef357b966ed676 Mon Sep 17 00:00:00 2001 From: Jan Klaas Kollhof Date: Fri, 1 Oct 2021 18:43:47 +0200 Subject: [PATCH] fix: list optimizations --- src/ir/call/pipe.test.fnk | 8 +++++++ src/ir/call/pipe.test.fnk.snap | 34 ++++++++++++++++++++++++++++++ src/ir/literals/list.test.fnk | 15 ++++++++++++- src/ir/literals/list.test.fnk.snap | 7 ++++++ src/ir/module/init.fnk | 3 +-- src/js/call/call.fnk | 1 - src/js/call/pipe.test.fnk | 4 +--- src/js/call/pipe.test.fnk.snap | 28 ++++++++++++------------ src/js/func/init.fnk | 7 +++--- src/optimize/init.fnk | 6 +++--- src/optimize/init.test.fnk | 2 ++ src/optimize/init.test.fnk.snap | 29 +++++++++++++------------ src/optimize/refs.fnk | 23 +++++++------------- src/optimize/tail-calls.fnk | 2 -- 14 files changed, 111 insertions(+), 58 deletions(-) diff --git a/src/ir/call/pipe.test.fnk b/src/ir/call/pipe.test.fnk index 3dcfec0..f8c2809 100644 --- a/src/ir/call/pipe.test.fnk +++ b/src/ir/call/pipe.test.fnk @@ -35,3 +35,11 @@ describe 'pipe', fn: ' to_match_snapshot + expect + fink2lir ' + foo = bar fn: + pipe: + spam + ?.shrub 123 + ' + to_match_snapshot diff --git a/src/ir/call/pipe.test.fnk.snap b/src/ir/call/pipe.test.fnk.snap index 232bbdf..d01058c 100644 --- a/src/ir/call/pipe.test.fnk.snap +++ b/src/ir/call/pipe.test.fnk.snap @@ -113,3 +113,37 @@ rec_e fn exports_0: lst_e fn drctvs_0: mod exports_0, drctvs_0, fn mod_0:" `; + +exports[`pipe compiles with partials 2`] = ` +" +rec_e fn exports_0: + id bar, fn callee_0: + lst_e fn cargs_0: + id (fn args_0, ret_1: #fn + id spam, fn pfn_0: + lst_e fn args_1: + af pfn_0, args_1, fn ppr_0: + id (fn args_2, ret_0: #fn + lst_h args_2, fn prtl_0: + id prtl_0, fn left_0: + str 'shrub', fn key_0: + rec_g left_0, key_0, fn callee_1: + lst_e fn cargs_1: + int '123', fn arg_1: + lst_a cargs_1, arg_1, fn cargs_2: + af callee_1, cargs_2, fn pfn_2: + cc ret_0, pfn_2 + ), fn pfn_1: + lst_e fn args_3: + lst_a args_3, ppr_0, fn args_4: + af pfn_1, args_4, fn ppr_1: + id ppr_1, fn result_0: + cc ret_1, result_0 + ), fn arg_0: + lst_a cargs_0, arg_0, fn cargs_3: + af callee_0, cargs_3, fn foo_0: + str 'foo', fn key_1: + rec_s exports_0, key_1, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/literals/list.test.fnk b/src/ir/literals/list.test.fnk index fb3d644..29fca3f 100644 --- a/src/ir/literals/list.test.fnk +++ b/src/ir/literals/list.test.fnk @@ -1,4 +1,4 @@ -{fink2lir} = import '../../testing/generate.fnk' +{fink2lir, fink2js} = import '../../testing/generate.fnk' {skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' @@ -103,6 +103,19 @@ describe 'optimizations', fn: to_match_snapshot + it 'optimizes spreads', fn: + expect + fink2js ' + y = [1, 2] + [..., spam] = y + [...sp, shrub] = [1, 2, 3] + [x] = sp + [...spl] = lala + log x, y, spl, lala, sp, shrub + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + it 'ignores empty concats', fn: expect fink2lir ' diff --git a/src/ir/literals/list.test.fnk.snap b/src/ir/literals/list.test.fnk.snap index a78431b..73eaf4d 100644 --- a/src/ir/literals/list.test.fnk.snap +++ b/src/ir/literals/list.test.fnk.snap @@ -102,6 +102,13 @@ rec_e fn exports_0: mod exports_3, drctvs_0, fn mod_0:" `; +exports[`optimizations optimizes spreads 1`] = ` +"const y_0 = [1, 2]; +const item_4 = 1; +log(item_4, y_0, lala, lala, [item_4, 2], 3); +export const y = y_0;" +`; + exports[`optimizations reuses item refs 1`] = ` " rec_e fn exports_0: diff --git a/src/ir/module/init.fnk b/src/ir/module/init.fnk index d3d5057..7ea6151 100644 --- a/src/ir/module/init.fnk +++ b/src/ir/module/init.fnk @@ -55,8 +55,7 @@ transform_exprs = fn [expr=false, ...rest], exp_id, ctx, out: transform_directives = fn expr, ctx: - # TODO: directives should be handled as separate AST node - + # TODO: directives should be handled as separate AST node in larix [drctvs, dirs_id, next_ctx] = lst 'drctvs', expr, ctx {exprs: [{comments}]} = expr diff --git a/src/js/call/call.fnk b/src/js/call/call.fnk index 891f383..4bb8c10 100644 --- a/src/js/call/call.fnk +++ b/src/js/call/call.fnk @@ -86,7 +86,6 @@ transform_continue_with_cont = fn expr, ctx: false: match ret: {type: 'ReturnStatement'}: - # TODO remove if this is the last expr in a func [[ret], ctx] else: [[], ctx] diff --git a/src/js/call/pipe.test.fnk b/src/js/call/pipe.test.fnk index b877a71..848a554 100644 --- a/src/js/call/pipe.test.fnk +++ b/src/js/call/pipe.test.fnk @@ -21,9 +21,6 @@ describe 'pipe', fn: ' to_match_snapshot -# TODO: move or copy to ir/ -describe 'TODO', fn: - it 'compiles', fn: expect fink2js ' foo = bar fn: @@ -34,6 +31,7 @@ describe 'TODO', fn: to_match_snapshot + describe 'small pipe |', fn: it 'pipes', fn: expect diff --git a/src/js/call/pipe.test.fnk.snap b/src/js/call/pipe.test.fnk.snap index 5317cbf..c48ce70 100644 --- a/src/js/call/pipe.test.fnk.snap +++ b/src/js/call/pipe.test.fnk.snap @@ -1,19 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TODO compiles 1`] = ` -"const foo_0 = bar(() => { - const ppr_0 = spam(); - - const ppr_1 = (prtl_0 => { - const pfn_2 = prtl_0.shrub(123); - return pfn_2; - })(ppr_0); - - return ppr_1; -}); -export const foo = foo_0;" -`; - exports[`pipe compiles 1`] = ` "const ppr_0 = foo(); @@ -50,6 +36,20 @@ export const p1 = ppr_5, p2 = ppr_7;" `; +exports[`pipe compiles 2`] = ` +"const foo_0 = bar(() => { + const ppr_0 = spam(); + + const ppr_1 = (prtl_0 => { + const pfn_2 = prtl_0.shrub(123); + return pfn_2; + })(ppr_0); + + return ppr_1; +}); +export const foo = foo_0;" +`; + exports[`small pipe | handles precedence 1`] = ` "export const foo = (ˆpartial => matches(rx\`[a-z]\`, ˆpartial))(\`foo\`); export const bar = [ham(spam), ni(shrub)];" diff --git a/src/js/func/init.fnk b/src/js/func/init.fnk index b40e3f7..df76668 100644 --- a/src/js/func/init.fnk +++ b/src/js/func/init.fnk @@ -4,7 +4,7 @@ types = import '@babel/types' labeledStatement, doWhileStatement, booleanLiteral } = types -{map} = import '@fink/std-lib/iter.fnk' +{map, is_empty} = import '@fink/std-lib/iter.fnk' {get_refs, update_value} = import '../../ir/context.fnk' {transform_exprs} = import '../transform.fnk' @@ -15,8 +15,7 @@ types = import '@babel/types' clean_args = fn args_id, args, body, ctx: fn_args = match [args, get_refs args_id, ctx]: - # TODO use is_empty - [{length: 0}, ? > 0]: + [(is_empty ?), ? > 0]: [with_loc args_id, restElement ident args_id, ctx] else: [..., last] = args @@ -29,6 +28,8 @@ clean_args = fn args_id, args, body, ctx: [fn_args, body, ctx] + + # These are mostly ir transformations, should this be done as a prep step split_args_body = fn [expr=false, ...exprs], args_id, ctx, args=[], body=[]: match expr: diff --git a/src/optimize/init.fnk b/src/optimize/init.fnk index 8fb6cb8..5a10087 100644 --- a/src/optimize/init.fnk +++ b/src/optimize/init.fnk @@ -6,7 +6,6 @@ - maybe_opt_refs = fn ir, ctx: match ctx: {optimize.refs: true}: @@ -16,6 +15,7 @@ maybe_opt_refs = fn ir, ctx: [ir, ctx] + maybe_opt_tails = fn ir, ctx: match ctx: {optimize.tails: true}: @@ -25,6 +25,7 @@ maybe_opt_tails = fn ir, ctx: [ir, ctx] + maybe_opt_unused = fn ir, ctx: match ctx: {optimize.unused: true}: @@ -34,6 +35,7 @@ maybe_opt_unused = fn ir, ctx: [ir, ctx] + maybe_opt_names = fn ir, ctx: match ctx: {optimize.names: true}: @@ -43,8 +45,6 @@ maybe_opt_names = fn ir, ctx: - - optimize = fn exprs, options: pipe [exprs, init_ctx exprs, options]: maybe_opt_refs ...? diff --git a/src/optimize/init.test.fnk b/src/optimize/init.test.fnk index f9ab9b1..2c2337d 100644 --- a/src/optimize/init.test.fnk +++ b/src/optimize/init.test.fnk @@ -2,6 +2,7 @@ {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + describe 'optimize', fn: it 'foo', fn: expect @@ -14,6 +15,7 @@ describe 'optimize', fn: ', {optimize: {refs: true, tails: true, unused: true}} to_match_snapshot + it 'optimizes values', fn: expect fink2lir ' diff --git a/src/optimize/init.test.fnk.snap b/src/optimize/init.test.fnk.snap index caddca2..2433a57 100644 --- a/src/optimize/init.test.fnk.snap +++ b/src/optimize/init.test.fnk.snap @@ -198,18 +198,19 @@ rec_e fn exports_0: int '1', fn item_9: int '2', fn item_8: int '3', fn item_7: - lst_a sp_0_2, item_9, fn sp_0_1: - lst_a sp_0_1, item_8, fn sp_0: - lst_e fn cargs_0: - lst_a cargs_0, item_6, fn cargs_1: - lst_a cargs_1, x_0, fn cargs_2: - lst_a cargs_2, item_4, fn cargs_3: - lst_a cargs_3, y_0, fn cargs_4: - lst_a cargs_4, item_7, fn cargs_5: - lst_a cargs_5, sp_0, fn cargs_6: - lst_a cargs_6, item_9, fn cargs_7: - lst_a cargs_7, lala, fn cargs_8: - af log, cargs_8, fn mex_5: - lst_e fn drctvs_0: - mod exports_2, drctvs_0, fn mod_0:" + lst_e fn sp_0_1: + lst_a sp_0_1, item_9, fn sp_0_0: + lst_a sp_0_0, item_8, fn sp_0: + lst_e fn cargs_0: + lst_a cargs_0, item_6, fn cargs_1: + lst_a cargs_1, x_0, fn cargs_2: + lst_a cargs_2, item_4, fn cargs_3: + lst_a cargs_3, y_0, fn cargs_4: + lst_a cargs_4, item_7, fn cargs_5: + lst_a cargs_5, sp_0, fn cargs_6: + lst_a cargs_6, item_9, fn cargs_7: + lst_a cargs_7, lala, fn cargs_8: + af log, cargs_8, fn mex_5: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" `; diff --git a/src/optimize/refs.fnk b/src/optimize/refs.fnk index d44979d..87a324e 100644 --- a/src/optimize/refs.fnk +++ b/src/optimize/refs.fnk @@ -1,6 +1,6 @@ {reverse} = import '@fink/std-lib/iter.fnk' -{update_value, get_value} = import '../ir/context.fnk' +{update_value, get_value, unique_name} = import '../ir/context.fnk' @@ -110,21 +110,15 @@ optimize_lst_c = fn [expr, res], ctx: -create_lst = fn [id=false, ...ids], lst_id, idx=0, out=[]: +create_lst = fn [id=false, ...ids], lst_id, tmp_id, ctx, out=[]: match id: - # TODO gen unique ids false: - nid = {i: '${lst_id.i}_${idx + 1}', loc: lst_id.loc} - [[{f: 'lst', args: [], loc: lst_id.loc}, [nid]], ...out] + [[[{f: 'lst', args: [], loc: lst_id.loc}, [tmp_id]], ...out], ctx] else: - res_id = match idx: - 0: lst_id - else: {i: '${lst_id.i}_${idx}', loc: lst_id.loc} - - next_lst_id = {i: '${lst_id.i}_${idx + 1}'} - lst = [{f: 'lst_a', args: [next_lst_id, id], loc: id.loc}, [res_id]] - create_lst ids, lst_id, idx + 1, [lst, ...out] + [next_tmp_id, end_ctx] = unique_name lst_id.i, lst_id, ctx + lst = [{f: 'lst_a', args: [next_tmp_id, id], loc: id.loc}, [tmp_id]] + create_lst ids, lst_id, next_tmp_id, end_ctx, [lst, ...out] @@ -144,9 +138,8 @@ optimize_lst_r = fn [expr, res], ctx: {item_aliases: rev_aliases} = info # find existing tpl instead of creating item_aliases = reverse rev_aliases - next_ctx = update_value res_id, {item_aliases, tpr: lst_id}, ctx - next_lst = create_lst rev_aliases, res_id - [next_lst, next_ctx] + lst_ctx = update_value res_id, {item_aliases, tpr: lst_id}, ctx + create_lst rev_aliases, res_id, res_id, lst_ctx else: next_ctx = update_value res_id, {tpr: lst_id}, ctx diff --git a/src/optimize/tail-calls.fnk b/src/optimize/tail-calls.fnk index db83b69..da39da2 100644 --- a/src/optimize/tail-calls.fnk +++ b/src/optimize/tail-calls.fnk @@ -44,8 +44,6 @@ optimize_af = fn [expr, res], exprs, ctx: match [callee_id.i, next_expr]: [curr_fn_id.i, [{f: 'cc', args: [{i: ret_id.i}]}]]: - # TODO: if cc would have an id, we could just store opt info for it and - # convert it separately instead of using exprs opt_expr = {...expr, f: 'cf', args: [callee_id, ...args]} next_ctx = update_value curr_fn_id, {tco: true}, ctx [[[opt_expr, []]], rest_exprs, next_ctx]