%%% -*- 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 <pergu@it.uu.se> %%% Description : %%% %%% Created : 12 Sep 2005 by Per Gustafsson <pergu@it.uu.se> %%%------------------------------------------------------------------- -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)].