Add loop operator in fcode

This commit is contained in:
radrow 2022-07-02 21:53:42 +02:00
parent 7b8957b46a
commit 62a0ff2e4c
4 changed files with 98 additions and 92 deletions

View File

@ -75,6 +75,7 @@
| {switch, fsplit()} | {switch, fsplit()}
| {set_state, state_reg(), fexpr()} | {set_state, state_reg(), fexpr()}
| {get_state, state_reg()} | {get_state, state_reg()}
| {loop, fexpr(), var_name(), fexpr()} | {continue, fexpr()} | {break, fexpr()}
%% The following (unapplied top-level functions/builtins and %% The following (unapplied top-level functions/builtins and
%% lambdas) are generated by the fcode compiler, but translated %% lambdas) are generated by the fcode compiler, but translated
%% to closures by the lambda lifter. %% to closures by the lambda lifter.
@ -653,9 +654,20 @@ expr_to_fcode(Env, _Type, {list, _, Es}) ->
nil, Es); nil, Es);
expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) ->
{def_u, FromTo, _} = resolve_fun(Env, ["ListInternal", "from_to"]), AV = fresh_name(),
{def, FromTo, [expr_to_fcode(Env, A), expr_to_fcode(Env, B)]}; 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, []}) -> expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) ->
{op, '::', [expr_to_fcode(Env, Yield), nil]}; {op, '::', [expr_to_fcode(Env, Yield), nil]};
expr_to_fcode(Env, _Type, {list_comp, As, Yield, [{comprehension_bind, Pat = {typed, _, _, PatType}, BindExpr}|Rest]}) -> 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}; {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)}; {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)}; {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)}; {'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)}; {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)}; {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({split, _, _, Cases}) -> read_only(Cases);
read_only({nosplit, E}) -> read_only(E); read_only({nosplit, E}) -> read_only(E);
read_only({'case', _, Split}) -> read_only(Split); 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({'let', _, A, B}) -> read_only([A, B]);
read_only({funcall, _, _}) -> false; read_only({funcall, _, _}) -> false;
read_only({closure, _, _}) -> internal_error(no_closures_here); read_only({closure, _, _}) -> internal_error(no_closures_here);
@ -1850,6 +1868,9 @@ free_vars(Expr) ->
{proj, A, _} -> free_vars(A); {proj, A, _} -> free_vars(A);
{set_proj, A, _, B} -> free_vars([A, B]); {set_proj, A, _, B} -> free_vars([A, B]);
{op, _, As} -> free_vars(As); {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}]); {'let', X, A, B} -> free_vars([A, {lam, [X], B}]);
{funcall, A, Bs} -> free_vars([A | Bs]); {funcall, A, Bs} -> free_vars([A | Bs]);
{set_state, _, A} -> free_vars(A); {set_state, _, A} -> free_vars(A);
@ -1881,6 +1902,9 @@ used_defs(Expr) ->
{proj, A, _} -> used_defs(A); {proj, A, _} -> used_defs(A);
{set_proj, A, _, B} -> used_defs([A, B]); {set_proj, A, _, B} -> used_defs([A, B]);
{op, _, As} -> used_defs(As); {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]); {'let', _, A, B} -> used_defs([A, B]);
{funcall, A, Bs} -> used_defs([A | Bs]); {funcall, A, Bs} -> used_defs([A | Bs]);
{set_state, _, A} -> used_defs(A); {set_state, _, A} -> used_defs(A);
@ -1917,6 +1941,9 @@ bottom_up(F, Env, Expr) ->
{get_state, _} -> Expr; {get_state, _} -> Expr;
{closure, F, CEnv} -> {closure, F, bottom_up(F, Env, CEnv)}; {closure, F, CEnv} -> {closure, F, bottom_up(F, Env, CEnv)};
{switch, Split} -> {switch, bottom_up(F, Env, Split)}; {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)}; {lam, Xs, B} -> {lam, Xs, bottom_up(F, Env, B)};
{'let', X, E, Body} -> {'let', X, E, Body} ->
E1 = bottom_up(F, Env, E), E1 = bottom_up(F, Env, E),
@ -1978,6 +2005,11 @@ rename(Ren, Expr) ->
{lam, Xs, B} -> {lam, Xs, B} ->
{Zs, Ren1} = rename_bindings(Ren, Xs), {Zs, Ren1} = rename_bindings(Ren, Xs),
{lam, Zs, rename(Ren1, B)}; {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} -> {'let', X, E, Body} ->
{Z, Ren1} = rename_binding(Ren, X), {Z, Ren1} = rename_binding(Ren, X),
{'let', Z, rename(Ren, E), rename(Ren1, Body)} {'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_parens(pp_par(pp_punctuate(pp_text(","), [pp_fexpr(E) || E <- Es])));
pp_fexpr({proj, E, I}) -> pp_fexpr({proj, E, I}) ->
pp_beside([pp_fexpr(E), pp_text("."), pp_int(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_fexpr({lam, Xs, A}) ->
pp_par([pp_fexpr({tuple, [{var, X} || X <- Xs]}), pp_text("=>"), pp_par([pp_fexpr({tuple, [{var, X} || X <- Xs]}), pp_text("=>"),
prettypr:nest(2, pp_fexpr(A))]); prettypr:nest(2, pp_fexpr(A))]);

View File

@ -45,7 +45,7 @@
-define(s(N), {store, N}). -define(s(N), {store, N}).
-define(void, {var, 9999}). -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 -------------------------------------------------------------- %% -- Debugging --------------------------------------------------------------
@ -77,6 +77,7 @@ compile(ChildContracts, FCode, Options) ->
SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options), SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options),
SFuns1 = optimize_scode(SFuns, Options), SFuns1 = optimize_scode(SFuns, Options),
FateCode = to_basic_blocks(SFuns1), FateCode = to_basic_blocks(SFuns1),
io:format("FINAL:\~p\n\n", [FateCode]),
?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]),
FateCode. FateCode.
@ -159,6 +160,9 @@ init_env(ChildContracts, ContractName, FunNames, Name, Args, Options) ->
next_var(#env{ vars = Vars }) -> next_var(#env{ vars = Vars }) ->
1 + lists:max([-1 | [J || {_, {var, J}} <- 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 }) -> bind_var(Name, Var, Env = #env{ vars = Vars }) ->
Env#env{ vars = [{Name, Var} | 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_scode1(Env, {closure, Fun, FVs}) ->
to_scode(Env, {tuple, [{lit, {string, make_function_id(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}) -> to_scode1(Env, {switch, Case}) ->
split_to_scode(Env, 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}) -> flatten_s({switch, Arg, Type, Alts, Catch}) ->
{switch, Arg, Type, [flatten(Alt) || Alt <- Alts], flatten(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. flatten_s(I) -> I.
-define(MAX_SIMPL_ITERATIONS, 10). -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), {Def1, LiveDef} = ann_live(LiveTop, Def, LiveOut),
LiveIn = ordsets:union([Read, LiveDef | LiveAlts]), LiveIn = ordsets:union([Read, LiveDef | LiveAlts]),
{{switch, Arg, Type, Alts1, Def1}, LiveIn}; {{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) -> ann_live1(_LiveTop, I, LiveOut) ->
#{ read := Reads0, write := W } = attributes(I), #{ read := Reads0, write := W } = attributes(I),
Reads = lists:filter(fun is_reg/1, Reads0), Reads = lists:filter(fun is_reg/1, Reads0),
@ -843,7 +866,9 @@ attributes(I) ->
{'CALL_T', A} -> Impure(pc, [A]); {'CALL_T', A} -> Impure(pc, [A]);
{'CALL_VALUE', A} -> Pure(A, []); {'CALL_VALUE', A} -> Pure(A, []);
{'JUMP', _} -> Impure(pc, []); {'JUMP', _} -> Impure(pc, []);
{jump, _} -> Impure(pc, []);
{'JUMPIF', A, _} -> Impure(pc, A); {'JUMPIF', A, _} -> Impure(pc, A);
{jumpif, A, _} -> Impure(pc, A);
{'SWITCH_V2', A, _, _} -> Impure(pc, A); {'SWITCH_V2', A, _, _} -> Impure(pc, A);
{'SWITCH_V3', A, _, _, _} -> Impure(pc, A); {'SWITCH_V3', A, _, _, _} -> Impure(pc, A);
{'SWITCH_VN', A, _} -> Impure(pc, A); {'SWITCH_VN', A, _} -> Impure(pc, A);
@ -1023,6 +1048,7 @@ var_writes(I) ->
-spec independent(sinstr_a(), sinstr_a()) -> boolean(). -spec independent(sinstr_a(), sinstr_a()) -> boolean().
%% independent({switch, _, _, _, _}, _) -> false; %% Commented due to Dialyzer whinging %% independent({switch, _, _, _, _}, _) -> false; %% Commented due to Dialyzer whinging
independent(_, {switch, _, _, _, _}) -> false; independent(_, {switch, _, _, _, _}) -> false;
independent(_, {loop, _, _, _, _, _}) -> false;
independent({i, _, I}, {i, _, J}) -> independent({i, _, I}, {i, _, J}) ->
#{ write := WI, read := RI, pure := PureI } = attributes(I), #{ write := WI, read := RI, pure := PureI } = attributes(I),
#{ write := WJ, read := RJ, pure := PureJ } = attributes(J), #{ 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. (missing) -> missing.
unannotate({switch, Arg, Type, Alts, Def}) -> unannotate({switch, Arg, Type, Alts, Def}) ->
[{switch, Arg, Type, [unannotate(A) || A <- Alts], unannotate(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(missing) -> missing;
unannotate(Code) when is_list(Code) -> unannotate(Code) when is_list(Code) ->
lists:flatmap(fun unannotate/1, Code); lists:flatmap(fun unannotate/1, Code);
@ -1547,6 +1575,7 @@ to_basic_blocks([], Acc) ->
Acc. Acc.
bb(_Name, Code) -> bb(_Name, Code) ->
io:format("FUN: ~p\nCODE:\n~p\n\n", [_Name, Code]),
Blocks0 = blocks(Code), Blocks0 = blocks(Code),
Blocks1 = optimize_blocks(Blocks0), Blocks1 = optimize_blocks(Blocks0),
Blocks = lists:flatmap(fun split_calls/1, Blocks1), Blocks = lists:flatmap(fun split_calls/1, Blocks1),
@ -1567,7 +1596,7 @@ bb(_Name, Code) ->
-type bb() :: {bbref(), bcode()}. -type bb() :: {bbref(), bcode()}.
-type bcode() :: [binstr()]. -type bcode() :: [binstr()].
-type binstr() :: {jump, bbref()} -type binstr() :: {jump, bbref()}
| {jumpif, bbref()} | {jumpif, term(), bbref()}
| tuple(). %% FATE instruction | tuple(). %% FATE instruction
-spec blocks(scode()) -> [bb()]. -spec blocks(scode()) -> [bb()].
@ -1581,27 +1610,37 @@ blocks([], Acc) ->
blocks([Blk | Blocks], Acc) -> blocks([Blk | Blocks], Acc) ->
block(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()]. -spec block(#blk{}, bcode(), [#blk{}], [bb()]) -> [bb()].
block(#blk{ref = Ref, code = []}, CodeAcc, Blocks, BlockAcc) -> block(#blk{ref = Ref, code = []}, CodeAcc, Blocks, BlockAcc) ->
blocks(Blocks, [{Ref, lists:reverse(CodeAcc)} | 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) -> block(Blk = #blk{code = [switch_body | Code]}, Acc, Blocks, BlockAcc) ->
%% Reached the body of a switch. Clear catchall ref. %% Reached the body of a switch. Clear catchall ref.
block(Blk#blk{code = Code, catchall = none}, Acc, Blocks, BlockAcc); block(Blk#blk{code = Code, catchall = none}, Acc, Blocks, BlockAcc);
block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code], block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code],
catchall = Catchall}, Acc, Blocks, BlockAcc) -> catchall = Catchall}, Acc, Blocks, BlockAcc) ->
FreshBlk = fun(C, Ca) -> {RestRef, RestBlk} = fresh_block(Code, Catchall),
R = make_ref(),
{R, [#blk{ref = R, code = C, catchall = Ca}]}
end,
{RestRef, RestBlk} = FreshBlk(Code, Catchall),
{DefRef, DefBlk} = {DefRef, DefBlk} =
case Default of case Default of
missing when Catchall == none -> 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, []}; missing -> {Catchall, []};
_ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall) _ -> fresh_block(Default ++ [{jump, RestRef}], Catchall)
%% ^ fall-through to the outer catchall %% ^ fall-through to the outer catchall
end, 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. %% If we don't generate a switch, we need to pop the argument if on the stack.
Pop = [{'POP', ?void} || Arg == ?a], Pop = [{'POP', ?void} || Arg == ?a],
{Blk1, Code1, AltBlks} = {Blk1, Code1, AltBlks} =
@ -1611,7 +1650,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code],
{ThenRef, ThenBlk} = {ThenRef, ThenBlk} =
case TrueCode of case TrueCode of
missing -> {DefRef, []}; missing -> {DefRef, []};
_ -> FreshBlk(TrueCode ++ [{jump, RestRef}], DefRef) _ -> fresh_block(TrueCode ++ [{jump, RestRef}], DefRef)
end, end,
ElseCode = ElseCode =
case FalseCode of case FalseCode of
@ -1646,7 +1685,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code],
true -> {Blk#blk{code = Pop ++ [{jump, DefRef}]}, [], []}; true -> {Blk#blk{code = Pop ++ [{jump, DefRef}]}, [], []};
false -> false ->
MkBlk = fun(missing) -> {DefRef, []}; MkBlk = fun(missing) -> {DefRef, []};
(ACode) -> FreshBlk(ACode ++ [{jump, RestRef}], DefRef) (ACode) -> fresh_block(ACode ++ [{jump, RestRef}], DefRef)
end, end,
{AltRefs, AltBs} = lists:unzip(lists:map(MkBlk, Alts)), {AltRefs, AltBs} = lists:unzip(lists:map(MkBlk, Alts)),
{Blk#blk{code = []}, [{switch, Arg, AltRefs}], lists:append(AltBs)} {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, Rev = fun(Bs) -> [ {Ref, lists:reverse(Code)} || {Ref, Code} <- Bs ] end,
RBlocks = Rev(Blocks), RBlocks = Rev(Blocks),
RBlockMap = maps:from_list(RBlocks), RBlockMap = maps:from_list(RBlocks),
io:format("REORDERING ~p\n\n", [RBlocks]),
RBlocks1 = reorder_blocks(RBlocks, []), RBlocks1 = reorder_blocks(RBlocks, []),
RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ], RBlocks2 = [ {Ref, inline_block(RBlockMap, Ref, Code)} || {Ref, Code} <- RBlocks1 ],
RBlocks3 = shortcut_jump_chains(RBlocks2), RBlocks3 = shortcut_jump_chains(RBlocks2),
@ -1686,6 +1726,7 @@ reorder_blocks(Ref, Code, Blocks, Acc) ->
[{'EXIT', _}|_] -> reorder_blocks(Blocks, Acc1); [{'EXIT', _}|_] -> reorder_blocks(Blocks, Acc1);
[{'ABORT', _}|_] -> reorder_blocks(Blocks, Acc1); [{'ABORT', _}|_] -> reorder_blocks(Blocks, Acc1);
[{switch, _, _}|_] -> reorder_blocks(Blocks, Acc1); [{switch, _, _}|_] -> reorder_blocks(Blocks, Acc1);
[{jumpif, _, _}|_] -> reorder_blocks(Blocks, Acc1);
[{jump, L}|_] -> [{jump, L}|_] ->
NotL = fun({L1, _}) -> L1 /= L end, NotL = fun({L1, _}) -> L1 /= L end,
case lists:splitwith(NotL, Blocks) of case lists:splitwith(NotL, Blocks) of

View File

@ -140,74 +140,7 @@ compile(Name, Options) ->
%% The currently compilable contracts. %% The currently compilable contracts.
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. "test" % Custom general-purpose test file. Keep it last on the list.
]. ].

View File

@ -1,12 +1,5 @@
// This is a custom test file if you need to run a compiler without // This is a custom test file if you need to run a compiler without
// changing aeso_compiler_tests.erl // changing aeso_compiler_tests.erl
include "List.aes" contract C =
entrypoint test() = [1..5]
contract IntegerHolder =
type state = int
entrypoint init(x) = x
entrypoint get() = state
main contract Test =
stateful entrypoint f(c) = Chain.clone(ref=c, 123)