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
This commit is contained in:
parent
dcae96ed21
commit
0fa09467f6
@ -3,7 +3,7 @@
|
|||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git",
|
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git",
|
||||||
{ref, "2f4e188"}}}
|
{ref, "11a8997"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
||||||
{tag, "2.8.0"}}}
|
{tag, "2.8.0"}}}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{"1.1.0",
|
{"1.1.0",
|
||||||
[{<<"aebytecode">>,
|
[{<<"aebytecode">>,
|
||||||
{git,"https://github.com/aeternity/aebytecode.git",
|
{git,"https://github.com/aeternity/aebytecode.git",
|
||||||
{ref,"2f4e1888c241a7347ffec855ab6761c2c2972f37"}},
|
{ref,"11a8997ac7ab2fc77948e6ab8ad22801640bcece"}},
|
||||||
0},
|
0},
|
||||||
{<<"aeserialization">>,
|
{<<"aeserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{git,"https://github.com/aeternity/aeserialization.git",
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
| switch_body
|
| switch_body
|
||||||
| tuple(). %% FATE instruction
|
| 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
|
%% Annotated scode
|
||||||
-type scode_a() :: [sinstr_a()].
|
-type scode_a() :: [sinstr_a()].
|
||||||
@ -107,17 +107,18 @@ debug(Tag, Options, Fmt, Args) ->
|
|||||||
%% @doc Main entry point.
|
%% @doc Main entry point.
|
||||||
compile(FCode, Options) ->
|
compile(FCode, Options) ->
|
||||||
#{ contract_name := ContractName,
|
#{ contract_name := ContractName,
|
||||||
state_type := _StateType,
|
state_type := StateType,
|
||||||
functions := Functions } = FCode,
|
functions := Functions } = FCode,
|
||||||
SFuns = functions_to_scode(ContractName, Functions, Options),
|
SFuns = functions_to_scode(ContractName, Functions, Options),
|
||||||
SFuns1 = optimize_scode(SFuns, Options),
|
SFuns1 = optimize_scode(SFuns, Options),
|
||||||
BBFuns = to_basic_blocks(SFuns1, Options),
|
SFuns2 = add_default_init_function(SFuns1, StateType),
|
||||||
FateCode = #{ functions => BBFuns,
|
FateCode = to_basic_blocks(SFuns2),
|
||||||
symbols => #{},
|
|
||||||
annotations => #{} },
|
|
||||||
debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]),
|
debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]),
|
||||||
FateCode.
|
FateCode.
|
||||||
|
|
||||||
|
make_function_id(X) ->
|
||||||
|
aeb_fate_code:symbol_identifier(make_function_name(X)).
|
||||||
|
|
||||||
make_function_name(init) -> <<"init">>;
|
make_function_name(init) -> <<"init">>;
|
||||||
make_function_name({entrypoint, Name}) -> Name;
|
make_function_name({entrypoint, Name}) -> Name;
|
||||||
make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")).
|
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)}
|
[ {make_function_name(Name), function_to_scode(ContractName, FunNames, Name, Args, Body, Type, Options)}
|
||||||
|| {Name, #{args := Args,
|
|| {Name, #{args := Args,
|
||||||
body := Body,
|
body := Body,
|
||||||
return := Type}} <- maps:to_list(Functions),
|
return := Type}} <- maps:to_list(Functions)]).
|
||||||
Name /= init ]). %% TODO: skip init for now
|
|
||||||
|
|
||||||
function_to_scode(ContractName, Functions, _Name, Args, Body, ResType, _Options) ->
|
function_to_scode(ContractName, Functions, _Name, Args, Body, ResType, _Options) ->
|
||||||
ArgTypes = [ type_to_scode(T) || {_, T} <- Args ],
|
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({function, _Args, _Res}) -> {tuple, [string, any]};
|
||||||
type_to_scode(T) -> T.
|
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 ----------------------------------------------------------------
|
%% -- Phase I ----------------------------------------------------------------
|
||||||
%% Icode to structured assembly
|
%% Icode to structured assembly
|
||||||
|
|
||||||
@ -188,7 +203,7 @@ to_scode(_Env, {lit, L}) ->
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
to_scode(_Env, nil) ->
|
to_scode(_Env, nil) ->
|
||||||
[aeb_fate_code:nil(?a)];
|
[aeb_fate_ops:nil(?a)];
|
||||||
|
|
||||||
to_scode(Env, {var, X}) ->
|
to_scode(Env, {var, X}) ->
|
||||||
[push(lookup_var(Env, X))];
|
[push(lookup_var(Env, X))];
|
||||||
@ -196,21 +211,21 @@ to_scode(Env, {var, X}) ->
|
|||||||
to_scode(Env, {con, Ar, I, As}) ->
|
to_scode(Env, {con, Ar, I, As}) ->
|
||||||
N = length(As),
|
N = length(As),
|
||||||
[[to_scode(notail(Env), A) || A <- 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}) ->
|
to_scode(Env, {tuple, As}) ->
|
||||||
N = length(As),
|
N = length(As),
|
||||||
[[ to_scode(notail(Env), A) || A <- 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(Env, {proj, E, I}) ->
|
||||||
[to_scode(notail(Env), E),
|
[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(Env, {set_proj, R, I, E}) ->
|
||||||
[to_scode(notail(Env), E),
|
[to_scode(notail(Env), E),
|
||||||
to_scode(notail(Env), R),
|
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}) ->
|
to_scode(Env, {op, Op, Args}) ->
|
||||||
call_to_scode(Env, op_to_scode(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}) ->
|
to_scode(Env, {'let', X, Expr, Body}) ->
|
||||||
{I, Env1} = bind_local(X, Env),
|
{I, Env1} = bind_local(X, Env),
|
||||||
[ to_scode(notail(Env), Expr),
|
[ 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(Env1, Body) ];
|
||||||
|
|
||||||
to_scode(Env, {def, Fun, Args}) ->
|
to_scode(Env, {def, Fun, Args}) ->
|
||||||
FName = make_function_name(Fun),
|
FName = make_function_id(Fun),
|
||||||
Lbl = aeb_fate_data:make_string(FName),
|
Lbl = aeb_fate_data:make_string(FName),
|
||||||
call_to_scode(Env, local_call(Env, ?i(Lbl)), Args);
|
call_to_scode(Env, local_call(Env, ?i(Lbl)), Args);
|
||||||
to_scode(Env, {funcall, Fun, 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]}) ->
|
to_scode(Env, {remote, Ct, Fun, [{builtin, call_gas_left, _}, Value | Args]}) ->
|
||||||
%% Gas is not limited.
|
%% Gas is not limited.
|
||||||
Lbl = make_function_name(Fun),
|
Lbl = make_function_id(Fun),
|
||||||
Call = if Env#env.tailpos -> aeb_fate_code:call_tr(?a, Lbl, ?a);
|
Call = if Env#env.tailpos -> aeb_fate_ops:call_tr(?a, Lbl, ?a);
|
||||||
true -> aeb_fate_code:call_r(?a, Lbl, ?a)
|
true -> aeb_fate_ops:call_r(?a, Lbl, ?a)
|
||||||
end,
|
end,
|
||||||
call_to_scode(Env, Call, [Ct, Value | Args]);
|
call_to_scode(Env, Call, [Ct, Value | Args]);
|
||||||
|
|
||||||
to_scode(Env, {remote, Ct, Fun, [Gas, Value | Args]}) ->
|
to_scode(Env, {remote, Ct, Fun, [Gas, Value | Args]}) ->
|
||||||
%% Gas is limited.
|
%% Gas is limited.
|
||||||
Lbl = make_function_name(Fun),
|
Lbl = make_function_id(Fun),
|
||||||
Call = if Env#env.tailpos -> aeb_fate_code:call_gtr(?a, Lbl, ?a, ?a);
|
Call = if Env#env.tailpos -> aeb_fate_ops:call_gtr(?a, Lbl, ?a, ?a);
|
||||||
true -> aeb_fate_code:call_gr(?a, Lbl, ?a, ?a)
|
true -> aeb_fate_ops:call_gr(?a, Lbl, ?a, ?a)
|
||||||
end,
|
end,
|
||||||
call_to_scode(Env, Call, [Ct, Value, Gas | Args]);
|
call_to_scode(Env, Call, [Ct, Value, Gas | Args]);
|
||||||
|
|
||||||
to_scode(Env, {closure, Fun, FVs}) ->
|
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}) ->
|
to_scode(Env, {switch, Case}) ->
|
||||||
split_to_scode(Env, Case).
|
split_to_scode(Env, Case).
|
||||||
|
|
||||||
local_call( Env, Fun) when Env#env.tailpos -> aeb_fate_code:call_t(Fun);
|
local_call( Env, Fun) when Env#env.tailpos -> aeb_fate_ops:call_t(Fun);
|
||||||
local_call(_Env, Fun) -> aeb_fate_code:call(Fun).
|
local_call(_Env, Fun) -> aeb_fate_ops:call(Fun).
|
||||||
|
|
||||||
split_to_scode(Env, {nosplit, Expr}) ->
|
split_to_scode(Env, {nosplit, Expr}) ->
|
||||||
[switch_body, to_scode(Env, Expr)];
|
[switch_body, to_scode(Env, Expr)];
|
||||||
@ -295,13 +310,13 @@ split_to_scode(Env, {split, {list, _}, X, Alts}) ->
|
|||||||
[{'case', {'::', Y, Z}, S} | _] ->
|
[{'case', {'::', Y, Z}, S} | _] ->
|
||||||
{I, Env1} = bind_local(Y, Env),
|
{I, Env1} = bind_local(Y, Env),
|
||||||
{J, Env2} = bind_local(Z, Env1),
|
{J, Env2} = bind_local(Z, Env1),
|
||||||
[aeb_fate_code:hd({var, I}, Arg),
|
[aeb_fate_ops:hd({var, I}, Arg),
|
||||||
aeb_fate_code:tl({var, J}, Arg),
|
aeb_fate_ops:tl({var, J}, Arg),
|
||||||
split_to_scode(Env2, S)]
|
split_to_scode(Env2, S)]
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
SAlts = [GetAlt('::'), GetAlt(nil)],
|
SAlts = [GetAlt('::'), GetAlt(nil)],
|
||||||
[aeb_fate_code:is_nil(?a, Arg),
|
[aeb_fate_ops:is_nil(?a, Arg),
|
||||||
{switch, ?a, boolean, SAlts, Def}];
|
{switch, ?a, boolean, SAlts, Def}];
|
||||||
split_to_scode(Env, {split, Type, X, Alts}) when Type == integer; Type == string ->
|
split_to_scode(Env, {split, Type, X, Alts}) when Type == integer; Type == string ->
|
||||||
{Def, Alts1} = catchall_to_scode(Env, X, Alts),
|
{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;
|
{int, N} -> N;
|
||||||
{string, S} -> aeb_fate_data:make_string(S)
|
{string, S} -> aeb_fate_data:make_string(S)
|
||||||
end,
|
end,
|
||||||
[aeb_fate_code:eq(?a, Arg, ?i(SLit)),
|
[aeb_fate_ops:eq(?a, Arg, ?i(SLit)),
|
||||||
{switch, ?a, boolean, [False, True], Def}].
|
{switch, ?a, boolean, [False, True], Def}].
|
||||||
|
|
||||||
catchall_to_scode(Env, X, Alts) -> catchall_to_scode(Env, X, Alts, []).
|
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.
|
%% Tuple is in the accumulator. Arguments are the variable names.
|
||||||
match_tuple(Env, Arg, Xs) ->
|
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) ->
|
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, 0, Elem, Arg, Xs).
|
||||||
|
|
||||||
match_tuple(Env, I, 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, []) ->
|
builtin_to_scode(_Env, get_state, []) ->
|
||||||
[push(?s)];
|
[push(?s)];
|
||||||
builtin_to_scode(Env, set_state, [_] = Args) ->
|
builtin_to_scode(Env, set_state, [_] = Args) ->
|
||||||
call_to_scode(Env, [aeb_fate_code:store(?s, ?a),
|
call_to_scode(Env, [aeb_fate_ops:store(?s, ?a),
|
||||||
aeb_fate_code:tuple(0)], Args);
|
aeb_fate_ops:tuple(0)], Args);
|
||||||
builtin_to_scode(_Env, event, [_] = _Args) ->
|
builtin_to_scode(_Env, event, [_] = _Args) ->
|
||||||
?TODO(fate_event_instruction);
|
?TODO(fate_event_instruction);
|
||||||
builtin_to_scode(_Env, map_empty, []) ->
|
builtin_to_scode(_Env, map_empty, []) ->
|
||||||
[aeb_fate_code:map_empty(?a)];
|
[aeb_fate_ops:map_empty(?a)];
|
||||||
builtin_to_scode(_Env, bits_none, []) ->
|
builtin_to_scode(_Env, bits_none, []) ->
|
||||||
[aeb_fate_code:bits_none(?a)];
|
[aeb_fate_ops:bits_none(?a)];
|
||||||
builtin_to_scode(_Env, bits_all, []) ->
|
builtin_to_scode(_Env, bits_all, []) ->
|
||||||
[aeb_fate_code:bits_all(?a)];
|
[aeb_fate_ops:bits_all(?a)];
|
||||||
builtin_to_scode(Env, abort, [_] = Args) ->
|
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) ->
|
builtin_to_scode(Env, chain_spend, [_, _] = Args) ->
|
||||||
call_to_scode(Env, [aeb_fate_code:spend(?a, ?a),
|
call_to_scode(Env, [aeb_fate_ops:spend(?a, ?a),
|
||||||
aeb_fate_code:tuple(0)], Args);
|
aeb_fate_ops:tuple(0)], Args);
|
||||||
builtin_to_scode(Env, chain_balance, [_] = 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) ->
|
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, []) ->
|
builtin_to_scode(_Env, chain_coinbase, []) ->
|
||||||
[aeb_fate_code:beneficiary(?a)];
|
[aeb_fate_ops:beneficiary(?a)];
|
||||||
builtin_to_scode(_Env, chain_timestamp, []) ->
|
builtin_to_scode(_Env, chain_timestamp, []) ->
|
||||||
[aeb_fate_code:timestamp(?a)];
|
[aeb_fate_ops:timestamp(?a)];
|
||||||
builtin_to_scode(_Env, chain_block_height, []) ->
|
builtin_to_scode(_Env, chain_block_height, []) ->
|
||||||
[aeb_fate_code:generation(?a)];
|
[aeb_fate_ops:generation(?a)];
|
||||||
builtin_to_scode(_Env, chain_difficulty, []) ->
|
builtin_to_scode(_Env, chain_difficulty, []) ->
|
||||||
[aeb_fate_code:difficulty(?a)];
|
[aeb_fate_ops:difficulty(?a)];
|
||||||
builtin_to_scode(_Env, chain_gas_limit, []) ->
|
builtin_to_scode(_Env, chain_gas_limit, []) ->
|
||||||
[aeb_fate_code:gaslimit(?a)];
|
[aeb_fate_ops:gaslimit(?a)];
|
||||||
builtin_to_scode(_Env, contract_balance, []) ->
|
builtin_to_scode(_Env, contract_balance, []) ->
|
||||||
[aeb_fate_code:balance(?a)];
|
[aeb_fate_ops:balance(?a)];
|
||||||
builtin_to_scode(_Env, contract_address, []) ->
|
builtin_to_scode(_Env, contract_address, []) ->
|
||||||
[aeb_fate_code:address(?a)];
|
[aeb_fate_ops:address(?a)];
|
||||||
builtin_to_scode(_Env, call_origin, []) ->
|
builtin_to_scode(_Env, call_origin, []) ->
|
||||||
[aeb_fate_code:origin(?a)];
|
[aeb_fate_ops:origin(?a)];
|
||||||
builtin_to_scode(_Env, call_caller, []) ->
|
builtin_to_scode(_Env, call_caller, []) ->
|
||||||
[aeb_fate_code:caller(?a)];
|
[aeb_fate_ops:caller(?a)];
|
||||||
builtin_to_scode(_Env, call_value, []) ->
|
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, []) ->
|
builtin_to_scode(_Env, call_gas_price, []) ->
|
||||||
[aeb_fate_code:gasprice(?a)];
|
[aeb_fate_ops:gasprice(?a)];
|
||||||
builtin_to_scode(_Env, call_gas_left, []) ->
|
builtin_to_scode(_Env, call_gas_left, []) ->
|
||||||
[aeb_fate_code:gas(?a)];
|
[aeb_fate_ops:gas(?a)];
|
||||||
builtin_to_scode(_Env, oracle_register, [_, _, _, _] = _Args) ->
|
builtin_to_scode(_Env, oracle_register, [_, _, _, _] = _Args) ->
|
||||||
?TODO(fate_oracle_register_instruction);
|
?TODO(fate_oracle_register_instruction);
|
||||||
builtin_to_scode(_Env, oracle_query_fee, [_] = _Args) ->
|
builtin_to_scode(_Env, oracle_query_fee, [_] = _Args) ->
|
||||||
@ -457,44 +472,44 @@ builtin_to_scode(_Env, auth_tx_hash, []) ->
|
|||||||
|
|
||||||
%% -- Operators --
|
%% -- Operators --
|
||||||
|
|
||||||
op_to_scode('+') -> aeb_fate_code:add(?a, ?a, ?a);
|
op_to_scode('+') -> aeb_fate_ops:add(?a, ?a, ?a);
|
||||||
op_to_scode('-') -> aeb_fate_code:sub(?a, ?a, ?a);
|
op_to_scode('-') -> aeb_fate_ops:sub(?a, ?a, ?a);
|
||||||
op_to_scode('*') -> aeb_fate_code:mul(?a, ?a, ?a);
|
op_to_scode('*') -> aeb_fate_ops:mul(?a, ?a, ?a);
|
||||||
op_to_scode('/') -> aeb_fate_code:divide(?a, ?a, ?a);
|
op_to_scode('/') -> aeb_fate_ops:divide(?a, ?a, ?a);
|
||||||
op_to_scode(mod) -> aeb_fate_code:modulo(?a, ?a, ?a);
|
op_to_scode(mod) -> aeb_fate_ops:modulo(?a, ?a, ?a);
|
||||||
op_to_scode('^') -> aeb_fate_code:pow(?a, ?a, ?a);
|
op_to_scode('^') -> aeb_fate_ops:pow(?a, ?a, ?a);
|
||||||
op_to_scode('++') -> aeb_fate_code:append(?a, ?a, ?a);
|
op_to_scode('++') -> aeb_fate_ops:append(?a, ?a, ?a);
|
||||||
op_to_scode('::') -> aeb_fate_code:cons(?a, ?a, ?a);
|
op_to_scode('::') -> aeb_fate_ops:cons(?a, ?a, ?a);
|
||||||
op_to_scode('<') -> aeb_fate_code:lt(?a, ?a, ?a);
|
op_to_scode('<') -> aeb_fate_ops:lt(?a, ?a, ?a);
|
||||||
op_to_scode('>') -> aeb_fate_code:gt(?a, ?a, ?a);
|
op_to_scode('>') -> aeb_fate_ops:gt(?a, ?a, ?a);
|
||||||
op_to_scode('=<') -> aeb_fate_code:elt(?a, ?a, ?a);
|
op_to_scode('=<') -> aeb_fate_ops:elt(?a, ?a, ?a);
|
||||||
op_to_scode('>=') -> aeb_fate_code:egt(?a, ?a, ?a);
|
op_to_scode('>=') -> aeb_fate_ops:egt(?a, ?a, ?a);
|
||||||
op_to_scode('==') -> aeb_fate_code:eq(?a, ?a, ?a);
|
op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a);
|
||||||
op_to_scode('!=') -> aeb_fate_code:neq(?a, ?a, ?a);
|
op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a);
|
||||||
op_to_scode('!') -> aeb_fate_code:not_op(?a, ?a);
|
op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a);
|
||||||
op_to_scode(map_get) -> aeb_fate_code:map_lookup(?a, ?a, ?a);
|
op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a);
|
||||||
op_to_scode(map_get_d) -> aeb_fate_code:map_lookup(?a, ?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_code:map_update(?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_code:map_from_list(?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_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_delete) -> aeb_fate_ops:map_delete(?a, ?a, ?a);
|
||||||
op_to_scode(map_member) -> aeb_fate_code:map_member(?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(map_size) -> ?TODO(fate_map_size_instruction);
|
||||||
op_to_scode(string_length) -> ?TODO(fate_string_length_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(string_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a);
|
||||||
op_to_scode(bits_set) -> aeb_fate_code:bits_set(?a, ?a, ?a);
|
op_to_scode(bits_set) -> aeb_fate_ops:bits_set(?a, ?a, ?a);
|
||||||
op_to_scode(bits_clear) -> aeb_fate_code:bits_clear(?a, ?a, ?a);
|
op_to_scode(bits_clear) -> aeb_fate_ops:bits_clear(?a, ?a, ?a);
|
||||||
op_to_scode(bits_test) -> aeb_fate_code:bits_test(?a, ?a, ?a);
|
op_to_scode(bits_test) -> aeb_fate_ops:bits_test(?a, ?a, ?a);
|
||||||
op_to_scode(bits_sum) -> aeb_fate_code:bits_sum(?a, ?a);
|
op_to_scode(bits_sum) -> aeb_fate_ops:bits_sum(?a, ?a);
|
||||||
op_to_scode(bits_intersection) -> aeb_fate_code:bits_and(?a, ?a, ?a);
|
op_to_scode(bits_intersection) -> aeb_fate_ops:bits_and(?a, ?a, ?a);
|
||||||
op_to_scode(bits_union) -> aeb_fate_code:bits_or(?a, ?a, ?a);
|
op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a);
|
||||||
op_to_scode(bits_difference) -> aeb_fate_code:bits_diff(?a, ?a, ?a);
|
op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
||||||
op_to_scode(address_to_str) -> aeb_fate_code:addr_to_str(?a, ?a);
|
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
||||||
op_to_scode(int_to_str) -> aeb_fate_code:int_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
|
%% 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.
|
%% 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 ---------------------------------------------------------------
|
%% -- Phase II ---------------------------------------------------------------
|
||||||
%% Optimize
|
%% Optimize
|
||||||
@ -708,7 +723,7 @@ attributes(I) ->
|
|||||||
{'ORIGIN', A} -> Pure(A, []);
|
{'ORIGIN', A} -> Pure(A, []);
|
||||||
{'CALLER', A} -> Pure(A, []);
|
{'CALLER', A} -> Pure(A, []);
|
||||||
{'GASPRICE', A} -> Pure(A, []);
|
{'GASPRICE', A} -> Pure(A, []);
|
||||||
{'BLOCKHASH', A} -> Pure(A, []);
|
{'BLOCKHASH', A, B} -> Impure(A, [B]);
|
||||||
{'BENEFICIARY', A} -> Pure(A, []);
|
{'BENEFICIARY', A} -> Pure(A, []);
|
||||||
{'TIMESTAMP', A} -> Pure(A, []);
|
{'TIMESTAMP', A} -> Pure(A, []);
|
||||||
{'GENERATION', A} -> Pure(A, []);
|
{'GENERATION', A} -> Pure(A, []);
|
||||||
@ -1150,9 +1165,9 @@ unannotate(Code) when is_list(Code) ->
|
|||||||
unannotate({i, _Ann, I}) -> [I].
|
unannotate({i, _Ann, I}) -> [I].
|
||||||
|
|
||||||
%% Desugar and specialize
|
%% Desugar and specialize
|
||||||
desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_code:inc()];
|
desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_ops:inc()];
|
||||||
desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_code:dec()];
|
desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:dec()];
|
||||||
desugar({'STORE', ?a, A}) -> [aeb_fate_code:push(A)];
|
desugar({'STORE', ?a, A}) -> [aeb_fate_ops:push(A)];
|
||||||
desugar({switch, Arg, Type, Alts, Def}) ->
|
desugar({switch, Arg, Type, Alts, Def}) ->
|
||||||
[{switch, Arg, Type, [desugar(A) || A <- Alts], desugar(Def)}];
|
[{switch, Arg, Type, [desugar(A) || A <- Alts], desugar(Def)}];
|
||||||
desugar(missing) -> missing;
|
desugar(missing) -> missing;
|
||||||
@ -1163,12 +1178,16 @@ desugar(I) -> [I].
|
|||||||
%% -- Phase III --------------------------------------------------------------
|
%% -- Phase III --------------------------------------------------------------
|
||||||
%% Constructing basic blocks
|
%% Constructing basic blocks
|
||||||
|
|
||||||
to_basic_blocks(Funs, Options) ->
|
to_basic_blocks(Funs) ->
|
||||||
maps:from_list([ {Name, {{Args, Res},
|
to_basic_blocks(maps:to_list(Funs), aeb_fate_code:new()).
|
||||||
bb(Name, Code ++ [aeb_fate_code:return()], Options)}}
|
|
||||||
|| {Name, {{Args, Res}, Code}} <- maps:to_list(Funs) ]).
|
|
||||||
|
|
||||||
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),
|
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),
|
||||||
@ -1219,7 +1238,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code],
|
|||||||
{DefRef, DefBlk} =
|
{DefRef, DefBlk} =
|
||||||
case Default of
|
case Default of
|
||||||
missing when Catchall == none ->
|
missing when Catchall == none ->
|
||||||
FreshBlk([aeb_fate_code:abort(?i(<<"Incomplete patterns">>))], none);
|
FreshBlk([aeb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none);
|
||||||
missing -> {Catchall, []};
|
missing -> {Catchall, []};
|
||||||
_ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall)
|
_ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall)
|
||||||
%% ^ fall-through to the outer 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', {'PUSH', A} | Code]) -> [{'RETURNR', A} | Code];
|
||||||
tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) -> Code;
|
tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) -> Code;
|
||||||
tweak_returns(['RETURN' | Code = [{'CALL_TR', _, _} | _]]) -> 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(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code;
|
||||||
tweak_returns(Code) -> Code.
|
tweak_returns(Code) -> Code.
|
||||||
|
|
||||||
@ -1346,7 +1367,9 @@ split_calls({Ref, Code}) ->
|
|||||||
|
|
||||||
split_calls(Ref, [], Acc, Blocks) ->
|
split_calls(Ref, [], Acc, Blocks) ->
|
||||||
lists:reverse([{Ref, lists:reverse(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(make_ref(), Code, [], [{Ref, lists:reverse([I | Acc])} | Blocks]);
|
||||||
split_calls(Ref, [I | Code], Acc, Blocks) ->
|
split_calls(Ref, [I | Code], Acc, Blocks) ->
|
||||||
split_calls(Ref, Code, [I | 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) ->
|
set_labels(Labels, {Ref, Code}) when is_reference(Ref) ->
|
||||||
{maps:get(Ref, Labels), [ set_labels(Labels, I) || I <- Code ]};
|
{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, {jump, Ref}) -> aeb_fate_ops:jump(maps:get(Ref, Labels));
|
||||||
set_labels(Labels, {jumpif, Arg, Ref}) -> aeb_fate_code:jumpif(Arg, 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}) ->
|
set_labels(Labels, {switch, Arg, Refs}) ->
|
||||||
case [ maps:get(Ref, Labels) || Ref <- Refs ] of
|
case [ maps:get(Ref, Labels) || Ref <- Refs ] of
|
||||||
[R1, R2] -> aeb_fate_code:switch(Arg, R1, R2);
|
[R1, R2] -> aeb_fate_ops:switch(Arg, R1, R2);
|
||||||
[R1, R2, R3] -> aeb_fate_code:switch(Arg, R1, R2, R3);
|
[R1, R2, R3] -> aeb_fate_ops:switch(Arg, R1, R2, R3);
|
||||||
Rs -> aeb_fate_code:switch(Arg, Rs)
|
Rs -> aeb_fate_ops:switch(Arg, Rs)
|
||||||
end;
|
end;
|
||||||
set_labels(_, I) -> I.
|
set_labels(_, I) -> I.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user