%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2017-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% Purpose : Optimize bit syntax matching. -module(sys_core_bsm). -export([module/2,format_error/1]). -include("core_parse.hrl"). -spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}. module(#c_module{defs=Ds}=Mod, _Opts) -> {ok,Mod#c_module{defs=function(Ds)}}. function([{#c_var{name={F,Arity}}=Name,B0}|Fs]) -> try cerl_trees:map(fun bsm_reorder/1, B0) of B -> [{Name,B} | function(Fs)] catch Class:Error:Stack -> io:fwrite("Function: ~w/~w\n", [F,Arity]), erlang:raise(Class, Error, Stack) end; function([]) -> []. -type error() :: atom(). -spec format_error(error()) -> nonempty_string(). format_error(_) -> error(badarg). %%% Reorder bit syntax matching to faciliate optimization in further passes. bsm_reorder(#c_case{arg=#c_var{}=V}=Case) -> bsm_reorder_1([V], Case); bsm_reorder(#c_case{arg=#c_values{es=Es}}=Case) -> bsm_reorder_1(Es, Case); bsm_reorder(Core) -> Core. bsm_reorder_1(Vs0, #c_case{clauses=Cs0}=Case) -> case bsm_leftmost(Cs0) of Pos when Pos > 0, Pos =/= none -> Vs = core_lib:make_values(move_from_col(Pos, Vs0)), Cs = [C#c_clause{pats=move_from_col(Pos, Ps)} || #c_clause{pats=Ps}=C <- Cs0], Case#c_case{arg=Vs,clauses=Cs}; _ -> Case end. move_from_col(Pos, L) -> {First,[Col|Rest]} = lists:split(Pos - 1, L), [Col|First] ++ Rest. %% bsm_leftmost(Cs) -> none | ArgumentNumber %% Find the leftmost argument that matches a nonempty binary. %% Return either 'none' or the argument number (1-N). bsm_leftmost(Cs) -> bsm_leftmost_1(Cs, none). bsm_leftmost_1([_|_], 1) -> 1; bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) -> bsm_leftmost_2(Ps, Cs, 1, Pos); bsm_leftmost_1([], Pos) -> Pos. bsm_leftmost_2(_, Cs, Pos, Pos) -> bsm_leftmost_1(Cs, Pos); bsm_leftmost_2([#c_binary{segments=[_|_]}|_], Cs, N, _) -> bsm_leftmost_1(Cs, N); bsm_leftmost_2([_|Ps], Cs, N, Pos) -> bsm_leftmost_2(Ps, Cs, N+1, Pos); bsm_leftmost_2([], Cs, _, Pos) -> bsm_leftmost_1(Cs, Pos).