Pattern matching on booleans
This commit is contained in:
parent
59845dec54
commit
ab13222d29
@ -38,13 +38,15 @@
|
|||||||
| {nosplit, [var_name()], fexpr()}.
|
| {nosplit, [var_name()], fexpr()}.
|
||||||
|
|
||||||
-type fsplit_case() :: {'case', fsplit_pat(), fcase()}.
|
-type fsplit_case() :: {'case', fsplit_pat(), fcase()}.
|
||||||
-type fsplit_pat() :: {tuple, [var_name()]}.
|
-type fsplit_pat() :: {bool, false | true}
|
||||||
|
| {tuple, [var_name()]}.
|
||||||
|
|
||||||
-type fdefault() :: nodefault | {default, fcase()}.
|
-type fdefault() :: nodefault | {default, fcase()}.
|
||||||
|
|
||||||
%% Intermediate format before case trees (fcase() and fsplit()).
|
%% Intermediate format before case trees (fcase() and fsplit()).
|
||||||
-type falt() :: {'case', [fpat()], fexpr()}.
|
-type falt() :: {'case', [fpat()], fexpr()}.
|
||||||
-type fpat() :: {var, var_name()}
|
-type fpat() :: {var, var_name()}
|
||||||
|
| {bool, false | true}
|
||||||
| {tuple, [fpat()]}.
|
| {tuple, [fpat()]}.
|
||||||
|
|
||||||
-type ftype() :: aeb_fate_data:fate_type_type().
|
-type ftype() :: aeb_fate_data:fate_type_type().
|
||||||
@ -238,6 +240,7 @@ split_tree(Env, Vars, Alts) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
-spec split_vars(fsplit_pat(), ftype()) -> [{var_name(), ftype()}].
|
-spec split_vars(fsplit_pat(), ftype()) -> [{var_name(), ftype()}].
|
||||||
|
split_vars({bool, _}, boolean) -> [];
|
||||||
split_vars({tuple, Xs}, {tuple, Ts}) ->
|
split_vars({tuple, Xs}, {tuple, Ts}) ->
|
||||||
lists:zip(Xs, Ts).
|
lists:zip(Xs, Ts).
|
||||||
|
|
||||||
@ -263,6 +266,7 @@ split_alt(I, {'case', Pats, Body}) ->
|
|||||||
|
|
||||||
-spec split_pat(fpat()) -> {fsplit_pat() | default, [fpat()]}.
|
-spec split_pat(fpat()) -> {fsplit_pat() | default, [fpat()]}.
|
||||||
split_pat({var, X}) -> {default, [{var, X}]};
|
split_pat({var, X}) -> {default, [{var, X}]};
|
||||||
|
split_pat({bool, B}) -> {{bool, B}, []};
|
||||||
split_pat({tuple, Pats}) ->
|
split_pat({tuple, Pats}) ->
|
||||||
Var = fun({var, X}) -> X; (_) -> fresh_name() end,
|
Var = fun({var, X}) -> X; (_) -> fresh_name() end,
|
||||||
Xs = [Var(P) || P <- Pats],
|
Xs = [Var(P) || P <- Pats],
|
||||||
@ -271,7 +275,9 @@ split_pat({tuple, Pats}) ->
|
|||||||
-spec group_by_split_pat([{fsplit_pat() | default, falt()}]) -> [{fsplit_pat(), [falt()]}].
|
-spec group_by_split_pat([{fsplit_pat() | default, falt()}]) -> [{fsplit_pat(), [falt()]}].
|
||||||
group_by_split_pat(Alts) ->
|
group_by_split_pat(Alts) ->
|
||||||
Tag = fun(default) -> default;
|
Tag = fun(default) -> default;
|
||||||
({tuple, _}) -> tuple end,
|
({tuple, _}) -> tuple;
|
||||||
|
({bool, B}) -> B
|
||||||
|
end,
|
||||||
Grouped = maps:values(lists:foldr(
|
Grouped = maps:values(lists:foldr(
|
||||||
fun({Pat, _} = Alt, Map) ->
|
fun({Pat, _} = Alt, Map) ->
|
||||||
maps:update_with(Tag(Pat), fun(As) -> [Alt | As] end, [Alt], Map)
|
maps:update_with(Tag(Pat), fun(As) -> [Alt | As] end, [Alt], Map)
|
||||||
@ -292,6 +298,8 @@ pat_to_fcode(Env, Pat) ->
|
|||||||
pat_to_fcode(_Env, _Type, {id, _, X}) -> {var, X};
|
pat_to_fcode(_Env, _Type, {id, _, X}) -> {var, X};
|
||||||
pat_to_fcode(Env, _Type, {tuple, _, Pats}) ->
|
pat_to_fcode(Env, _Type, {tuple, _, Pats}) ->
|
||||||
{tuple, [ pat_to_fcode(Env, Pat) || Pat <- Pats ]};
|
{tuple, [ pat_to_fcode(Env, Pat) || Pat <- Pats ]};
|
||||||
|
pat_to_fcode(_Env, _Type, {bool, _, B}) ->
|
||||||
|
{bool, B};
|
||||||
pat_to_fcode(_Env, Type, Pat) -> {todo, Pat, ':', Type}.
|
pat_to_fcode(_Env, Type, Pat) -> {todo, Pat, ':', Type}.
|
||||||
|
|
||||||
-spec stmts_to_fcode(env(), [aeso_syntax:stmt()]) -> fexpr().
|
-spec stmts_to_fcode(env(), [aeso_syntax:stmt()]) -> fexpr().
|
||||||
@ -307,6 +315,7 @@ stmts_to_fcode(Env, [Expr]) ->
|
|||||||
%% - Deadcode elimination
|
%% - Deadcode elimination
|
||||||
%% - Unused variable analysis (replace by _)
|
%% - Unused variable analysis (replace by _)
|
||||||
%% - Simplified case trees (FATE has special instructions for shallow matching)
|
%% - Simplified case trees (FATE has special instructions for shallow matching)
|
||||||
|
%% - Case specialization
|
||||||
%% - Constant propagation
|
%% - Constant propagation
|
||||||
|
|
||||||
%% -- Helper functions -------------------------------------------------------
|
%% -- Helper functions -------------------------------------------------------
|
||||||
|
@ -111,6 +111,9 @@ lookup_var(Env = #env{ args = Args, locals = Locals }, X) ->
|
|||||||
to_scode(_Env, {integer, N}) ->
|
to_scode(_Env, {integer, N}) ->
|
||||||
[aeb_fate_code:push(?i(N))]; %% Doesn't exist (yet), translated by desugaring
|
[aeb_fate_code:push(?i(N))]; %% Doesn't exist (yet), translated by desugaring
|
||||||
|
|
||||||
|
to_scode(_Env, {bool, B}) ->
|
||||||
|
[aeb_fate_code:push(?i(B))];
|
||||||
|
|
||||||
to_scode(Env, {var, X}) ->
|
to_scode(Env, {var, X}) ->
|
||||||
[aeb_fate_code:push(lookup_var(Env, X))];
|
[aeb_fate_code:push(lookup_var(Env, X))];
|
||||||
|
|
||||||
@ -146,6 +149,16 @@ case_to_scode(Env, {split, _Type, X, [{'case', {tuple, Xs}, Case}], nodefault})
|
|||||||
{Code, Env1} = match_tuple(Env, Xs),
|
{Code, Env1} = match_tuple(Env, Xs),
|
||||||
[aeb_fate_code:push(lookup_var(Env, X)),
|
[aeb_fate_code:push(lookup_var(Env, X)),
|
||||||
Code, case_to_scode(Env1, Case)];
|
Code, case_to_scode(Env1, Case)];
|
||||||
|
case_to_scode(Env, Split = {split, boolean, X, Cases, nodefault}) ->
|
||||||
|
Then = lists:keyfind({bool, true}, 2, Cases),
|
||||||
|
Else = lists:keyfind({bool, false}, 2, Cases),
|
||||||
|
case {Then, Else} of
|
||||||
|
{{'case', _, ThenSplit}, {'case', _, ElseSplit}} ->
|
||||||
|
[aeb_fate_code:push(lookup_var(Env, X)),
|
||||||
|
{ifte, case_to_scode(Env, ThenSplit),
|
||||||
|
case_to_scode(Env, ElseSplit)}];
|
||||||
|
_ -> ?TODO({'case', Split})
|
||||||
|
end;
|
||||||
case_to_scode(_, Split = {split, _, _, _, _}) ->
|
case_to_scode(_, Split = {split, _, _, _, _}) ->
|
||||||
?TODO({'case', Split}).
|
?TODO({'case', Split}).
|
||||||
|
|
||||||
@ -473,7 +486,8 @@ apply_rules_once([{RName, Rule} | Rules], I, Code) ->
|
|||||||
merge_rules() ->
|
merge_rules() ->
|
||||||
[?RULE(r_push_consume),
|
[?RULE(r_push_consume),
|
||||||
?RULE(r_one_shot_var),
|
?RULE(r_one_shot_var),
|
||||||
?RULE(r_write_to_dead_var)
|
?RULE(r_write_to_dead_var),
|
||||||
|
?RULE(r_write_single_branch)
|
||||||
].
|
].
|
||||||
|
|
||||||
rules() ->
|
rules() ->
|
||||||
@ -481,7 +495,7 @@ rules() ->
|
|||||||
[?RULE(r_dup_to_push),
|
[?RULE(r_dup_to_push),
|
||||||
?RULE(r_swap_push),
|
?RULE(r_swap_push),
|
||||||
?RULE(r_swap_write),
|
?RULE(r_swap_write),
|
||||||
?RULE(r_inline)
|
?RULE(r_inline_store)
|
||||||
].
|
].
|
||||||
|
|
||||||
%% Removing pushes that are immediately consumed.
|
%% Removing pushes that are immediately consumed.
|
||||||
@ -530,27 +544,28 @@ r_swap_write(IA = {_, I}, [JA = {_, J} | Code]) ->
|
|||||||
end;
|
end;
|
||||||
r_swap_write(_, _) -> false.
|
r_swap_write(_, _) -> false.
|
||||||
|
|
||||||
r_swap_write(Pre, IA = {_, I}, Code0 = [JA = {_, J} | Code]) ->
|
r_swap_write(Pre, IA = {_, I}, Code0 = [JA | Code]) ->
|
||||||
case apply_rules_once(merge_rules(), IA, Code0) of
|
case {apply_rules_once(merge_rules(), IA, Code0), JA} of
|
||||||
{_Rule, New, Rest} ->
|
{{_Rule, New, Rest}, _} ->
|
||||||
{lists:reverse(Pre) ++ New, Rest};
|
{lists:reverse(Pre) ++ New, Rest};
|
||||||
false ->
|
{false, {_, J}} ->
|
||||||
case independent(I, J) of
|
case independent(I, J) of
|
||||||
false -> false;
|
false -> false;
|
||||||
true ->
|
true ->
|
||||||
{J1, I1} = swap_instrs(IA, JA),
|
{J1, I1} = swap_instrs(IA, JA),
|
||||||
r_swap_write([J1 | Pre], I1, Code)
|
r_swap_write([J1 | Pre], I1, Code)
|
||||||
end
|
end;
|
||||||
|
_ -> false
|
||||||
end;
|
end;
|
||||||
r_swap_write(_, _, []) -> false.
|
r_swap_write(_, _, _) -> false.
|
||||||
|
|
||||||
%% Inline stores
|
%% Inline stores
|
||||||
r_inline(I = {_, {'STORE', R = {var, _}, A = {arg, _}}}, Code) ->
|
r_inline_store(I = {_, {'STORE', R = {var, _}, A = {arg, _}}}, Code) ->
|
||||||
%% Not when A is var unless updating the annotations properly.
|
%% Not when A is var unless updating the annotations properly.
|
||||||
r_inline([I], R, A, Code);
|
r_inline_store([I], R, A, Code);
|
||||||
r_inline(_, _) -> false.
|
r_inline_store(_, _) -> false.
|
||||||
|
|
||||||
r_inline(Acc, R, A, [{Ann, I} | Code]) ->
|
r_inline_store(Acc, R, A, [{Ann, I} | Code]) ->
|
||||||
#{ write := W, pure := Pure } = attributes(I),
|
#{ write := W, pure := Pure } = attributes(I),
|
||||||
Inl = fun(X) when X == R -> A; (X) -> X end,
|
Inl = fun(X) when X == R -> A; (X) -> X end,
|
||||||
case not live_in(R, Ann) orelse not Pure orelse lists:member(W, [R, A]) of
|
case not live_in(R, Ann) orelse not Pure orelse lists:member(W, [R, A]) of
|
||||||
@ -559,14 +574,14 @@ r_inline(Acc, R, A, [{Ann, I} | Code]) ->
|
|||||||
case I of
|
case I of
|
||||||
{Op, S, B, C} when ?IsBinOp(Op), B == R orelse C == R ->
|
{Op, S, B, C} when ?IsBinOp(Op), B == R orelse C == R ->
|
||||||
Acc1 = [{Ann, {Op, S, Inl(B), Inl(C)}} | Acc],
|
Acc1 = [{Ann, {Op, S, Inl(B), Inl(C)}} | Acc],
|
||||||
case r_inline(Acc1, R, A, Code) of
|
case r_inline_store(Acc1, R, A, Code) of
|
||||||
false -> {lists:reverse(Acc1), Code};
|
false -> {lists:reverse(Acc1), Code};
|
||||||
{New, Rest} -> {New, Rest}
|
{New, Rest} -> {New, Rest}
|
||||||
end;
|
end;
|
||||||
_ -> r_inline([{Ann, I} | Acc], R, A, Code)
|
_ -> r_inline_store([{Ann, I} | Acc], R, A, Code)
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
r_inline(_Acc, _, _, []) -> false.
|
r_inline_store(_Acc, _, _, _) -> false.
|
||||||
|
|
||||||
%% Shortcut write followed by final read
|
%% Shortcut write followed by final read
|
||||||
r_one_shot_var({Ann1, {Op, R = {var, _}, A, B}}, [{Ann2, J} | Code]) when ?IsBinOp(Op) ->
|
r_one_shot_var({Ann1, {Op, R = {var, _}, A, B}}, [{Ann2, J} | Code]) when ?IsBinOp(Op) ->
|
||||||
@ -604,6 +619,22 @@ r_write_to_dead_var({Ann, {'STORE', R = {var, _}, A}}, Code) when A /= ?a ->
|
|||||||
end;
|
end;
|
||||||
r_write_to_dead_var(_, _) -> false.
|
r_write_to_dead_var(_, _) -> false.
|
||||||
|
|
||||||
|
%% Push variable writes that are only needed in a single branch inside the branch.
|
||||||
|
r_write_single_branch(IA = {_Ann, I}, [{ifte, Then = [{AnnThen, _} | _], Else = [{AnnElse, _} | _]} | Code]) ->
|
||||||
|
#{ write := R } = attributes(I),
|
||||||
|
case R of
|
||||||
|
{var, _} ->
|
||||||
|
case {live_in(R, AnnThen), live_in(R, AnnElse)} of
|
||||||
|
{true, false} ->
|
||||||
|
{[], [{ifte, [IA | Then], Else} | Code]};
|
||||||
|
{false, true} ->
|
||||||
|
{[], [{ifte, Then, [IA | Else]} | Code]};
|
||||||
|
_ -> false
|
||||||
|
end;
|
||||||
|
_ -> false
|
||||||
|
end;
|
||||||
|
r_write_single_branch(_, _) -> false.
|
||||||
|
|
||||||
|
|
||||||
%% Desugar and specialize and remove annotations
|
%% Desugar and specialize and remove annotations
|
||||||
unannotate({ifte, Then, Else}) -> [{ifte, unannotate(Then), unannotate(Else)}];
|
unannotate({ifte, Then, Else}) -> [{ifte, unannotate(Then), unannotate(Else)}];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user