From 62a0ff2e4c3f46d098e0c8e83d97b5ccc952b7d3 Mon Sep 17 00:00:00 2001 From: radrow Date: Sat, 2 Jul 2022 21:53:42 +0200 Subject: [PATCH 01/27] Add loop operator in fcode --- src/aeso_ast_to_fcode.erl | 45 +++++++++++++++++++++-- src/aeso_fcode_to_fate.erl | 65 ++++++++++++++++++++++++++------- test/aeso_compiler_tests.erl | 69 +----------------------------------- test/contracts/test.aes | 11 ++---- 4 files changed, 98 insertions(+), 92 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index d0328c9..159a74b 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -75,6 +75,7 @@ | {switch, fsplit()} | {set_state, state_reg(), fexpr()} | {get_state, state_reg()} + | {loop, fexpr(), var_name(), fexpr()} | {continue, fexpr()} | {break, fexpr()} %% The following (unapplied top-level functions/builtins and %% lambdas) are generated by the fcode compiler, but translated %% to closures by the lambda lifter. @@ -653,9 +654,20 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> nil, Es); expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> - {def_u, FromTo, _} = resolve_fun(Env, ["ListInternal", "from_to"]), - {def, FromTo, [expr_to_fcode(Env, A), expr_to_fcode(Env, B)]}; - + AV = fresh_name(), + BV = fresh_name(), + WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, A), X} end, + WithB = fun(X) -> {'let', BV, expr_to_fcode(Env, B), X} end, + St = fresh_name(), + It = fresh_name(), + Init = {tuple, [nil, {var, AV}]}, + WithA(WithB( + {loop, Init, St, + {'let', It, {proj, {var, St}, 2}, + make_if({op, '=<', [{var, It}, {var, BV}]}, + {continue, {tuple, [{op, '::', [{var, It}, {proj, {var, St}, 1}]}]}}, + {break, {proj, {var, St}, 2}} + )}})); expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) -> {op, '::', [expr_to_fcode(Env, Yield), nil]}; expr_to_fcode(Env, _Type, {list_comp, As, Yield, [{comprehension_bind, Pat = {typed, _, _, PatType}, BindExpr}|Rest]}) -> @@ -1338,6 +1350,9 @@ lambda_lift_expr(Layout, Expr) -> {proj, A, I} -> {proj, lambda_lift_expr(Layout, A), I}; {set_proj, A, I, B} -> {set_proj, lambda_lift_expr(Layout, A), I, lambda_lift_expr(Layout, B)}; {op, Op, As} -> {op, Op, lambda_lift_exprs(Layout, As)}; + {loop, Init, I, Body} -> {loop, lambda_lift_expr(Layout, Init), I, lambda_lift_expr(Layout, Body)}; + {break, E} -> {break, lambda_lift_expr(Layout, E)}; + {continue, E} -> {continue, lambda_lift_expr(Layout, E)}; {'let', X, A, B} -> {'let', X, lambda_lift_expr(Layout, A), lambda_lift_expr(Layout, B)}; {funcall, A, Bs} -> {funcall, lambda_lift_expr(Layout, A), lambda_lift_exprs(Layout, Bs)}; {set_state, R, A} -> {set_state, R, lambda_lift_expr(Layout, A)}; @@ -1653,6 +1668,9 @@ read_only({switch, Split}) -> read_only(Split); read_only({split, _, _, Cases}) -> read_only(Cases); read_only({nosplit, E}) -> read_only(E); read_only({'case', _, Split}) -> read_only(Split); +read_only({loop, Init, _, Body}) -> read_only(Init) andalso read_only(Body); +read_only({break, E}) -> read_only(E); +read_only({continue, E}) -> read_only(E); read_only({'let', _, A, B}) -> read_only([A, B]); read_only({funcall, _, _}) -> false; read_only({closure, _, _}) -> internal_error(no_closures_here); @@ -1850,6 +1868,9 @@ free_vars(Expr) -> {proj, A, _} -> free_vars(A); {set_proj, A, _, B} -> free_vars([A, B]); {op, _, As} -> free_vars(As); + {loop, Init, Var, Body} -> free_vars(Init) ++ (free_vars(Body) -- [Var]); + {break, E} -> free_vars(E); + {continue, E} -> free_vars(E); {'let', X, A, B} -> free_vars([A, {lam, [X], B}]); {funcall, A, Bs} -> free_vars([A | Bs]); {set_state, _, A} -> free_vars(A); @@ -1881,6 +1902,9 @@ used_defs(Expr) -> {proj, A, _} -> used_defs(A); {set_proj, A, _, B} -> used_defs([A, B]); {op, _, As} -> used_defs(As); + {loop, I, _, B} -> used_defs(I) ++ used_defs(B); + {break, E} -> used_defs(E); + {continue, E} -> used_defs(E); {'let', _, A, B} -> used_defs([A, B]); {funcall, A, Bs} -> used_defs([A | Bs]); {set_state, _, A} -> used_defs(A); @@ -1917,6 +1941,9 @@ bottom_up(F, Env, Expr) -> {get_state, _} -> Expr; {closure, F, CEnv} -> {closure, F, bottom_up(F, Env, CEnv)}; {switch, Split} -> {switch, bottom_up(F, Env, Split)}; + {loop, Init, Var, Body} -> {loop, bottom_up(F, Env, Init), Var, bottom_up(F, Env, Body)}; + {break, E} -> {break, bottom_up(F, Env, E)}; + {continue, E} -> {continue, bottom_up(F, Env, E)}; {lam, Xs, B} -> {lam, Xs, bottom_up(F, Env, B)}; {'let', X, E, Body} -> E1 = bottom_up(F, Env, E), @@ -1978,6 +2005,11 @@ rename(Ren, Expr) -> {lam, Xs, B} -> {Zs, Ren1} = rename_bindings(Ren, Xs), {lam, Zs, rename(Ren1, B)}; + {loop, Init, Var, Body} -> + {Z, Ren1} = rename_binding(Ren, Var), + {loop, rename(Ren, Init), Z, rename(Ren1, Body)}; + {break, E} -> {break, rename(Ren, E)}; + {continue, E} -> {continue, rename(Ren, E)}; {'let', X, E, Body} -> {Z, Ren1} = rename_binding(Ren, X), {'let', Z, rename(Ren, E), rename(Ren1, Body)} @@ -2169,6 +2201,13 @@ pp_fexpr({tuple, Es}) -> pp_parens(pp_par(pp_punctuate(pp_text(","), [pp_fexpr(E) || E <- Es]))); pp_fexpr({proj, E, I}) -> pp_beside([pp_fexpr(E), pp_text("."), pp_int(I)]); +pp_fexpr({loop, Init, Var, Body}) -> + pp_par( + [ pp_beside([pp_text("loop"), pp_fexpr(Init), pp_text("as"), pp_text(Var)]) + , pp_fexpr(Body) + ]); +pp_fexpr({break, E}) -> pp_beside([pp_text("break"), pp_fexpr(E)]); +pp_fexpr({continue, E}) -> pp_beside([pp_text("continue"), pp_fexpr(E)]); pp_fexpr({lam, Xs, A}) -> pp_par([pp_fexpr({tuple, [{var, X} || X <- Xs]}), pp_text("=>"), prettypr:nest(2, pp_fexpr(A))]); diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 67a4b5c..23e8b31 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -45,7 +45,7 @@ -define(s(N), {store, N}). -define(void, {var, 9999}). --record(env, { contract, vars = [], locals = [], current_function, tailpos = true, child_contracts = #{}, options = []}). +-record(env, { contract, vars = [], locals = [], break_ref = none, cont_ref = none, loop_it = none, current_function, tailpos = true, child_contracts = #{}, options = []}). %% -- Debugging -------------------------------------------------------------- @@ -77,6 +77,7 @@ compile(ChildContracts, FCode, Options) -> SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options), SFuns1 = optimize_scode(SFuns, Options), FateCode = to_basic_blocks(SFuns1), + io:format("FINAL:\~p\n\n", [FateCode]), ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), FateCode. @@ -159,6 +160,9 @@ init_env(ChildContracts, ContractName, FunNames, Name, Args, Options) -> next_var(#env{ vars = Vars }) -> 1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]). +bind_loop(ContRef, BreakRef, It, Env) -> + Env#env{break_ref = BreakRef, cont_ref = ContRef, loop_it = It}. + bind_var(Name, Var, Env = #env{ vars = Vars }) -> Env#env{ vars = [{Name, Var} | Vars] }. @@ -368,7 +372,19 @@ to_scode1(Env, {set_state, Reg, Val}) -> to_scode1(Env, {closure, Fun, FVs}) -> to_scode(Env, {tuple, [{lit, {string, make_function_id(Fun)}}, FVs]}); - +to_scode1(Env, {loop, Init, It, Expr}) -> + ContRef = make_ref(), + BreakRef = make_ref(), + InitS = to_scode(Env, Init) ++ [{jump, ContRef}], + {ItV, Env1} = bind_local(It, Env), + ExprS = to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr) ++ [{jumpif, ?a, ContRef}, {jump, BreakRef}], + [{loop, InitS, It, ExprS, ContRef, BreakRef}]; +to_scode1(Env = #env{cont_ref = ContRef, loop_it = It}, {continue, Expr}) -> + ExprS = to_scode1(Env, Expr), + ExprS ++ [{'POP', It}, push(?i(1))]; +to_scode1(Env = #env{break_ref = BreakRef}, {break, Expr}) -> + ExprS = to_scode1(Env, Expr), + ExprS ++ [push(?i(0))]; to_scode1(Env, {switch, Case}) -> split_to_scode(Env, Case). @@ -712,6 +728,8 @@ flatten(Code) -> lists:map(fun flatten_s/1, lists:flatten(Code)). flatten_s({switch, Arg, Type, Alts, Catch}) -> {switch, Arg, Type, [flatten(Alt) || Alt <- Alts], flatten(Catch)}; +flatten_s({loop, Init, It, Body, BRef, CRef}) -> + {loop, flatten(Init), It, flatten(Body), BRef, CRef}; flatten_s(I) -> I. -define(MAX_SIMPL_ITERATIONS, 10). @@ -808,6 +826,11 @@ ann_live1(LiveTop, {switch, Arg, Type, Alts, Def}, LiveOut) -> {Def1, LiveDef} = ann_live(LiveTop, Def, LiveOut), LiveIn = ordsets:union([Read, LiveDef | LiveAlts]), {{switch, Arg, Type, Alts1, Def1}, LiveIn}; +ann_live1(LiveTop, {loop, Init, It, Body, BRef, CRef}, LiveOut) -> + {Init1, LiveInit} = ann_live(LiveTop, Init, LiveOut), + {Body1, LiveBody} = ann_live(LiveTop, Body, LiveOut), + LiveIn = ordsets:union([It, LiveInit, LiveBody]), % TODO not sure about this + {{loop, Init1, It, Body1, BRef, CRef}, LiveIn}; ann_live1(_LiveTop, I, LiveOut) -> #{ read := Reads0, write := W } = attributes(I), Reads = lists:filter(fun is_reg/1, Reads0), @@ -843,7 +866,9 @@ attributes(I) -> {'CALL_T', A} -> Impure(pc, [A]); {'CALL_VALUE', A} -> Pure(A, []); {'JUMP', _} -> Impure(pc, []); + {jump, _} -> Impure(pc, []); {'JUMPIF', A, _} -> Impure(pc, A); + {jumpif, A, _} -> Impure(pc, A); {'SWITCH_V2', A, _, _} -> Impure(pc, A); {'SWITCH_V3', A, _, _, _} -> Impure(pc, A); {'SWITCH_VN', A, _} -> Impure(pc, A); @@ -1023,6 +1048,7 @@ var_writes(I) -> -spec independent(sinstr_a(), sinstr_a()) -> boolean(). %% independent({switch, _, _, _, _}, _) -> false; %% Commented due to Dialyzer whinging independent(_, {switch, _, _, _, _}) -> false; +independent(_, {loop, _, _, _, _, _}) -> false; independent({i, _, I}, {i, _, J}) -> #{ write := WI, read := RI, pure := PureI } = attributes(I), #{ write := WJ, read := RJ, pure := PureJ } = attributes(J), @@ -1505,6 +1531,8 @@ from_op_view(Op, R, As) -> list_to_tuple([Op, R | As]). (missing) -> missing. unannotate({switch, Arg, Type, Alts, Def}) -> [{switch, Arg, Type, [unannotate(A) || A <- Alts], unannotate(Def)}]; +unannotate({loop, Init, It, Body, BRef, CRef}) -> + [{loop, unannotate(Init), It, unannotate(Body), BRef, CRef}]; unannotate(missing) -> missing; unannotate(Code) when is_list(Code) -> lists:flatmap(fun unannotate/1, Code); @@ -1547,6 +1575,7 @@ to_basic_blocks([], Acc) -> Acc. bb(_Name, Code) -> + io:format("FUN: ~p\nCODE:\n~p\n\n", [_Name, Code]), Blocks0 = blocks(Code), Blocks1 = optimize_blocks(Blocks0), Blocks = lists:flatmap(fun split_calls/1, Blocks1), @@ -1567,7 +1596,7 @@ bb(_Name, Code) -> -type bb() :: {bbref(), bcode()}. -type bcode() :: [binstr()]. -type binstr() :: {jump, bbref()} - | {jumpif, bbref()} + | {jumpif, term(), bbref()} | tuple(). %% FATE instruction -spec blocks(scode()) -> [bb()]. @@ -1581,27 +1610,37 @@ blocks([], Acc) -> blocks([Blk | Blocks], Acc) -> block(Blk, [], Blocks, Acc). +fresh_block(C, Ca) -> + R = make_ref(), + {R, [#blk{ref = R, code = C, catchall = Ca}]}. + -spec block(#blk{}, bcode(), [#blk{}], [bb()]) -> [bb()]. block(#blk{ref = Ref, code = []}, CodeAcc, Blocks, BlockAcc) -> blocks(Blocks, [{Ref, lists:reverse(CodeAcc)} | BlockAcc]); +block(Blk = #blk{code = [{loop, Init, _, Expr, ContRef, BreakRef} | Code], catchall = Catchall}, Acc, Blocks, BlockAcc) -> + LoopBlock = #blk{ref = ContRef, code = Expr, catchall = BreakRef}, + BreakBlock = #blk{ref = BreakRef, code = Code, catchall = Catchall}, + + io:format("INIT: ~p\n\nLOOP: ~p\n\nBREAK: ~p\n\n", [Init, Expr, Code]), + + block(Blk#blk{code = Init}, Acc, [LoopBlock, BreakBlock | Blocks], BlockAcc); block(Blk = #blk{code = [switch_body | Code]}, Acc, Blocks, BlockAcc) -> %% Reached the body of a switch. Clear catchall ref. block(Blk#blk{code = Code, catchall = none}, Acc, Blocks, BlockAcc); block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code], catchall = Catchall}, Acc, Blocks, BlockAcc) -> - FreshBlk = fun(C, Ca) -> - R = make_ref(), - {R, [#blk{ref = R, code = C, catchall = Ca}]} - end, - {RestRef, RestBlk} = FreshBlk(Code, Catchall), + {RestRef, RestBlk} = fresh_block(Code, Catchall), {DefRef, DefBlk} = case Default of missing when Catchall == none -> - FreshBlk([aeb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none); + fresh_block([aeb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none); missing -> {Catchall, []}; - _ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall) + _ -> fresh_block(Default ++ [{jump, RestRef}], Catchall) %% ^ fall-through to the outer catchall end, + + io:format("RestRef: ~p, DefRef: ~p\n\n", [RestRef, DefRef]), + %% If we don't generate a switch, we need to pop the argument if on the stack. Pop = [{'POP', ?void} || Arg == ?a], {Blk1, Code1, AltBlks} = @@ -1611,7 +1650,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code], {ThenRef, ThenBlk} = case TrueCode of missing -> {DefRef, []}; - _ -> FreshBlk(TrueCode ++ [{jump, RestRef}], DefRef) + _ -> fresh_block(TrueCode ++ [{jump, RestRef}], DefRef) end, ElseCode = case FalseCode of @@ -1646,7 +1685,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code], true -> {Blk#blk{code = Pop ++ [{jump, DefRef}]}, [], []}; false -> MkBlk = fun(missing) -> {DefRef, []}; - (ACode) -> FreshBlk(ACode ++ [{jump, RestRef}], DefRef) + (ACode) -> fresh_block(ACode ++ [{jump, RestRef}], DefRef) end, {AltRefs, AltBs} = lists:unzip(lists:map(MkBlk, Alts)), {Blk#blk{code = []}, [{switch, Arg, AltRefs}], lists:append(AltBs)} @@ -1664,6 +1703,7 @@ optimize_blocks(Blocks) -> Rev = fun(Bs) -> [ {Ref, lists:reverse(Code)} || {Ref, Code} <- Bs ] end, RBlocks = Rev(Blocks), RBlockMap = maps:from_list(RBlocks), + io:format("REORDERING ~p\n\n", [RBlocks]), RBlocks1 = reorder_blocks(RBlocks, []), RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ], RBlocks3 = shortcut_jump_chains(RBlocks2), @@ -1686,6 +1726,7 @@ reorder_blocks(Ref, Code, Blocks, Acc) -> [{'EXIT', _}|_] -> reorder_blocks(Blocks, Acc1); [{'ABORT', _}|_] -> reorder_blocks(Blocks, Acc1); [{switch, _, _}|_] -> reorder_blocks(Blocks, Acc1); + [{jumpif, _, _}|_] -> reorder_blocks(Blocks, Acc1); [{jump, L}|_] -> NotL = fun({L1, _}) -> L1 /= L end, case lists:splitwith(NotL, Blocks) of diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index fe53c95..379daad 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -140,74 +140,7 @@ compile(Name, Options) -> %% The currently compilable contracts. compilable_contracts() -> - ["complex_types", - "counter", - "dutch_auction", - "environment", - "factorial", - "functions", - "fundme", - "identity", - "maps", - "oracles", - "remote_call", - "remote_call_ambiguous_record", - "simple", - "simple_storage", - "spend_test", - "stack", - "test", - "builtin_bug", - "builtin_map_get_bug", - "lc_record_bug", - "nodeadcode", - "deadcode", - "variant_types", - "state_handling", - "events", - "include", - "basic_auth", - "basic_auth_tx", - "bitcoin_auth", - "address_literals", - "bytes_equality", - "address_chain", - "namespace_bug", - "bytes_to_x", - "bytes_concat", - "aens", - "aens_update", - "tuple_match", - "cyclic_include", - "stdlib_include", - "double_include", - "manual_stdlib_include", - "list_comp", - "payable", - "unapplied_builtins", - "underscore_number_literals", - "pairing_crypto", - "qualified_constructor", - "let_patterns", - "lhs_matching", - "more_strings", - "protected_call", - "hermetization_turnoff", - "multiple_contracts", - "clone", - "clone_simple", - "create", - "child_contract_init_bug", - "using_namespace", - "assign_patterns", - "patterns_guards", - "pipe_operator", - "polymorphism_contract_implements_interface", - "polymorphism_contract_multi_interface", - "polymorphism_contract_interface_extends_interface", - "polymorphism_contract_interface_extensions", - "polymorphism_contract_interface_same_decl_multi_interface", - "polymorphism_contract_interface_same_name_same_type", + [ "test" % Custom general-purpose test file. Keep it last on the list. ]. diff --git a/test/contracts/test.aes b/test/contracts/test.aes index d978179..5a90d06 100644 --- a/test/contracts/test.aes +++ b/test/contracts/test.aes @@ -1,12 +1,5 @@ // This is a custom test file if you need to run a compiler without // changing aeso_compiler_tests.erl -include "List.aes" - -contract IntegerHolder = - type state = int - entrypoint init(x) = x - entrypoint get() = state - -main contract Test = - stateful entrypoint f(c) = Chain.clone(ref=c, 123) +contract C = + entrypoint test() = [1..5] \ No newline at end of file -- 2.30.2 From e050618d7ab3fff8f5a5667a5d1706c31525a12a Mon Sep 17 00:00:00 2001 From: radrow Date: Sat, 2 Jul 2022 23:23:13 +0200 Subject: [PATCH 02/27] Fix stupid --- src/aeso_ast_to_fcode.erl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 159a74b..daca7e5 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -663,10 +663,12 @@ expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> Init = {tuple, [nil, {var, AV}]}, WithA(WithB( {loop, Init, St, - {'let', It, {proj, {var, St}, 2}, + {'let', It, {proj, {var, St}, 1}, make_if({op, '=<', [{var, It}, {var, BV}]}, - {continue, {tuple, [{op, '::', [{var, It}, {proj, {var, St}, 1}]}]}}, - {break, {proj, {var, St}, 2}} + {continue, {tuple, [{op, '::', [{var, It}, {proj, {var, St}, 0}]}, + {op, '+', [{var, It}, {lit, {int, 1}}]} + ]}}, + {break, {proj, {var, St}, 0}} )}})); expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) -> {op, '::', [expr_to_fcode(Env, Yield), nil]}; -- 2.30.2 From 0f5daafc2921be0aadf8ec332237bde26e6c2a00 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 15:57:28 +0200 Subject: [PATCH 03/27] . --- src/aeso_ast_to_fcode.erl | 12 ++++++++++++ src/aeso_fcode_to_fate.erl | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index daca7e5..54f61c7 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -653,6 +653,18 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end, nil, Es); +expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> + AV = fresh_name(), + BV = fresh_name(), + WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, A), X} end, + WithB = fun(X) -> {'let', BV, expr_to_fcode(Env, B), X} end, + St = fresh_name(), + Init = {var, AV}, + Loop = {loop, Init, St, make_if({op, '<', [{var, St}, {var, BV}]}, + {continue, {op, '+', [{var, St}, {lit, {int, 1}}]}}, + {break, nil} + )}, + WithA(WithB(Loop)); expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> AV = fresh_name(), BV = fresh_name(), diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 23e8b31..ff34f42 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -378,10 +378,10 @@ to_scode1(Env, {loop, Init, It, Expr}) -> InitS = to_scode(Env, Init) ++ [{jump, ContRef}], {ItV, Env1} = bind_local(It, Env), ExprS = to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr) ++ [{jumpif, ?a, ContRef}, {jump, BreakRef}], - [{loop, InitS, It, ExprS, ContRef, BreakRef}]; + [{loop, InitS, ItV, ExprS, ContRef, BreakRef}]; to_scode1(Env = #env{cont_ref = ContRef, loop_it = It}, {continue, Expr}) -> ExprS = to_scode1(Env, Expr), - ExprS ++ [{'POP', It}, push(?i(1))]; + ExprS ++ [{'STORE', It, ?a}, push(?i(1))]; to_scode1(Env = #env{break_ref = BreakRef}, {break, Expr}) -> ExprS = to_scode1(Env, Expr), ExprS ++ [push(?i(0))]; -- 2.30.2 From ed934019dbcc8495a35820250b18ca809fa8d9fa Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 16:01:50 +0200 Subject: [PATCH 04/27] . --- src/aeso_ast_to_fcode.erl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 54f61c7..2c25542 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -654,17 +654,13 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> nil, Es); expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> - AV = fresh_name(), - BV = fresh_name(), - WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, A), X} end, - WithB = fun(X) -> {'let', BV, expr_to_fcode(Env, B), X} end, St = fresh_name(), - Init = {var, AV}, - Loop = {loop, Init, St, make_if({op, '<', [{var, St}, {var, BV}]}, + Init = expr_to_fcode(Env, A), + Loop = {loop, Init, St, make_if({op, '<', [{var, St}, expr_to_fcode(Env, B)]}, {continue, {op, '+', [{var, St}, {lit, {int, 1}}]}}, {break, nil} )}, - WithA(WithB(Loop)); + Loop; expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> AV = fresh_name(), BV = fresh_name(), -- 2.30.2 From a64e9643fd7c4114c444e5a0c4d840a55fb79714 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 16:04:01 +0200 Subject: [PATCH 05/27] . --- src/aeso_fcode_to_fate.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index ff34f42..0bb5107 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -378,7 +378,7 @@ to_scode1(Env, {loop, Init, It, Expr}) -> InitS = to_scode(Env, Init) ++ [{jump, ContRef}], {ItV, Env1} = bind_local(It, Env), ExprS = to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr) ++ [{jumpif, ?a, ContRef}, {jump, BreakRef}], - [{loop, InitS, ItV, ExprS, ContRef, BreakRef}]; + [{loop, InitS, It, ExprS, ContRef, BreakRef}]; to_scode1(Env = #env{cont_ref = ContRef, loop_it = It}, {continue, Expr}) -> ExprS = to_scode1(Env, Expr), ExprS ++ [{'STORE', It, ?a}, push(?i(1))]; -- 2.30.2 From c4243fb1da166706532e9e88bef99a9b835175da Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:08:04 +0200 Subject: [PATCH 06/27] . --- src/aeso_ast_to_fcode.erl | 2 +- src/aeso_fcode_to_fate.erl | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 2c25542..8162953 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -656,7 +656,7 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> St = fresh_name(), Init = expr_to_fcode(Env, A), - Loop = {loop, Init, St, make_if({op, '<', [{var, St}, expr_to_fcode(Env, B)]}, + Loop = {loop, {}, St, make_if({op, '<', [{var, St}, expr_to_fcode(Env, B)]}, {continue, {op, '+', [{var, St}, {lit, {int, 1}}]}}, {break, nil} )}, diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 0bb5107..817e5d9 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -375,14 +375,14 @@ to_scode1(Env, {closure, Fun, FVs}) -> to_scode1(Env, {loop, Init, It, Expr}) -> ContRef = make_ref(), BreakRef = make_ref(), - InitS = to_scode(Env, Init) ++ [{jump, ContRef}], {ItV, Env1} = bind_local(It, Env), + InitS = to_scode(Env, Init) ++ [aeb_fate_ops:store({var, ItV}, {stack, 0}), {jump, ContRef}], ExprS = to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr) ++ [{jumpif, ?a, ContRef}, {jump, BreakRef}], [{loop, InitS, It, ExprS, ContRef, BreakRef}]; -to_scode1(Env = #env{cont_ref = ContRef, loop_it = It}, {continue, Expr}) -> +to_scode1(Env = #env{loop_it = It}, {continue, Expr}) -> ExprS = to_scode1(Env, Expr), - ExprS ++ [{'STORE', It, ?a}, push(?i(1))]; -to_scode1(Env = #env{break_ref = BreakRef}, {break, Expr}) -> + ExprS ++ [aeb_fate_ops:store({var, It}, {stack, 0}), push(?i(1))]; +to_scode1(Env, {break, Expr}) -> ExprS = to_scode1(Env, Expr), ExprS ++ [push(?i(0))]; to_scode1(Env, {switch, Case}) -> -- 2.30.2 From ffc63704fb3078d4565ebe71f7e67d933a320bf7 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:08:44 +0200 Subject: [PATCH 07/27] . --- src/aeso_ast_to_fcode.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 8162953..2c25542 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -656,7 +656,7 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> St = fresh_name(), Init = expr_to_fcode(Env, A), - Loop = {loop, {}, St, make_if({op, '<', [{var, St}, expr_to_fcode(Env, B)]}, + Loop = {loop, Init, St, make_if({op, '<', [{var, St}, expr_to_fcode(Env, B)]}, {continue, {op, '+', [{var, St}, {lit, {int, 1}}]}}, {break, nil} )}, -- 2.30.2 From 126a78455bb707d1f8c5515a06ba7449395418d9 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:09:21 +0200 Subject: [PATCH 08/27] . --- src/aeso_fcode_to_fate.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 817e5d9..c230d76 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -381,10 +381,10 @@ to_scode1(Env, {loop, Init, It, Expr}) -> [{loop, InitS, It, ExprS, ContRef, BreakRef}]; to_scode1(Env = #env{loop_it = It}, {continue, Expr}) -> ExprS = to_scode1(Env, Expr), - ExprS ++ [aeb_fate_ops:store({var, It}, {stack, 0}), push(?i(1))]; + ExprS ++ [aeb_fate_ops:store({var, It}, {stack, 0}), push(?i(true))]; to_scode1(Env, {break, Expr}) -> ExprS = to_scode1(Env, Expr), - ExprS ++ [push(?i(0))]; + ExprS ++ [push(?i(false))]; to_scode1(Env, {switch, Case}) -> split_to_scode(Env, Case). -- 2.30.2 From 85c14c512b3258a16948da9bf54f798086cd10b6 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:18:00 +0200 Subject: [PATCH 09/27] . --- src/aeso_fcode_to_fate.erl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index c230d76..9c841f5 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -376,15 +376,16 @@ to_scode1(Env, {loop, Init, It, Expr}) -> ContRef = make_ref(), BreakRef = make_ref(), {ItV, Env1} = bind_local(It, Env), - InitS = to_scode(Env, Init) ++ [aeb_fate_ops:store({var, ItV}, {stack, 0}), {jump, ContRef}], - ExprS = to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr) ++ [{jumpif, ?a, ContRef}, {jump, BreakRef}], + InitS = to_scode(notail(Env), Init) ++ [{jump, ContRef}], + ExprS = [aeb_fate_ops:store({var, ItV}, {stack, 0}), + to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr), + {jump, BreakRef}], [{loop, InitS, It, ExprS, ContRef, BreakRef}]; -to_scode1(Env = #env{loop_it = It}, {continue, Expr}) -> - ExprS = to_scode1(Env, Expr), - ExprS ++ [aeb_fate_ops:store({var, It}, {stack, 0}), push(?i(true))]; +to_scode1(Env = #env{cont_ref = ContRef}, {continue, Expr}) -> + ExprS = to_scode1(notail(Env), Expr), + ExprS ++ [{jump, ContRef}]; to_scode1(Env, {break, Expr}) -> - ExprS = to_scode1(Env, Expr), - ExprS ++ [push(?i(false))]; + to_scode1(Env, Expr); to_scode1(Env, {switch, Case}) -> split_to_scode(Env, Case). -- 2.30.2 From 5c14fc3fe62d76190ed288a2c2c4209d12626b8c Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:27:21 +0200 Subject: [PATCH 10/27] . --- src/aeso_fcode_to_fate.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 9c841f5..a856426 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -376,14 +376,15 @@ to_scode1(Env, {loop, Init, It, Expr}) -> ContRef = make_ref(), BreakRef = make_ref(), {ItV, Env1} = bind_local(It, Env), - InitS = to_scode(notail(Env), Init) ++ [{jump, ContRef}], + InitS = [to_scode(notail(Env), Init), + {jump, ContRef}], ExprS = [aeb_fate_ops:store({var, ItV}, {stack, 0}), to_scode(bind_loop(ContRef, BreakRef, ItV, Env1), Expr), {jump, BreakRef}], [{loop, InitS, It, ExprS, ContRef, BreakRef}]; to_scode1(Env = #env{cont_ref = ContRef}, {continue, Expr}) -> - ExprS = to_scode1(notail(Env), Expr), - ExprS ++ [{jump, ContRef}]; + [to_scode1(notail(Env), Expr), + {jump, ContRef}]; to_scode1(Env, {break, Expr}) -> to_scode1(Env, Expr); to_scode1(Env, {switch, Case}) -> @@ -1727,7 +1728,6 @@ reorder_blocks(Ref, Code, Blocks, Acc) -> [{'EXIT', _}|_] -> reorder_blocks(Blocks, Acc1); [{'ABORT', _}|_] -> reorder_blocks(Blocks, Acc1); [{switch, _, _}|_] -> reorder_blocks(Blocks, Acc1); - [{jumpif, _, _}|_] -> reorder_blocks(Blocks, Acc1); [{jump, L}|_] -> NotL = fun({L1, _}) -> L1 /= L end, case lists:splitwith(NotL, Blocks) of @@ -1783,6 +1783,7 @@ tweak_returns(['RETURN', {'PUSH', A} | Code]) -> [{'RETURNR', A} | Code tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'EXIT', _} | _]]) -> Code; +tweak_returns(['RETURN' | Code = [{jump, _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [loop | _]]) -> Code; tweak_returns(Code) -> Code. -- 2.30.2 From 97db569b9bda9cbdb17863cfd68d4af1970a1811 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:32:05 +0200 Subject: [PATCH 11/27] . --- src/aeso_fcode_to_fate.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index a856426..79c6625 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1620,7 +1620,7 @@ fresh_block(C, Ca) -> block(#blk{ref = Ref, code = []}, CodeAcc, Blocks, BlockAcc) -> blocks(Blocks, [{Ref, lists:reverse(CodeAcc)} | BlockAcc]); block(Blk = #blk{code = [{loop, Init, _, Expr, ContRef, BreakRef} | Code], catchall = Catchall}, Acc, Blocks, BlockAcc) -> - LoopBlock = #blk{ref = ContRef, code = Expr, catchall = BreakRef}, + LoopBlock = #blk{ref = ContRef, code = Expr, catchall = none}, BreakBlock = #blk{ref = BreakRef, code = Code, catchall = Catchall}, io:format("INIT: ~p\n\nLOOP: ~p\n\nBREAK: ~p\n\n", [Init, Expr, Code]), -- 2.30.2 From 1aa476318ff9e9f0810b2914604e437829a5b91d Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 17:48:48 +0200 Subject: [PATCH 12/27] . --- src/aeso_fcode_to_fate.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 79c6625..a6dcb72 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1707,6 +1707,7 @@ optimize_blocks(Blocks) -> RBlockMap = maps:from_list(RBlocks), io:format("REORDERING ~p\n\n", [RBlocks]), RBlocks1 = reorder_blocks(RBlocks, []), + io:format("REORDERED ~p\n\n", [RBlocks1]), RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ], RBlocks3 = shortcut_jump_chains(RBlocks2), RBlocks4 = remove_dead_blocks(RBlocks3), @@ -1783,7 +1784,6 @@ tweak_returns(['RETURN', {'PUSH', A} | Code]) -> [{'RETURNR', A} | Code tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'EXIT', _} | _]]) -> Code; -tweak_returns(['RETURN' | Code = [{jump, _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [loop | _]]) -> Code; tweak_returns(Code) -> Code. -- 2.30.2 From cdcc119c9e50911b3c9af97b1b0018c9fdc108a3 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:19:06 +0200 Subject: [PATCH 13/27] . --- src/aeso_fcode_to_fate.erl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index a6dcb72..2f4bb47 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1706,8 +1706,8 @@ optimize_blocks(Blocks) -> RBlocks = Rev(Blocks), RBlockMap = maps:from_list(RBlocks), io:format("REORDERING ~p\n\n", [RBlocks]), - RBlocks1 = reorder_blocks(RBlocks, []), - io:format("REORDERED ~p\n\n", [RBlocks1]), + RBlocks0 = [{Ref, crop_jumps(Code)} || {Ref, Code} <- RBlocks], + RBlocks1 = reorder_blocks(RBlocks0, []), RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ], RBlocks3 = shortcut_jump_chains(RBlocks2), RBlocks4 = remove_dead_blocks(RBlocks3), @@ -1787,12 +1787,19 @@ tweak_returns(['RETURN' | Code = [{'EXIT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [loop | _]]) -> Code; tweak_returns(Code) -> Code. +%% Remove instructions that appear after jumps +crop_jumps(Code) -> + crop_jumps(Code, []). +crop_jumps([], Acc) -> + lists:reverse(Acc); +crop_jumps([I = {jump, _}|_], Acc) -> + lists:reverse([I|Acc]); +crop_jumps([I|Code], Acc) -> + crop_jumps(Code, [I|Acc]). + %% -- Split basic blocks at CALL instructions -- %% Calls can only return to a new basic block. Also splits at JUMPIF instructions. -split_calls({Ref, Code}) -> - split_calls(Ref, Code, [], []). - split_calls(Ref, [], Acc, Blocks) -> lists:reverse([{Ref, lists:reverse(Acc)} | Blocks]); split_calls(Ref, [I | Code], Acc, Blocks) when element(1, I) == 'CALL'; -- 2.30.2 From 54c8c50a582ba1547ca2941b097985c156c71375 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:20:48 +0200 Subject: [PATCH 14/27] . --- src/aeso_fcode_to_fate.erl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 2f4bb47..fe11e8b 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1800,6 +1800,9 @@ crop_jumps([I|Code], Acc) -> %% -- Split basic blocks at CALL instructions -- %% Calls can only return to a new basic block. Also splits at JUMPIF instructions. +split_calls({Ref, Code}) -> + split_calls(Ref, Code, [], []). + split_calls(Ref, [], Acc, Blocks) -> lists:reverse([{Ref, lists:reverse(Acc)} | Blocks]); split_calls(Ref, [I | Code], Acc, Blocks) when element(1, I) == 'CALL'; -- 2.30.2 From 701a24553a4afb3fc62e442d7f7223177585074a Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:23:26 +0200 Subject: [PATCH 15/27] . --- src/aeso_fcode_to_fate.erl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index fe11e8b..f41799c 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1703,11 +1703,10 @@ block(Blk = #blk{code = [I | Code]}, Acc, Blocks, BlockAcc) -> optimize_blocks(Blocks) -> %% We need to look at the last instruction a lot, so reverse all blocks. Rev = fun(Bs) -> [ {Ref, lists:reverse(Code)} || {Ref, Code} <- Bs ] end, - RBlocks = Rev(Blocks), + RBlocks = [{Ref, crop_jumps(Code)} || {Ref, Code} <- Blocks], RBlockMap = maps:from_list(RBlocks), io:format("REORDERING ~p\n\n", [RBlocks]), - RBlocks0 = [{Ref, crop_jumps(Code)} || {Ref, Code} <- RBlocks], - RBlocks1 = reorder_blocks(RBlocks0, []), + RBlocks1 = reorder_blocks(RBlocks, []), RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ], RBlocks3 = shortcut_jump_chains(RBlocks2), RBlocks4 = remove_dead_blocks(RBlocks3), @@ -1787,9 +1786,9 @@ tweak_returns(['RETURN' | Code = [{'EXIT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [loop | _]]) -> Code; tweak_returns(Code) -> Code. -%% Remove instructions that appear after jumps +%% Remove instructions that appear after jumps. Returns reversed code. crop_jumps(Code) -> - crop_jumps(Code, []). + crop_jumps(lists:reverse(Code), []). crop_jumps([], Acc) -> lists:reverse(Acc); crop_jumps([I = {jump, _}|_], Acc) -> -- 2.30.2 From c0330be3b408113d3e98afb8cc08b861114e0639 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:25:49 +0200 Subject: [PATCH 16/27] . --- src/aeso_fcode_to_fate.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index f41799c..909dc4f 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1788,7 +1788,7 @@ tweak_returns(Code) -> Code. %% Remove instructions that appear after jumps. Returns reversed code. crop_jumps(Code) -> - crop_jumps(lists:reverse(Code), []). + crop_jumps(Code, []). crop_jumps([], Acc) -> lists:reverse(Acc); crop_jumps([I = {jump, _}|_], Acc) -> -- 2.30.2 From 03e53f60cdba1c018c7d56b907c29e42944d0d34 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:26:25 +0200 Subject: [PATCH 17/27] . --- src/aeso_fcode_to_fate.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 909dc4f..7544c07 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1790,9 +1790,9 @@ tweak_returns(Code) -> Code. crop_jumps(Code) -> crop_jumps(Code, []). crop_jumps([], Acc) -> - lists:reverse(Acc); + Acc; crop_jumps([I = {jump, _}|_], Acc) -> - lists:reverse([I|Acc]); + [I|Acc]; crop_jumps([I|Code], Acc) -> crop_jumps(Code, [I|Acc]). -- 2.30.2 From cf7830e4f5063503f7912bd31e63c594398db45f Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:44:46 +0200 Subject: [PATCH 18/27] . --- src/aeso_fcode_to_fate.erl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 7544c07..69ff195 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -819,6 +819,9 @@ ann_live(LiveTop, [I | Is], LiveOut) -> ann_live1(_LiveTop, switch_body, LiveOut) -> Ann = #{ live_in => LiveOut, live_out => LiveOut }, {{i, Ann, switch_body}, LiveOut}; +ann_live1(LiveTop, {jump, Ref}, _LiveOut) -> + Ann = #{ live_in => LiveTop, live_out => [] }, + {{i, Ann, {jump, Ref}}, LiveTop}; ann_live1(LiveTop, loop, _LiveOut) -> Ann = #{ live_in => LiveTop, live_out => [] }, {{i, Ann, loop}, LiveTop}; @@ -1104,6 +1107,8 @@ simplify([I | Code], Options) -> simpl_s({switch, Arg, Type, Alts, Def}, Options) -> {switch, Arg, Type, [simplify(A, Options) || A <- Alts], simplify(Def, Options)}; +simpl_s({loop, Init, Var, Expr, ContRef, BreakRef}, Options) -> + {loop, simplify(Init, Options), Var, simplify(Expr, Options), ContRef, BreakRef}; simpl_s(I, _) -> I. %% Safe-guard against loops in the rewriting. Shouldn't happen so throw an @@ -1705,7 +1710,6 @@ optimize_blocks(Blocks) -> Rev = fun(Bs) -> [ {Ref, lists:reverse(Code)} || {Ref, Code} <- Bs ] end, RBlocks = [{Ref, crop_jumps(Code)} || {Ref, Code} <- Blocks], RBlockMap = maps:from_list(RBlocks), - io:format("REORDERING ~p\n\n", [RBlocks]), RBlocks1 = reorder_blocks(RBlocks, []), RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ], RBlocks3 = shortcut_jump_chains(RBlocks2), @@ -1786,13 +1790,15 @@ tweak_returns(['RETURN' | Code = [{'EXIT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [loop | _]]) -> Code; tweak_returns(Code) -> Code. -%% Remove instructions that appear after jumps. Returns reversed code. +%% -- Remove instructions that appear after jumps. Returns reversed code. +%% This is useful for example when bb emitter adds continuation jumps +%% for switch expressions, but some of the branches crop_jumps(Code) -> crop_jumps(Code, []). crop_jumps([], Acc) -> Acc; -crop_jumps([I = {jump, _}|_], Acc) -> - [I|Acc]; +%% crop_jumps([I = {jump, _}|_], Acc) -> +%% [I|Acc]; crop_jumps([I|Code], Acc) -> crop_jumps(Code, [I|Acc]). -- 2.30.2 From 4d6b13bcf181d2944e7eef3d2ea3efdd56b76970 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:53:27 +0200 Subject: [PATCH 19/27] . --- src/aeso_fcode_to_fate.erl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 69ff195..6db1074 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -1092,6 +1092,8 @@ live_in(R, {i, Ann, _}) -> live_in(R, Ann); live_in(R, [I = {i, _, _} | _]) -> live_in(R, I); live_in(R, [{switch, A, _, Alts, Def} | _]) -> R == A orelse lists:any(fun(Code) -> live_in(R, Code) end, [Def | Alts]); +live_in(R, [{loop, Init, Var, Expr, _, _}]) -> + live_in(Var, Init) orelse (R /= Var andalso live_in(R, Expr)); live_in(_, missing) -> false; live_in(_, []) -> false. @@ -1411,6 +1413,8 @@ does_abort({i, _, {'EXIT', _}}) -> true; does_abort(missing) -> true; does_abort({switch, _, _, Alts, Def}) -> lists:all(fun does_abort/1, [Def | Alts]); +does_abort({loop, Init, _, Expr, _, _}) -> + does_abort(Init) orelse does_abort(Expr); does_abort(_) -> false. %% STORE R A, SWITCH R --> SWITCH A @@ -1556,6 +1560,8 @@ desugar({'STORE', ?a, A}) -> [aeb_fate_ops:push(desugar_arg(A))]; desugar({'STORE', R, ?a}) -> [aeb_fate_ops:pop(desugar_arg(R))]; desugar({switch, Arg, Type, Alts, Def}) -> [{switch, desugar_arg(Arg), Type, [desugar(A) || A <- Alts], desugar(Def)}]; +desugar({loop, Init, Var, Expr, ContRef, BreakRef}) -> + [{loop, desugar(Init), Var, desugar(Expr), ContRef, BreakRef}]; desugar(missing) -> missing; desugar(Code) when is_list(Code) -> lists:flatmap(fun desugar/1, Code); -- 2.30.2 From d8558df6a456476b4a6d0bb7228eac74e5e7755c Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 18:57:01 +0200 Subject: [PATCH 20/27] . --- src/aeso_fcode_to_fate.erl | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 6db1074..37788fe 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -77,7 +77,6 @@ compile(ChildContracts, FCode, Options) -> SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options), SFuns1 = optimize_scode(SFuns, Options), FateCode = to_basic_blocks(SFuns1), - io:format("FINAL:\~p\n\n", [FateCode]), ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), FateCode. @@ -862,6 +861,7 @@ attributes(I) -> case I of loop -> Impure(pc, []); switch_body -> Pure(none, []); + {jump, _} -> Impure(pc, []); 'RETURN' -> Impure(pc, []); {'RETURNR', A} -> Impure(pc, A); {'CALL', A} -> Impure(?a, [A]); @@ -871,9 +871,7 @@ attributes(I) -> {'CALL_T', A} -> Impure(pc, [A]); {'CALL_VALUE', A} -> Pure(A, []); {'JUMP', _} -> Impure(pc, []); - {jump, _} -> Impure(pc, []); {'JUMPIF', A, _} -> Impure(pc, A); - {jumpif, A, _} -> Impure(pc, A); {'SWITCH_V2', A, _, _} -> Impure(pc, A); {'SWITCH_V3', A, _, _, _} -> Impure(pc, A); {'SWITCH_VN', A, _} -> Impure(pc, A); @@ -1588,7 +1586,6 @@ to_basic_blocks([], Acc) -> Acc. bb(_Name, Code) -> - io:format("FUN: ~p\nCODE:\n~p\n\n", [_Name, Code]), Blocks0 = blocks(Code), Blocks1 = optimize_blocks(Blocks0), Blocks = lists:flatmap(fun split_calls/1, Blocks1), @@ -1633,9 +1630,6 @@ block(#blk{ref = Ref, code = []}, CodeAcc, Blocks, BlockAcc) -> block(Blk = #blk{code = [{loop, Init, _, Expr, ContRef, BreakRef} | Code], catchall = Catchall}, Acc, Blocks, BlockAcc) -> LoopBlock = #blk{ref = ContRef, code = Expr, catchall = none}, BreakBlock = #blk{ref = BreakRef, code = Code, catchall = Catchall}, - - io:format("INIT: ~p\n\nLOOP: ~p\n\nBREAK: ~p\n\n", [Init, Expr, Code]), - block(Blk#blk{code = Init}, Acc, [LoopBlock, BreakBlock | Blocks], BlockAcc); block(Blk = #blk{code = [switch_body | Code]}, Acc, Blocks, BlockAcc) -> %% Reached the body of a switch. Clear catchall ref. @@ -1651,9 +1645,6 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code], _ -> fresh_block(Default ++ [{jump, RestRef}], Catchall) %% ^ fall-through to the outer catchall end, - - io:format("RestRef: ~p, DefRef: ~p\n\n", [RestRef, DefRef]), - %% If we don't generate a switch, we need to pop the argument if on the stack. Pop = [{'POP', ?void} || Arg == ?a], {Blk1, Code1, AltBlks} = @@ -1803,8 +1794,8 @@ crop_jumps(Code) -> crop_jumps(Code, []). crop_jumps([], Acc) -> Acc; -%% crop_jumps([I = {jump, _}|_], Acc) -> -%% [I|Acc]; +crop_jumps([I = {jump, _}|_], Acc) -> + [I|Acc]; crop_jumps([I|Code], Acc) -> crop_jumps(Code, [I|Acc]). -- 2.30.2 From 7277a968f8827c2b32a2f5f9eea17517d2724a99 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:06:56 +0200 Subject: [PATCH 21/27] . --- src/aeso_ast_to_fcode.erl | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 2c25542..f5f528e 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -662,22 +662,21 @@ expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> )}, Loop; expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> - AV = fresh_name(), - BV = fresh_name(), - WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, A), X} end, + BV = fresh_name(), % var to keep B WithB = fun(X) -> {'let', BV, expr_to_fcode(Env, B), X} end, - St = fresh_name(), - It = fresh_name(), - Init = {tuple, [nil, {var, AV}]}, - WithA(WithB( - {loop, Init, St, - {'let', It, {proj, {var, St}, 1}, - make_if({op, '=<', [{var, It}, {var, BV}]}, - {continue, {tuple, [{op, '::', [{var, It}, {proj, {var, St}, 0}]}, - {op, '+', [{var, It}, {lit, {int, 1}}]} - ]}}, - {break, {proj, {var, St}, 0}} - )}})); + St = fresh_name(), % loop state + ItProj = {proj, {var, St}, 1}, + AcProj = {proj, {var, St}, 0}, + Init = {tuple, [nil, expr_to_fcode(Env, A)]}, + Loop = {loop, Init, St, + make_if( + {op, '=<', [ItProj, {var, BV}]}, + {continue, {tuple, [{op, '::', [ItProj, AcProj]}, + {op, '+', [ItProj, {lit, {int, 1}}]} + ]}}, + {break, AcProj} + )}, + WithB(Loop); expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) -> {op, '::', [expr_to_fcode(Env, Yield), nil]}; expr_to_fcode(Env, _Type, {list_comp, As, Yield, [{comprehension_bind, Pat = {typed, _, _, PatType}, BindExpr}|Rest]}) -> -- 2.30.2 From bd726a8902e8f1045d787933b44297af44535626 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:10:47 +0200 Subject: [PATCH 22/27] . --- src/aeso_ast_to_fcode.erl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index f5f528e..1c95a88 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -652,15 +652,6 @@ expr_to_fcode(Env, {record_t, FieldTypes}, {record, _Ann, Rec, Fields}) -> expr_to_fcode(Env, _Type, {list, _, Es}) -> lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end, nil, Es); - -expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> - St = fresh_name(), - Init = expr_to_fcode(Env, A), - Loop = {loop, Init, St, make_if({op, '<', [{var, St}, expr_to_fcode(Env, B)]}, - {continue, {op, '+', [{var, St}, {lit, {int, 1}}]}}, - {break, nil} - )}, - Loop; expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> BV = fresh_name(), % var to keep B WithB = fun(X) -> {'let', BV, expr_to_fcode(Env, B), X} end, -- 2.30.2 From 1d6f24965bfff011a486fb8c28d4054f14272173 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:11:50 +0200 Subject: [PATCH 23/27] . --- src/aeso_ast_to_fcode.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 1c95a88..f2e50c8 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -653,21 +653,21 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end, nil, Es); expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> - BV = fresh_name(), % var to keep B - WithB = fun(X) -> {'let', BV, expr_to_fcode(Env, B), X} end, + AV = fresh_name(), % var to keep B + WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, B), X} end, St = fresh_name(), % loop state ItProj = {proj, {var, St}, 1}, AcProj = {proj, {var, St}, 0}, - Init = {tuple, [nil, expr_to_fcode(Env, A)]}, + Init = {tuple, [nil, expr_to_fcode(Env, B)]}, Loop = {loop, Init, St, make_if( - {op, '=<', [ItProj, {var, BV}]}, + {op, '=<', [ItProj, {var, AV}]}, {continue, {tuple, [{op, '::', [ItProj, AcProj]}, {op, '+', [ItProj, {lit, {int, 1}}]} ]}}, {break, AcProj} )}, - WithB(Loop); + WithA(Loop); expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) -> {op, '::', [expr_to_fcode(Env, Yield), nil]}; expr_to_fcode(Env, _Type, {list_comp, As, Yield, [{comprehension_bind, Pat = {typed, _, _, PatType}, BindExpr}|Rest]}) -> -- 2.30.2 From 5575d3cb17b943c2215914e15a1343a9a189b134 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:12:33 +0200 Subject: [PATCH 24/27] . --- src/aeso_ast_to_fcode.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index f2e50c8..6818bfb 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -661,9 +661,9 @@ expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> Init = {tuple, [nil, expr_to_fcode(Env, B)]}, Loop = {loop, Init, St, make_if( - {op, '=<', [ItProj, {var, AV}]}, + {op, '>=', [ItProj, {var, AV}]}, {continue, {tuple, [{op, '::', [ItProj, AcProj]}, - {op, '+', [ItProj, {lit, {int, 1}}]} + {op, '-', [ItProj, {lit, {int, 1}}]} ]}}, {break, AcProj} )}, -- 2.30.2 From 89afa9ec8f0bdc8565a26e4d2524fe4d5431b189 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:13:02 +0200 Subject: [PATCH 25/27] . --- src/aeso_ast_to_fcode.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 6818bfb..85f1bd2 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -654,7 +654,7 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> nil, Es); expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> AV = fresh_name(), % var to keep B - WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, B), X} end, + WithA = fun(X) -> {'let', AV, expr_to_fcode(Env, A), X} end, St = fresh_name(), % loop state ItProj = {proj, {var, St}, 1}, AcProj = {proj, {var, St}, 0}, -- 2.30.2 From 0bc9cfb957c044e9de68ace39cf294fad78b3ee1 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:17:02 +0200 Subject: [PATCH 26/27] Readd tests --- src/aeso_fcode_to_fate.erl | 1 + test/aeso_compiler_tests.erl | 69 +++++++++++++++++++++++++++++++++++- test/contracts/test.aes | 11 ++++-- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 37788fe..9a4c5cb 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -19,6 +19,7 @@ -type scode() :: [sinstr()]. -type sinstr() :: {switch, arg(), stype(), [maybe_scode()], maybe_scode()} %% last arg is catch-all + | {loop, scode(), var(), scode(), reference(), reference()} | switch_body | loop | tuple() | atom(). %% FATE instruction diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index 379daad..fe53c95 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -140,7 +140,74 @@ compile(Name, Options) -> %% The currently compilable contracts. compilable_contracts() -> - [ + ["complex_types", + "counter", + "dutch_auction", + "environment", + "factorial", + "functions", + "fundme", + "identity", + "maps", + "oracles", + "remote_call", + "remote_call_ambiguous_record", + "simple", + "simple_storage", + "spend_test", + "stack", + "test", + "builtin_bug", + "builtin_map_get_bug", + "lc_record_bug", + "nodeadcode", + "deadcode", + "variant_types", + "state_handling", + "events", + "include", + "basic_auth", + "basic_auth_tx", + "bitcoin_auth", + "address_literals", + "bytes_equality", + "address_chain", + "namespace_bug", + "bytes_to_x", + "bytes_concat", + "aens", + "aens_update", + "tuple_match", + "cyclic_include", + "stdlib_include", + "double_include", + "manual_stdlib_include", + "list_comp", + "payable", + "unapplied_builtins", + "underscore_number_literals", + "pairing_crypto", + "qualified_constructor", + "let_patterns", + "lhs_matching", + "more_strings", + "protected_call", + "hermetization_turnoff", + "multiple_contracts", + "clone", + "clone_simple", + "create", + "child_contract_init_bug", + "using_namespace", + "assign_patterns", + "patterns_guards", + "pipe_operator", + "polymorphism_contract_implements_interface", + "polymorphism_contract_multi_interface", + "polymorphism_contract_interface_extends_interface", + "polymorphism_contract_interface_extensions", + "polymorphism_contract_interface_same_decl_multi_interface", + "polymorphism_contract_interface_same_name_same_type", "test" % Custom general-purpose test file. Keep it last on the list. ]. diff --git a/test/contracts/test.aes b/test/contracts/test.aes index 5a90d06..d978179 100644 --- a/test/contracts/test.aes +++ b/test/contracts/test.aes @@ -1,5 +1,12 @@ // This is a custom test file if you need to run a compiler without // changing aeso_compiler_tests.erl -contract C = - entrypoint test() = [1..5] \ No newline at end of file +include "List.aes" + +contract IntegerHolder = + type state = int + entrypoint init(x) = x + entrypoint get() = state + +main contract Test = + stateful entrypoint f(c) = Chain.clone(ref=c, 123) -- 2.30.2 From 9335db65d0729d1de2e529197de1da0a033b9700 Mon Sep 17 00:00:00 2001 From: radrow Date: Sun, 3 Jul 2022 19:25:10 +0200 Subject: [PATCH 27/27] Fix liveness --- src/aeso_fcode_to_fate.erl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 9a4c5cb..99be7b7 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -819,9 +819,6 @@ ann_live(LiveTop, [I | Is], LiveOut) -> ann_live1(_LiveTop, switch_body, LiveOut) -> Ann = #{ live_in => LiveOut, live_out => LiveOut }, {{i, Ann, switch_body}, LiveOut}; -ann_live1(LiveTop, {jump, Ref}, _LiveOut) -> - Ann = #{ live_in => LiveTop, live_out => [] }, - {{i, Ann, {jump, Ref}}, LiveTop}; ann_live1(LiveTop, loop, _LiveOut) -> Ann = #{ live_in => LiveTop, live_out => [] }, {{i, Ann, loop}, LiveTop}; -- 2.30.2