From 0fa09467f62481ee92cd4ba424c993d49718717a Mon Sep 17 00:00:00 2001 From: Tobias Lindahl Date: Thu, 23 May 2019 14:01:41 +0200 Subject: [PATCH] Pt 166148534 refactor fate code (#71) * Change of module names aeb_fate_code -> aeb_fate_ops * Add missing call instructions * Use new adt for fate code * Add default init function if not present and keep init function if present * Fix BLOCKHASH function for fate * Rewrite for clarity and Dialyzer --- rebar.config | 2 +- rebar.lock | 2 +- src/aeso_fcode_to_fate.erl | 223 ++++++++++++++++++++----------------- 3 files changed, 125 insertions(+), 102 deletions(-) diff --git a/rebar.config b/rebar.config index 6099820..3c86310 100644 --- a/rebar.config +++ b/rebar.config @@ -3,7 +3,7 @@ {erl_opts, [debug_info]}. {deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", - {ref, "2f4e188"}}} + {ref, "11a8997"}}} , {getopt, "1.0.1"} , {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}} diff --git a/rebar.lock b/rebar.lock index 1ca177e..e4aaaaa 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,7 +1,7 @@ {"1.1.0", [{<<"aebytecode">>, {git,"https://github.com/aeternity/aebytecode.git", - {ref,"2f4e1888c241a7347ffec855ab6761c2c2972f37"}}, + {ref,"11a8997ac7ab2fc77948e6ab8ad22801640bcece"}}, 0}, {<<"aeserialization">>, {git,"https://github.com/aeternity/aeserialization.git", diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 777b3f2..4d8a31b 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -18,7 +18,7 @@ | switch_body | tuple(). %% FATE instruction --type arg() :: tuple(). %% Not exported: aeb_fate_code:fate_arg(). +-type arg() :: tuple(). %% Not exported: aeb_fate_ops:fate_arg(). %% Annotated scode -type scode_a() :: [sinstr_a()]. @@ -107,17 +107,18 @@ debug(Tag, Options, Fmt, Args) -> %% @doc Main entry point. compile(FCode, Options) -> #{ contract_name := ContractName, - state_type := _StateType, + state_type := StateType, functions := Functions } = FCode, SFuns = functions_to_scode(ContractName, Functions, Options), SFuns1 = optimize_scode(SFuns, Options), - BBFuns = to_basic_blocks(SFuns1, Options), - FateCode = #{ functions => BBFuns, - symbols => #{}, - annotations => #{} }, + SFuns2 = add_default_init_function(SFuns1, StateType), + FateCode = to_basic_blocks(SFuns2), debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), FateCode. +make_function_id(X) -> + aeb_fate_code:symbol_identifier(make_function_name(X)). + make_function_name(init) -> <<"init">>; make_function_name({entrypoint, Name}) -> Name; make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")). @@ -128,8 +129,7 @@ functions_to_scode(ContractName, Functions, Options) -> [ {make_function_name(Name), function_to_scode(ContractName, FunNames, Name, Args, Body, Type, Options)} || {Name, #{args := Args, body := Body, - return := Type}} <- maps:to_list(Functions), - Name /= init ]). %% TODO: skip init for now + return := Type}} <- maps:to_list(Functions)]). function_to_scode(ContractName, Functions, _Name, Args, Body, ResType, _Options) -> ArgTypes = [ type_to_scode(T) || {_, T} <- Args ], @@ -143,6 +143,21 @@ type_to_scode({map, Key, Val}) -> {map, type_to_scode(Key), type_to_scode(Val)}; type_to_scode({function, _Args, _Res}) -> {tuple, [string, any]}; type_to_scode(T) -> T. +add_default_init_function(SFuns, StateType) when StateType /= {tuple, []} -> + %% Only add default if the type is unit. + SFuns; +add_default_init_function(SFuns, {tuple, []}) -> + %% Only add default if the init function is not present + InitName = make_function_name(init), + case maps:find(InitName, SFuns) of + {ok, _} -> + SFuns; + error -> + Sig = {[], {tuple, []}}, + Body = [aeb_fate_ops:tuple(0)], + SFuns#{ InitName => {Sig, Body} } + end. + %% -- Phase I ---------------------------------------------------------------- %% Icode to structured assembly @@ -188,7 +203,7 @@ to_scode(_Env, {lit, L}) -> end; to_scode(_Env, nil) -> - [aeb_fate_code:nil(?a)]; + [aeb_fate_ops:nil(?a)]; to_scode(Env, {var, X}) -> [push(lookup_var(Env, X))]; @@ -196,21 +211,21 @@ to_scode(Env, {var, X}) -> to_scode(Env, {con, Ar, I, As}) -> N = length(As), [[to_scode(notail(Env), A) || A <- As], - aeb_fate_code:variant(?a, ?i(Ar), ?i(I), ?i(N))]; + aeb_fate_ops:variant(?a, ?i(Ar), ?i(I), ?i(N))]; to_scode(Env, {tuple, As}) -> N = length(As), [[ to_scode(notail(Env), A) || A <- As ], - aeb_fate_code:tuple(N)]; + aeb_fate_ops:tuple(N)]; to_scode(Env, {proj, E, I}) -> [to_scode(notail(Env), E), - aeb_fate_code:element_op(?a, ?i(I), ?a)]; + aeb_fate_ops:element_op(?a, ?i(I), ?a)]; to_scode(Env, {set_proj, R, I, E}) -> [to_scode(notail(Env), E), to_scode(notail(Env), R), - aeb_fate_code:setelement(?a, ?i(I), ?a, ?a)]; + aeb_fate_ops:setelement(?a, ?i(I), ?a, ?a)]; to_scode(Env, {op, Op, Args}) -> call_to_scode(Env, op_to_scode(Op), Args); @@ -221,11 +236,11 @@ to_scode(Env, {'let', X, {var, Y}, Body}) -> to_scode(Env, {'let', X, Expr, Body}) -> {I, Env1} = bind_local(X, Env), [ to_scode(notail(Env), Expr), - aeb_fate_code:store({var, I}, {stack, 0}), + aeb_fate_ops:store({var, I}, {stack, 0}), to_scode(Env1, Body) ]; to_scode(Env, {def, Fun, Args}) -> - FName = make_function_name(Fun), + FName = make_function_id(Fun), Lbl = aeb_fate_data:make_string(FName), call_to_scode(Env, local_call(Env, ?i(Lbl)), Args); to_scode(Env, {funcall, Fun, Args}) -> @@ -236,28 +251,28 @@ to_scode(Env, {builtin, B, Args}) -> to_scode(Env, {remote, Ct, Fun, [{builtin, call_gas_left, _}, Value | Args]}) -> %% Gas is not limited. - Lbl = make_function_name(Fun), - Call = if Env#env.tailpos -> aeb_fate_code:call_tr(?a, Lbl, ?a); - true -> aeb_fate_code:call_r(?a, Lbl, ?a) + Lbl = make_function_id(Fun), + Call = if Env#env.tailpos -> aeb_fate_ops:call_tr(?a, Lbl, ?a); + true -> aeb_fate_ops:call_r(?a, Lbl, ?a) end, call_to_scode(Env, Call, [Ct, Value | Args]); to_scode(Env, {remote, Ct, Fun, [Gas, Value | Args]}) -> %% Gas is limited. - Lbl = make_function_name(Fun), - Call = if Env#env.tailpos -> aeb_fate_code:call_gtr(?a, Lbl, ?a, ?a); - true -> aeb_fate_code:call_gr(?a, Lbl, ?a, ?a) + Lbl = make_function_id(Fun), + Call = if Env#env.tailpos -> aeb_fate_ops:call_gtr(?a, Lbl, ?a, ?a); + true -> aeb_fate_ops:call_gr(?a, Lbl, ?a, ?a) end, call_to_scode(Env, Call, [Ct, Value, Gas | Args]); to_scode(Env, {closure, Fun, FVs}) -> - to_scode(Env, {tuple, [{lit, {string, make_function_name(Fun)}}, FVs]}); + to_scode(Env, {tuple, [{lit, {string, make_function_id(Fun)}}, FVs]}); to_scode(Env, {switch, Case}) -> split_to_scode(Env, Case). -local_call( Env, Fun) when Env#env.tailpos -> aeb_fate_code:call_t(Fun); -local_call(_Env, Fun) -> aeb_fate_code:call(Fun). +local_call( Env, Fun) when Env#env.tailpos -> aeb_fate_ops:call_t(Fun); +local_call(_Env, Fun) -> aeb_fate_ops:call(Fun). split_to_scode(Env, {nosplit, Expr}) -> [switch_body, to_scode(Env, Expr)]; @@ -295,13 +310,13 @@ split_to_scode(Env, {split, {list, _}, X, Alts}) -> [{'case', {'::', Y, Z}, S} | _] -> {I, Env1} = bind_local(Y, Env), {J, Env2} = bind_local(Z, Env1), - [aeb_fate_code:hd({var, I}, Arg), - aeb_fate_code:tl({var, J}, Arg), + [aeb_fate_ops:hd({var, I}, Arg), + aeb_fate_ops:tl({var, J}, Arg), split_to_scode(Env2, S)] end end, SAlts = [GetAlt('::'), GetAlt(nil)], - [aeb_fate_code:is_nil(?a, Arg), + [aeb_fate_ops:is_nil(?a, Arg), {switch, ?a, boolean, SAlts, Def}]; split_to_scode(Env, {split, Type, X, Alts}) when Type == integer; Type == string -> {Def, Alts1} = catchall_to_scode(Env, X, Alts), @@ -337,7 +352,7 @@ literal_split_to_scode(Env, Type, Arg, [{'case', Lit, Body} | Alts], Def) when T {int, N} -> N; {string, S} -> aeb_fate_data:make_string(S) end, - [aeb_fate_code:eq(?a, Arg, ?i(SLit)), + [aeb_fate_ops:eq(?a, Arg, ?i(SLit)), {switch, ?a, boolean, [False, True], Def}]. catchall_to_scode(Env, X, Alts) -> catchall_to_scode(Env, X, Alts, []). @@ -351,10 +366,10 @@ catchall_to_scode(_, _, [], Acc) -> {missing, lists:reverse(Acc)}. %% Tuple is in the accumulator. Arguments are the variable names. match_tuple(Env, Arg, Xs) -> - match_tuple(Env, 0, fun aeb_fate_code:element_op/3, Arg, Xs). + match_tuple(Env, 0, fun aeb_fate_ops:element_op/3, Arg, Xs). match_variant(Env, Arg, Xs) -> - Elem = fun(Dst, I, Val) -> aeb_fate_code:variant_element(Dst, Val, I) end, + Elem = fun(Dst, I, Val) -> aeb_fate_ops:variant_element(Dst, Val, I) end, match_tuple(Env, 0, Elem, Arg, Xs). match_tuple(Env, I, Elem, Arg, ["_" | Xs]) -> @@ -375,49 +390,49 @@ call_to_scode(Env, CallCode, Args) -> builtin_to_scode(_Env, get_state, []) -> [push(?s)]; builtin_to_scode(Env, set_state, [_] = Args) -> - call_to_scode(Env, [aeb_fate_code:store(?s, ?a), - aeb_fate_code:tuple(0)], Args); + call_to_scode(Env, [aeb_fate_ops:store(?s, ?a), + aeb_fate_ops:tuple(0)], Args); builtin_to_scode(_Env, event, [_] = _Args) -> ?TODO(fate_event_instruction); builtin_to_scode(_Env, map_empty, []) -> - [aeb_fate_code:map_empty(?a)]; + [aeb_fate_ops:map_empty(?a)]; builtin_to_scode(_Env, bits_none, []) -> - [aeb_fate_code:bits_none(?a)]; + [aeb_fate_ops:bits_none(?a)]; builtin_to_scode(_Env, bits_all, []) -> - [aeb_fate_code:bits_all(?a)]; + [aeb_fate_ops:bits_all(?a)]; builtin_to_scode(Env, abort, [_] = Args) -> - call_to_scode(Env, aeb_fate_code:abort(?a), Args); + call_to_scode(Env, aeb_fate_ops:abort(?a), Args); builtin_to_scode(Env, chain_spend, [_, _] = Args) -> - call_to_scode(Env, [aeb_fate_code:spend(?a, ?a), - aeb_fate_code:tuple(0)], Args); + call_to_scode(Env, [aeb_fate_ops:spend(?a, ?a), + aeb_fate_ops:tuple(0)], Args); builtin_to_scode(Env, chain_balance, [_] = Args) -> - call_to_scode(Env, aeb_fate_code:balance_other(?a, ?a), Args); + call_to_scode(Env, aeb_fate_ops:balance_other(?a, ?a), Args); builtin_to_scode(Env, chain_block_hash, [_] = Args) -> - call_to_scode(Env, aeb_fate_code:blockhash(?a, ?a), Args); + call_to_scode(Env, aeb_fate_ops:blockhash(?a, ?a), Args); builtin_to_scode(_Env, chain_coinbase, []) -> - [aeb_fate_code:beneficiary(?a)]; + [aeb_fate_ops:beneficiary(?a)]; builtin_to_scode(_Env, chain_timestamp, []) -> - [aeb_fate_code:timestamp(?a)]; + [aeb_fate_ops:timestamp(?a)]; builtin_to_scode(_Env, chain_block_height, []) -> - [aeb_fate_code:generation(?a)]; + [aeb_fate_ops:generation(?a)]; builtin_to_scode(_Env, chain_difficulty, []) -> - [aeb_fate_code:difficulty(?a)]; + [aeb_fate_ops:difficulty(?a)]; builtin_to_scode(_Env, chain_gas_limit, []) -> - [aeb_fate_code:gaslimit(?a)]; + [aeb_fate_ops:gaslimit(?a)]; builtin_to_scode(_Env, contract_balance, []) -> - [aeb_fate_code:balance(?a)]; + [aeb_fate_ops:balance(?a)]; builtin_to_scode(_Env, contract_address, []) -> - [aeb_fate_code:address(?a)]; + [aeb_fate_ops:address(?a)]; builtin_to_scode(_Env, call_origin, []) -> - [aeb_fate_code:origin(?a)]; + [aeb_fate_ops:origin(?a)]; builtin_to_scode(_Env, call_caller, []) -> - [aeb_fate_code:caller(?a)]; + [aeb_fate_ops:caller(?a)]; builtin_to_scode(_Env, call_value, []) -> - [aeb_fate_code:call_value(?a)]; + [aeb_fate_ops:call_value(?a)]; builtin_to_scode(_Env, call_gas_price, []) -> - [aeb_fate_code:gasprice(?a)]; + [aeb_fate_ops:gasprice(?a)]; builtin_to_scode(_Env, call_gas_left, []) -> - [aeb_fate_code:gas(?a)]; + [aeb_fate_ops:gas(?a)]; builtin_to_scode(_Env, oracle_register, [_, _, _, _] = _Args) -> ?TODO(fate_oracle_register_instruction); builtin_to_scode(_Env, oracle_query_fee, [_] = _Args) -> @@ -457,44 +472,44 @@ builtin_to_scode(_Env, auth_tx_hash, []) -> %% -- Operators -- -op_to_scode('+') -> aeb_fate_code:add(?a, ?a, ?a); -op_to_scode('-') -> aeb_fate_code:sub(?a, ?a, ?a); -op_to_scode('*') -> aeb_fate_code:mul(?a, ?a, ?a); -op_to_scode('/') -> aeb_fate_code:divide(?a, ?a, ?a); -op_to_scode(mod) -> aeb_fate_code:modulo(?a, ?a, ?a); -op_to_scode('^') -> aeb_fate_code:pow(?a, ?a, ?a); -op_to_scode('++') -> aeb_fate_code:append(?a, ?a, ?a); -op_to_scode('::') -> aeb_fate_code:cons(?a, ?a, ?a); -op_to_scode('<') -> aeb_fate_code:lt(?a, ?a, ?a); -op_to_scode('>') -> aeb_fate_code:gt(?a, ?a, ?a); -op_to_scode('=<') -> aeb_fate_code:elt(?a, ?a, ?a); -op_to_scode('>=') -> aeb_fate_code:egt(?a, ?a, ?a); -op_to_scode('==') -> aeb_fate_code:eq(?a, ?a, ?a); -op_to_scode('!=') -> aeb_fate_code:neq(?a, ?a, ?a); -op_to_scode('!') -> aeb_fate_code:not_op(?a, ?a); -op_to_scode(map_get) -> aeb_fate_code:map_lookup(?a, ?a, ?a); -op_to_scode(map_get_d) -> aeb_fate_code:map_lookup(?a, ?a, ?a, ?a); -op_to_scode(map_set) -> aeb_fate_code:map_update(?a, ?a, ?a, ?a); -op_to_scode(map_from_list) -> aeb_fate_code:map_from_list(?a, ?a); +op_to_scode('+') -> aeb_fate_ops:add(?a, ?a, ?a); +op_to_scode('-') -> aeb_fate_ops:sub(?a, ?a, ?a); +op_to_scode('*') -> aeb_fate_ops:mul(?a, ?a, ?a); +op_to_scode('/') -> aeb_fate_ops:divide(?a, ?a, ?a); +op_to_scode(mod) -> aeb_fate_ops:modulo(?a, ?a, ?a); +op_to_scode('^') -> aeb_fate_ops:pow(?a, ?a, ?a); +op_to_scode('++') -> aeb_fate_ops:append(?a, ?a, ?a); +op_to_scode('::') -> aeb_fate_ops:cons(?a, ?a, ?a); +op_to_scode('<') -> aeb_fate_ops:lt(?a, ?a, ?a); +op_to_scode('>') -> aeb_fate_ops:gt(?a, ?a, ?a); +op_to_scode('=<') -> aeb_fate_ops:elt(?a, ?a, ?a); +op_to_scode('>=') -> aeb_fate_ops:egt(?a, ?a, ?a); +op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a); +op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a); +op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a); +op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a); +op_to_scode(map_get_d) -> aeb_fate_ops:map_lookup(?a, ?a, ?a, ?a); +op_to_scode(map_set) -> aeb_fate_ops:map_update(?a, ?a, ?a, ?a); +op_to_scode(map_from_list) -> aeb_fate_ops:map_from_list(?a, ?a); op_to_scode(map_to_list) -> ?TODO(fate_map_to_list_instruction); -op_to_scode(map_delete) -> aeb_fate_code:map_delete(?a, ?a, ?a); -op_to_scode(map_member) -> aeb_fate_code:map_member(?a, ?a, ?a); +op_to_scode(map_delete) -> aeb_fate_ops:map_delete(?a, ?a, ?a); +op_to_scode(map_member) -> aeb_fate_ops:map_member(?a, ?a, ?a); op_to_scode(map_size) -> ?TODO(fate_map_size_instruction); op_to_scode(string_length) -> ?TODO(fate_string_length_instruction); -op_to_scode(string_concat) -> aeb_fate_code:str_join(?a, ?a, ?a); -op_to_scode(bits_set) -> aeb_fate_code:bits_set(?a, ?a, ?a); -op_to_scode(bits_clear) -> aeb_fate_code:bits_clear(?a, ?a, ?a); -op_to_scode(bits_test) -> aeb_fate_code:bits_test(?a, ?a, ?a); -op_to_scode(bits_sum) -> aeb_fate_code:bits_sum(?a, ?a); -op_to_scode(bits_intersection) -> aeb_fate_code:bits_and(?a, ?a, ?a); -op_to_scode(bits_union) -> aeb_fate_code:bits_or(?a, ?a, ?a); -op_to_scode(bits_difference) -> aeb_fate_code:bits_diff(?a, ?a, ?a); -op_to_scode(address_to_str) -> aeb_fate_code:addr_to_str(?a, ?a); -op_to_scode(int_to_str) -> aeb_fate_code:int_to_str(?a, ?a). +op_to_scode(string_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a); +op_to_scode(bits_set) -> aeb_fate_ops:bits_set(?a, ?a, ?a); +op_to_scode(bits_clear) -> aeb_fate_ops:bits_clear(?a, ?a, ?a); +op_to_scode(bits_test) -> aeb_fate_ops:bits_test(?a, ?a, ?a); +op_to_scode(bits_sum) -> aeb_fate_ops:bits_sum(?a, ?a); +op_to_scode(bits_intersection) -> aeb_fate_ops:bits_and(?a, ?a, ?a); +op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a); +op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a); +op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a); +op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a). %% PUSH and STORE ?a are the same, so we use STORE to make optimizations %% easier, and specialize to PUSH (which is cheaper) at the end. -push(A) -> aeb_fate_code:store(?a, A). +push(A) -> aeb_fate_ops:store(?a, A). %% -- Phase II --------------------------------------------------------------- %% Optimize @@ -708,7 +723,7 @@ attributes(I) -> {'ORIGIN', A} -> Pure(A, []); {'CALLER', A} -> Pure(A, []); {'GASPRICE', A} -> Pure(A, []); - {'BLOCKHASH', A} -> Pure(A, []); + {'BLOCKHASH', A, B} -> Impure(A, [B]); {'BENEFICIARY', A} -> Pure(A, []); {'TIMESTAMP', A} -> Pure(A, []); {'GENERATION', A} -> Pure(A, []); @@ -1150,9 +1165,9 @@ unannotate(Code) when is_list(Code) -> unannotate({i, _Ann, I}) -> [I]. %% Desugar and specialize -desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_code:inc()]; -desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_code:dec()]; -desugar({'STORE', ?a, A}) -> [aeb_fate_code:push(A)]; +desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_ops:inc()]; +desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:dec()]; +desugar({'STORE', ?a, A}) -> [aeb_fate_ops:push(A)]; desugar({switch, Arg, Type, Alts, Def}) -> [{switch, Arg, Type, [desugar(A) || A <- Alts], desugar(Def)}]; desugar(missing) -> missing; @@ -1163,12 +1178,16 @@ desugar(I) -> [I]. %% -- Phase III -------------------------------------------------------------- %% Constructing basic blocks -to_basic_blocks(Funs, Options) -> - maps:from_list([ {Name, {{Args, Res}, - bb(Name, Code ++ [aeb_fate_code:return()], Options)}} - || {Name, {{Args, Res}, Code}} <- maps:to_list(Funs) ]). +to_basic_blocks(Funs) -> + to_basic_blocks(maps:to_list(Funs), aeb_fate_code:new()). -bb(_Name, Code, _Options) -> +to_basic_blocks([{Name, {Sig, Code}}|Left], Acc) -> + BB = bb(Name, Code ++ [aeb_fate_ops:return()]), + to_basic_blocks(Left, aeb_fate_code:insert_fun(Name, Sig, BB, Acc)); +to_basic_blocks([], Acc) -> + Acc. + +bb(_Name, Code) -> Blocks0 = blocks(Code), Blocks1 = optimize_blocks(Blocks0), Blocks = lists:flatmap(fun split_calls/1, Blocks1), @@ -1219,7 +1238,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code], {DefRef, DefBlk} = case Default of missing when Catchall == none -> - FreshBlk([aeb_fate_code:abort(?i(<<"Incomplete patterns">>))], none); + FreshBlk([aeb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none); missing -> {Catchall, []}; _ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall) %% ^ fall-through to the outer catchall @@ -1335,6 +1354,8 @@ chase_labels([L | Ls], Map, Live) -> tweak_returns(['RETURN', {'PUSH', A} | Code]) -> [{'RETURNR', A} | Code]; tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'CALL_TR', _, _} | _]]) -> Code; +tweak_returns(['RETURN' | Code = [{'CALL_GT', _} | _]]) -> Code; +tweak_returns(['RETURN' | Code = [{'CALL_GTR', _, _} | _]])-> Code; tweak_returns(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code; tweak_returns(Code) -> Code. @@ -1346,7 +1367,9 @@ 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'; element(1, I) == 'CALL_R' -> +split_calls(Ref, [I | Code], Acc, Blocks) when element(1, I) == 'CALL'; + element(1, I) == 'CALL_R'; + element(1, I) == 'CALL_GR' -> split_calls(make_ref(), Code, [], [{Ref, lists:reverse([I | Acc])} | Blocks]); split_calls(Ref, [I | Code], Acc, Blocks) -> split_calls(Ref, Code, [I | Acc], Blocks). @@ -1355,13 +1378,13 @@ split_calls(Ref, [I | Code], Acc, Blocks) -> set_labels(Labels, {Ref, Code}) when is_reference(Ref) -> {maps:get(Ref, Labels), [ set_labels(Labels, I) || I <- Code ]}; -set_labels(Labels, {jump, Ref}) -> aeb_fate_code:jump(maps:get(Ref, Labels)); -set_labels(Labels, {jumpif, Arg, Ref}) -> aeb_fate_code:jumpif(Arg, maps:get(Ref, Labels)); +set_labels(Labels, {jump, Ref}) -> aeb_fate_ops:jump(maps:get(Ref, Labels)); +set_labels(Labels, {jumpif, Arg, Ref}) -> aeb_fate_ops:jumpif(Arg, maps:get(Ref, Labels)); set_labels(Labels, {switch, Arg, Refs}) -> case [ maps:get(Ref, Labels) || Ref <- Refs ] of - [R1, R2] -> aeb_fate_code:switch(Arg, R1, R2); - [R1, R2, R3] -> aeb_fate_code:switch(Arg, R1, R2, R3); - Rs -> aeb_fate_code:switch(Arg, Rs) + [R1, R2] -> aeb_fate_ops:switch(Arg, R1, R2); + [R1, R2, R3] -> aeb_fate_ops:switch(Arg, R1, R2, R3); + Rs -> aeb_fate_ops:switch(Arg, Rs) end; set_labels(_, I) -> I.