1%%% -*- erlang-indent-level: 2 -*- 2%%% 3%%% Licensed under the Apache License, Version 2.0 (the "License"); 4%%% you may not use this file except in compliance with the License. 5%%% You may obtain a copy of the License at 6%%% 7%%% http://www.apache.org/licenses/LICENSE-2.0 8%%% 9%%% Unless required by applicable law or agreed to in writing, software 10%%% distributed under the License is distributed on an "AS IS" BASIS, 11%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12%%% See the License for the specific language governing permissions and 13%%% limitations under the License. 14%%% 15%%%------------------------------------------------------------------- 16%%% File : hipe_icode_bincomp.erl 17%%% Author : Per Gustafsson <pergu@it.uu.se> 18%%% Description : 19%%% 20%%% Created : 12 Sep 2005 by Per Gustafsson <pergu@it.uu.se> 21%%%------------------------------------------------------------------- 22 23-module(hipe_icode_bincomp). 24 25-export([cfg/1]). 26 27%%-------------------------------------------------------------------- 28 29-include("hipe_icode.hrl"). 30-include("../flow/cfg.hrl"). 31 32%%-------------------------------------------------------------------- 33 34-spec cfg(cfg()) -> cfg(). 35 36cfg(Cfg1) -> 37 StartLbl = hipe_icode_cfg:start_label(Cfg1), 38 find_bs_get_integer([StartLbl], Cfg1, set_from_list([StartLbl])). 39 40find_bs_get_integer([Lbl|Rest], Cfg, Visited) -> 41 BB = hipe_icode_cfg:bb(Cfg, Lbl), 42 Last = hipe_bb:last(BB), 43 NewCfg = 44 case ok(Last, Cfg) of 45 {ok,{Type, FakeFail, RealFail, SuccLbl, MsIn, MsOut}} -> 46 {Cont, Info, OldLbl, LastMsOut} = 47 collect_info(SuccLbl, Cfg, [Type], Lbl, RealFail, MsOut), 48 update_code(Lbl, OldLbl, Cfg, Info, Cont, FakeFail, MsIn, LastMsOut); 49 not_ok -> 50 Cfg 51 end, 52 Succs = hipe_icode_cfg:succ(NewCfg, Lbl), 53 NewSuccs = not_visited(Succs, Visited), 54 NewLbls = NewSuccs ++ Rest, 55 NewVisited = set_union(set_from_list(NewSuccs), Visited), 56 find_bs_get_integer(NewLbls, NewCfg, NewVisited); 57find_bs_get_integer([], Cfg, _) -> 58 Cfg. 59 60ok(I, Cfg) -> 61 case hipe_icode:is_call(I) of 62 true -> 63 case hipe_icode:call_fun(I) of 64 {hipe_bs_primop, {bs_get_integer, Size, Flags}} when (Flags band 6) =:= 0 -> 65 case {hipe_icode:call_dstlist(I), hipe_icode:call_args(I)} of 66 {[Dst, MsOut] = DstList, [MsIn]} -> 67 Cont = hipe_icode:call_continuation(I), 68 FirstFail = hipe_icode:call_fail_label(I), 69 FirstFailBB = hipe_icode_cfg:bb(Cfg, FirstFail), 70 case check_for_restore_block(FirstFailBB, DstList) of 71 {restore_block, RealFail} -> 72 {ok, {{Dst, Size}, FirstFail, RealFail, Cont, MsIn, MsOut}}; 73 not_restore_block -> 74 not_ok 75 end; 76 _ -> 77 not_ok 78 end; 79 _ -> 80 not_ok 81 end; 82 false -> 83 not_ok 84 end. 85 86check_for_restore_block(FirstFailBB, DefVars) -> 87 Moves = hipe_bb:butlast(FirstFailBB), 88 case [Instr || Instr <- Moves, is_badinstr(Instr, DefVars)] of 89 [] -> 90 Last = hipe_bb:last(FirstFailBB), 91 case hipe_icode:is_goto(Last) of 92 true -> 93 {restore_block, hipe_icode:goto_label(Last)}; 94 false -> 95 not_restore_block 96 end; 97 [_|_] -> 98 not_restore_block 99 end. 100 101is_badinstr(Instr, DefVars) -> 102 not(hipe_icode:is_move(Instr) andalso 103 lists:member(hipe_icode:move_dst(Instr), DefVars)). 104 105collect_info(Lbl, Cfg, Acc, OldLbl, FailLbl, MsOut) -> 106 case do_collect_info(Lbl, Cfg, Acc, FailLbl, MsOut) of 107 done -> 108 {Lbl, Acc, OldLbl, MsOut}; 109 {cont, NewAcc, NewLbl, NewMsOut} -> 110 collect_info(NewLbl, Cfg, NewAcc, Lbl, FailLbl, NewMsOut) 111 end. 112 113do_collect_info(Lbl, Cfg, Acc, FailLbl, MsOut) -> 114 BB = hipe_icode_cfg:bb(Cfg,Lbl), 115 case hipe_bb:code(BB) of 116 [I] -> 117 case hipe_icode_cfg:pred(Cfg,Lbl) of 118 [_] -> 119 case ok(I, Cfg) of 120 {ok, {Type,_FakeFail,FailLbl,SuccLbl,MsOut,NewMsOut}} -> 121 NewAcc = [Type|Acc], 122 MaxSize = hipe_rtl_arch:word_size() * 8 - 5, 123 case calc_size(NewAcc) of 124 Size when Size =< MaxSize -> 125 {cont,NewAcc,SuccLbl,NewMsOut}; 126 _ -> 127 done 128 end; 129 _ -> 130 done 131 end; 132 _ -> 133 done 134 end; 135 _ -> 136 done 137 end. 138 139calc_size([{_,Size}|Rest]) when is_integer(Size) -> 140 Size + calc_size(Rest); 141calc_size([]) -> 0. 142 143update_code(_Lbl, _, Cfg, [_Info], _Cont, _LastFail, _MsIn, _MsOut) -> 144 Cfg; 145update_code(Lbl, OldLbl, Cfg, Info, Cont, LastFail, MsIn, MsOut) -> 146 BB = hipe_icode_cfg:bb(Cfg, Lbl), 147 ButLast = hipe_bb:butlast(BB), 148 NewVar = hipe_icode:mk_new_var(), 149 Size = calc_size(Info), 150 NewLast = 151 hipe_icode:mk_primop([NewVar,MsOut], 152 {hipe_bs_primop, {bs_get_integer,Size,0}}, 153 [MsIn], 154 OldLbl, 155 LastFail), 156 NewBB = hipe_bb:mk_bb(ButLast++[NewLast]), 157 NewCfg = hipe_icode_cfg:bb_add(Cfg, Lbl, NewBB), 158 fix_rest(Info, NewVar, OldLbl, Cont, NewCfg). 159 160fix_rest(Info, Var, Lbl, Cont, Cfg) -> 161 ButLast = make_butlast(Info, Var), 162 Last = hipe_icode:mk_goto(Cont), 163 NewBB = hipe_bb:mk_bb(ButLast++[Last]), 164 hipe_icode_cfg:bb_add(Cfg, Lbl, NewBB). 165 166make_butlast([{Res,_Size}], Var) -> 167 [hipe_icode:mk_move(Res, Var)]; 168make_butlast([{Res, Size}|Rest], Var) -> 169 NewVar = hipe_icode:mk_new_var(), 170 [hipe_icode:mk_primop([Res], 'band', 171 [Var, hipe_icode:mk_const((1 bsl Size)-1)]), 172 hipe_icode:mk_primop([NewVar], 'bsr', [Var, hipe_icode:mk_const(Size)]) 173 |make_butlast(Rest, NewVar)]. 174 175%%-------------------------------------------------------------------- 176%% Sets 177 178set_from_list([]) -> #{}; 179set_from_list(L) -> 180 maps:from_list([{E, []} || E <- L]). 181 182not_visited([], _) -> []; 183not_visited([E|T], M) -> 184 case M of 185 #{E := _} -> not_visited(T, M); 186 _ -> [E|not_visited(T, M)] 187 end. 188 189set_union(A, B) -> maps:merge(A, B). 190