diff options
Diffstat (limited to 'lib/hipe/icode/hipe_icode_bincomp.erl')
-rw-r--r-- | lib/hipe/icode/hipe_icode_bincomp.erl | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/lib/hipe/icode/hipe_icode_bincomp.erl b/lib/hipe/icode/hipe_icode_bincomp.erl new file mode 100644 index 0000000000..6f694f2bce --- /dev/null +++ b/lib/hipe/icode/hipe_icode_bincomp.erl @@ -0,0 +1,178 @@ +%%% -*- erlang-indent-level: 2 -*- +%%% +%%% %CopyrightBegin% +%%% +%%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%%% +%%% The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved online at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% %CopyrightEnd% +%%% +%%%------------------------------------------------------------------- +%%% File : hipe_icode_bincomp.erl +%%% Author : Per Gustafsson <[email protected]> +%%% Description : +%%% +%%% Created : 12 Sep 2005 by Per Gustafsson <[email protected]> +%%%------------------------------------------------------------------- + +-module(hipe_icode_bincomp). + +-export([cfg/1]). + +%%-------------------------------------------------------------------- + +-include("hipe_icode.hrl"). +-include("../flow/cfg.hrl"). + +%%-------------------------------------------------------------------- + +-spec cfg(cfg()) -> cfg(). + +cfg(Cfg1) -> + StartLbls = ordsets:from_list([hipe_icode_cfg:start_label(Cfg1)]), + find_bs_get_integer(StartLbls, Cfg1, StartLbls). + +find_bs_get_integer([Lbl|Rest], Cfg, Visited) -> + BB = hipe_icode_cfg:bb(Cfg, Lbl), + Last = hipe_bb:last(BB), + NewCfg = + case ok(Last, Cfg) of + {ok,{Type, FakeFail, RealFail, SuccLbl, MsIn, MsOut}} -> + {Cont, Info, OldLbl, LastMsOut} = + collect_info(SuccLbl, Cfg, [Type], Lbl, RealFail, MsOut), + update_code(Lbl, OldLbl, Cfg, Info, Cont, FakeFail, MsIn, LastMsOut); + not_ok -> + Cfg + end, + Succs = ordsets:from_list(hipe_icode_cfg:succ(NewCfg, Lbl)), + NewSuccs = ordsets:subtract(Succs, Visited), + NewLbls = ordsets:union(NewSuccs, Rest), + NewVisited = ordsets:union(NewSuccs, Visited), + find_bs_get_integer(NewLbls, NewCfg, NewVisited); +find_bs_get_integer([], Cfg, _) -> + Cfg. + +ok(I, Cfg) -> + case hipe_icode:is_call(I) of + true -> + case hipe_icode:call_fun(I) of + {hipe_bs_primop, {bs_get_integer, Size, Flags}} when (Flags band 6) =:= 0 -> + case {hipe_icode:call_dstlist(I), hipe_icode:call_args(I)} of + {[Dst, MsOut] = DstList, [MsIn]} -> + Cont = hipe_icode:call_continuation(I), + FirstFail = hipe_icode:call_fail_label(I), + FirstFailBB = hipe_icode_cfg:bb(Cfg, FirstFail), + case check_for_restore_block(FirstFailBB, DstList) of + {restore_block, RealFail} -> + {ok, {{Dst, Size}, FirstFail, RealFail, Cont, MsIn, MsOut}}; + not_restore_block -> + not_ok + end; + _ -> + not_ok + end; + _ -> + not_ok + end; + false -> + not_ok + end. + +check_for_restore_block(FirstFailBB, DefVars) -> + Moves = hipe_bb:butlast(FirstFailBB), + case [Instr || Instr <- Moves, is_badinstr(Instr, DefVars)] of + [] -> + Last = hipe_bb:last(FirstFailBB), + case hipe_icode:is_goto(Last) of + true -> + {restore_block, hipe_icode:goto_label(Last)}; + false -> + not_restore_block + end; + [_|_] -> + not_restore_block + end. + +is_badinstr(Instr, DefVars) -> + not(hipe_icode:is_move(Instr) andalso + lists:member(hipe_icode:move_dst(Instr), DefVars)). + +collect_info(Lbl, Cfg, Acc, OldLbl, FailLbl, MsOut) -> + case do_collect_info(Lbl, Cfg, Acc, FailLbl, MsOut) of + done -> + {Lbl, Acc, OldLbl, MsOut}; + {cont, NewAcc, NewLbl, NewMsOut} -> + collect_info(NewLbl, Cfg, NewAcc, Lbl, FailLbl, NewMsOut) + end. + +do_collect_info(Lbl, Cfg, Acc, FailLbl, MsOut) -> + BB = hipe_icode_cfg:bb(Cfg,Lbl), + case hipe_bb:code(BB) of + [I] -> + case hipe_icode_cfg:pred(Cfg,Lbl) of + [_] -> + case ok(I, Cfg) of + {ok, {Type,_FakeFail,FailLbl,SuccLbl,MsOut,NewMsOut}} -> + NewAcc = [Type|Acc], + MaxSize = hipe_rtl_arch:word_size() * 8 - 5, + case calc_size(NewAcc) of + Size when Size =< MaxSize -> + {cont,NewAcc,SuccLbl,NewMsOut}; + _ -> + done + end; + _ -> + done + end; + _ -> + done + end; + _ -> + done + end. + +calc_size([{_,Size}|Rest]) when is_integer(Size) -> + Size + calc_size(Rest); +calc_size([]) -> 0. + +update_code(_Lbl, _, Cfg, [_Info], _Cont, _LastFail, _MsIn, _MsOut) -> + Cfg; +update_code(Lbl, OldLbl, Cfg, Info, Cont, LastFail, MsIn, MsOut) -> + BB = hipe_icode_cfg:bb(Cfg, Lbl), + ButLast = hipe_bb:butlast(BB), + NewVar = hipe_icode:mk_new_var(), + Size = calc_size(Info), + NewLast = + hipe_icode:mk_primop([NewVar,MsOut], + {hipe_bs_primop, {bs_get_integer,Size,0}}, + [MsIn], + OldLbl, + LastFail), + NewBB = hipe_bb:mk_bb(ButLast++[NewLast]), + NewCfg = hipe_icode_cfg:bb_add(Cfg, Lbl, NewBB), + fix_rest(Info, NewVar, OldLbl, Cont, NewCfg). + +fix_rest(Info, Var, Lbl, Cont, Cfg) -> + ButLast = make_butlast(Info, Var), + Last = hipe_icode:mk_goto(Cont), + NewBB = hipe_bb:mk_bb(ButLast++[Last]), + hipe_icode_cfg:bb_add(Cfg, Lbl, NewBB). + +make_butlast([{Res,_Size}], Var) -> + [hipe_icode:mk_move(Res, Var)]; +make_butlast([{Res, Size}|Rest], Var) -> + NewVar = hipe_icode:mk_new_var(), + [hipe_icode:mk_primop([Res], 'band', + [Var, hipe_icode:mk_const((1 bsl Size)-1)]), + hipe_icode:mk_primop([NewVar], 'bsr', [Var, hipe_icode:mk_const(Size)]) + |make_butlast(Rest, NewVar)]. |