1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%% Purpose : Optimize bit syntax matching.
21
22
23-module(sys_core_bsm).
24-export([module/2]).
25
26-include("core_parse.hrl").
27
28-spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}.
29
30module(#c_module{defs=Ds}=Mod, _Opts) ->
31    {ok,Mod#c_module{defs=function(Ds)}}.
32
33function([{#c_var{name={F,Arity}}=Name,B0}|Fs]) ->
34    try cerl_trees:map(fun bsm_reorder/1, B0) of
35        B -> [{Name,B} | function(Fs)]
36    catch
37        Class:Error:Stack ->
38            io:fwrite("Function: ~w/~w\n", [F,Arity]),
39            erlang:raise(Class, Error, Stack)
40    end;
41function([]) ->
42    [].
43
44%%% Reorder bit syntax matching to faciliate optimization in further passes.
45
46bsm_reorder(#c_case{arg=#c_var{}=V}=Case) ->
47    bsm_reorder_1([V], Case);
48bsm_reorder(#c_case{arg=#c_values{es=Es}}=Case) ->
49    bsm_reorder_1(Es, Case);
50bsm_reorder(Core) ->
51    Core.
52
53bsm_reorder_1(Vs0, #c_case{clauses=Cs0}=Case) ->
54    case bsm_leftmost(Cs0) of
55        Pos when Pos > 0, Pos =/= none ->
56            Vs = core_lib:make_values(move_from_col(Pos, Vs0)),
57            Cs = [C#c_clause{pats=move_from_col(Pos, Ps)}
58                  || #c_clause{pats=Ps}=C <- Cs0],
59            Case#c_case{arg=Vs,clauses=Cs};
60        _ ->
61            Case
62    end.
63
64move_from_col(Pos, L) ->
65    {First,[Col|Rest]} = lists:split(Pos - 1, L),
66    [Col|First] ++ Rest.
67
68%% bsm_leftmost(Cs) -> none | ArgumentNumber
69%%  Find the leftmost argument that matches a nonempty binary.
70%%  Return either 'none' or the argument number (1-N).
71
72bsm_leftmost(Cs) ->
73    bsm_leftmost_1(Cs, none).
74
75bsm_leftmost_1([_|_], 1) ->
76    1;
77bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) ->
78    bsm_leftmost_2(Ps, Cs, 1, Pos);
79bsm_leftmost_1([], Pos) -> Pos.
80
81bsm_leftmost_2(_, Cs, Pos, Pos) ->
82    bsm_leftmost_1(Cs, Pos);
83bsm_leftmost_2([#c_binary{segments=[_|_]}|_], Cs, N, _) ->
84    bsm_leftmost_1(Cs, N);
85bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
86    bsm_leftmost_2(Ps, Cs, N+1, Pos);
87bsm_leftmost_2([], Cs, _, Pos) ->
88    bsm_leftmost_1(Cs, Pos).
89