diff options
Diffstat (limited to 'lib/hipe/arm')
| -rw-r--r-- | lib/hipe/arm/Makefile | 1 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm.erl | 14 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm.hrl | 8 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_assemble.erl | 9 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_cfg.erl | 30 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_defuse.erl | 16 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_encode.erl | 6 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_finalise.erl | 92 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_frame.erl | 126 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_liveness_gpr.erl | 7 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_main.erl | 17 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_pp.erl | 7 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_ra.erl | 45 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_ra_finalise.erl | 43 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_ra_ls.erl | 42 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_ra_naive.erl | 17 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_ra_postconditions.erl | 52 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_registers.erl | 9 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_arm_subst.erl | 127 | ||||
| -rw-r--r-- | lib/hipe/arm/hipe_rtl_to_arm.erl | 148 | 
20 files changed, 495 insertions, 321 deletions
| diff --git a/lib/hipe/arm/Makefile b/lib/hipe/arm/Makefile index 00b6732afa..ed2eccf428 100644 --- a/lib/hipe/arm/Makefile +++ b/lib/hipe/arm/Makefile @@ -61,6 +61,7 @@ MODULES=hipe_arm \  	hipe_arm_ra_naive \  	hipe_arm_ra_postconditions \  	hipe_arm_registers \ +	hipe_arm_subst \  	hipe_rtl_to_arm  HRL_FILES=hipe_arm.hrl diff --git a/lib/hipe/arm/hipe_arm.erl b/lib/hipe/arm/hipe_arm.erl index f34525fa3b..3b090b501a 100644 --- a/lib/hipe/arm/hipe_arm.erl +++ b/lib/hipe/arm/hipe_arm.erl @@ -1,9 +1,5 @@  %%% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm).  -export([ @@ -86,6 +79,9 @@  	 pseudo_move_dst/1,  	 pseudo_move_src/1, +	 mk_pseudo_spill_move/3, +	 is_pseudo_spill_move/1, +  	 mk_pseudo_switch/3,  	 mk_pseudo_tailcall/4, @@ -257,6 +253,10 @@ is_pseudo_move(I) -> case I of #pseudo_move{} -> true; _ -> false end.  pseudo_move_dst(#pseudo_move{dst=Dst}) -> Dst.  pseudo_move_src(#pseudo_move{src=Src}) -> Src. +mk_pseudo_spill_move(Dst, Temp, Src) -> +  #pseudo_spill_move{dst=Dst, temp=Temp, src=Src}. +is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move). +  mk_pseudo_switch(JTab, Index, Labels) ->    #pseudo_switch{jtab=JTab, index=Index, labels=Labels}. diff --git a/lib/hipe/arm/hipe_arm.hrl b/lib/hipe/arm/hipe_arm.hrl index 558174e3fc..be06b1ebd7 100644 --- a/lib/hipe/arm/hipe_arm.hrl +++ b/lib/hipe/arm/hipe_arm.hrl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  %%%--------------------------------------------------------------------  %%% Basic Values: @@ -108,6 +101,7 @@  -record(pseudo_call_prepare, {nrstkargs}).  -record(pseudo_li, {dst, imm, label}).	% pre-generated label for use by the assembler  -record(pseudo_move, {dst, src}). +-record(pseudo_spill_move, {dst, temp, src}).  -record(pseudo_switch, {jtab, index, labels}).  -record(pseudo_tailcall, {funv, arity, stkargs, linkage}).  -record(pseudo_tailcall_prepare, {}). diff --git a/lib/hipe/arm/hipe_arm_assemble.erl b/lib/hipe/arm/hipe_arm_assemble.erl index 4a245cd853..9aa730afa9 100644 --- a/lib/hipe/arm/hipe_arm_assemble.erl +++ b/lib/hipe/arm/hipe_arm_assemble.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm_assemble).  -export([assemble/4]). @@ -38,7 +31,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->  	  || {MFA, Defun} <- CompiledCode],    %%    {ConstAlign,ConstSize,ConstMap,RefsFromConsts} = -    hipe_pack_constants:pack_constants(Code, 4), +    hipe_pack_constants:pack_constants(Code),    %%    {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =      encode(translate(Code, ConstMap), Options), diff --git a/lib/hipe/arm/hipe_arm_cfg.erl b/lib/hipe/arm/hipe_arm_cfg.erl index f2fa0a5164..0bc3df30b9 100644 --- a/lib/hipe/arm/hipe_arm_cfg.erl +++ b/lib/hipe/arm/hipe_arm_cfg.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,26 +11,26 @@  %% 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% -%%  -module(hipe_arm_cfg).  -export([init/1,           labels/1, start_label/1,           succ/2, +         map_bbs/2, fold_bbs/3,           bb/2, bb_add/3]).  -export([postorder/1]).  -export([linearise/1]).  -export([params/1, reverse_postorder/1]).  -export([arity/1]). % for linear scan  %%-export([redirect_jmp/3]). +-export([branch_preds/1]).  %%% these tell cfg.inc what to define (ugly as hell)  -define(BREADTH_ORDER,true).  % for linear scan  -define(PARAMS_NEEDED,true).  -define(START_LABEL_UPDATE_NEEDED,true). +-define(MAP_FOLD_NEEDED,true).  -include("hipe_arm.hrl").  -include("../flow/cfg.hrl"). @@ -80,6 +76,26 @@ branch_successors(Branch) ->      #pseudo_tailcall{} -> []    end. +branch_preds(Branch) -> +  case Branch of +    #pseudo_bc{true_label=TrueLab,false_label=FalseLab,pred=Pred} -> +      [{FalseLab, 1.0-Pred}, {TrueLab, Pred}]; +    #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=[]}} -> +      %% A function can still cause an exception, even if we won't catch it +      [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}]; +    #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=ExnLab}} -> +      CallExnPred = hipe_bb_weights:call_exn_pred(), +      [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}]; +    #pseudo_switch{labels=Labels} -> +      Prob = 1.0/length(Labels), +      [{L, Prob} || L <- Labels]; +    _ -> +      case branch_successors(Branch) of +	[] -> []; +	[Single] -> [{Single, 1.0}] +      end +  end. +  -ifdef(REMOVE_TRIVIAL_BBS_NEEDED).  fails_to(_Instr) -> [].  -endif. diff --git a/lib/hipe/arm/hipe_arm_defuse.erl b/lib/hipe/arm/hipe_arm_defuse.erl index f57b0e601c..652299a514 100644 --- a/lib/hipe/arm/hipe_arm_defuse.erl +++ b/lib/hipe/arm/hipe_arm_defuse.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,13 +11,11 @@  %% 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% -%%  -module(hipe_arm_defuse).  -export([insn_def_all/1, insn_use_all/1]).  -export([insn_def_gpr/1, insn_use_gpr/1]). +-export([insn_defs_all_gpr/1]).  -include("hipe_arm.hrl").  %%% @@ -46,6 +40,7 @@ insn_def_gpr(I) ->      #pseudo_call{} -> call_clobbered_gpr();      #pseudo_li{dst=Dst} -> [Dst];      #pseudo_move{dst=Dst} -> [Dst]; +    #pseudo_spill_move{dst=Dst, temp=Temp} -> [Dst, Temp];      #pseudo_tailcall_prepare{} -> tailcall_clobbered_gpr();      #smull{dstlo=DstLo,dsthi=DstHi,src1=Src1} ->        %% ARM requires DstLo, DstHi, and Src1 to be distinct. @@ -55,6 +50,12 @@ insn_def_gpr(I) ->      _ -> []    end. +insn_defs_all_gpr(I) -> +  case I of +    #pseudo_call{} -> true; +    _ -> false +  end. +  call_clobbered_gpr() ->    [hipe_arm:mk_temp(R, T)     || {R,T} <- hipe_arm_registers:call_clobbered() ++ all_fp_pseudos()]. @@ -83,6 +84,7 @@ insn_use_gpr(I) ->      #pseudo_call{funv=FunV,sdesc=#arm_sdesc{arity=Arity}} ->        funv_use(FunV, arity_use_gpr(Arity));      #pseudo_move{src=Src} -> [Src]; +    #pseudo_spill_move{src=Src} -> [Src];      #pseudo_switch{jtab=JTabR,index=IndexR} -> addtemp(JTabR, [IndexR]);      #pseudo_tailcall{funv=FunV,arity=Arity,stkargs=StkArgs} ->        addargs(StkArgs, addtemps(tailcall_clobbered_gpr(), funv_use(FunV, arity_use_gpr(Arity)))); diff --git a/lib/hipe/arm/hipe_arm_encode.erl b/lib/hipe/arm/hipe_arm_encode.erl index 9368cbf628..dedb6547bb 100644 --- a/lib/hipe/arm/hipe_arm_encode.erl +++ b/lib/hipe/arm/hipe_arm_encode.erl @@ -1,9 +1,5 @@  %%% -*- erlang-indent-level: 2 -*-  %%% -%%% %CopyrightBegin% -%%%  -%%% Copyright Ericsson AB 2005-2016. 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 @@ -15,8 +11,6 @@  %%% 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%  %%%  %%% Encode symbolic ARM instructions to binary form.  %%% Copyright (C) 2005  Mikael Pettersson diff --git a/lib/hipe/arm/hipe_arm_finalise.erl b/lib/hipe/arm/hipe_arm_finalise.erl index a4b2f9c73c..3a6fd5a2dd 100644 --- a/lib/hipe/arm/hipe_arm_finalise.erl +++ b/lib/hipe/arm/hipe_arm_finalise.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,18 +11,19 @@  %% 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% -%%  -module(hipe_arm_finalise). --export([finalise/1]). +-export([finalise/2]).  -include("hipe_arm.hrl"). -finalise(Defun) -> +finalise(Defun, Options) ->    #defun{code=Code0} = Defun, -  Code1 = peep(expand(Code0)), -  Defun#defun{code=Code1}. +  Code1Rev = expand(Code0), +  Code2 = case proplists:get_bool(peephole, Options) of +	    true -> peep(Code1Rev); +	    false -> lists:reverse(Code1Rev) +	  end, +  Defun#defun{code=Code2}.  expand(Insns) ->    expand_list(Insns, []). @@ -34,7 +31,7 @@ expand(Insns) ->  expand_list([I|Insns], Accum) ->    expand_list(Insns, expand_insn(I, Accum));  expand_list([], Accum) -> -  lists:reverse(Accum). +  Accum.  expand_insn(I, Accum) ->    case I of @@ -63,12 +60,67 @@ expand_insn(I, Accum) ->        [I|Accum]    end. -peep(Insns) -> -  peep_list(Insns, []). +%% We do peephole "bottom-up" (in reverse, but applying rules to the correctly +%% ordered list). This way, we can do replacements that would take multiple +%% passes with an in-order peephole optimiser. +%% +%% N.B., if a rule wants to produce multiple instructions (even if some of them +%% are unchanged, it should push the additional instructions on the More list, +%% so that only the top instruction on Insns is new or changed, i.e. tl(Insns) +%% should have been peepholed previously. +peep(RevInsns) -> +  peep_list_skip([], RevInsns). + +peep_list([#b_label{'cond'='al',label=Label} +	   | (Insns = [#label{label=Label}|_])], More) -> +  peep_list_skip(Insns, More); + +peep_list([#move{movop='mov',s=false,dst=#arm_temp{reg=Dst} +		,am1=#arm_temp{reg=Dst}}|Insns], More) -> +  peep_list_skip(Insns, More); + +peep_list([#move{movop='mov',s=false,dst=Dst,am1={Src,lsr,Imm}}, +	   #move{movop='mov',s=false,dst=Dst,am1={Dst,lsl,Imm}} +	   |Insns], More) when Imm > 0, Imm =< 8 -> +  peep_list([#alu{aluop='bic',s=false,dst=Dst,src=Src,am1={(1 bsl Imm)-1,0}} +	    |Insns], More); +peep_list([#move{movop='mov',s=false,dst=Dst,am1={Src,lsl,Imm}}, +	   #move{movop='mov',s=false,dst=Dst,am1={Dst,lsr,Imm}} +	   |Insns], More) when Imm >= 24, Imm < 32 -> +  peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src +		 ,am1={(1 bsl (32-Imm))-1,0}} | Insns], More); + +%% XXX: Load-after-store optimisation should also be applied to RTL, where it +%% can be more general, expose opportunities for constant propagation, etc. +peep_list([#store{stop='strb',src=Src,am2=Mem}=Str, +	   #load {ldop='ldrb',dst=Dst,am2=Mem} | Insns], More) -> +  peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src,am1={16#ff,0}}|Insns], +	    [Str|More]); +peep_list([#store{stop='str',src=Src,am2=Mem}=Str, +	   #load {ldop='ldr',dst=Dst,am2=Mem} | Insns], More) -> +  peep_list([#move{movop='mov',s=false,dst=Dst,am1=Src}|Insns], [Str|More]); + +peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src,am1={Mask,0}}, +	   #alu{aluop='bic',s=false,dst=Dst,src=Dst,am1={InvMask,0}} +	   |Insns], More) -> +  peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src +		 ,am1={Mask band (bnot InvMask),0}} | Insns], More); + +%% XXX: The place that generates brain-dead code like the following should be +%% fixed rather than trying to patch it over here. +peep_list([#load{ldop='ldrb',dst=Dst,am2=_Mem}, +	   #alu{aluop='bic',s=false,dst=Dst,src=Dst,am1={16#ff,0}} +	   | Insns], More) -> +  peep_list([#move{movop='mov',s=false,dst=Dst,am1={0,0}}|Insns], More); + +peep_list(Insns, [I|More]) -> +  peep_list([I|Insns], More); +peep_list(Accum, []) -> +  Accum. -peep_list([#b_label{'cond'='al',label=Label} | (Insns = [#label{label=Label}|_])], Accum) -> -  peep_list(Insns, Accum); -peep_list([I|Insns], Accum) -> -  peep_list(Insns, [I|Accum]); -peep_list([], Accum) -> -  lists:reverse(Accum). +%% Used as an optimisation instead of tailcalling peep_list/2 when Insns has +%% already been peeped or is otherwise uninteresting (such as empty). +peep_list_skip(Insns, [I|More]) -> +  peep_list([I|Insns], More); +peep_list_skip(Accum, []) -> +  Accum. diff --git a/lib/hipe/arm/hipe_arm_frame.erl b/lib/hipe/arm/hipe_arm_frame.erl index e1e441a967..a1004fb609 100644 --- a/lib/hipe/arm/hipe_arm_frame.erl +++ b/lib/hipe/arm/hipe_arm_frame.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm_frame).  -export([frame/1]). @@ -27,16 +20,14 @@  -define(LIVENESS_ALL, hipe_arm_liveness_gpr). % since we have no FP yet -frame(Defun) -> -  Formals = fix_formals(hipe_arm:defun_formals(Defun)), -  Temps0 = all_temps(hipe_arm:defun_code(Defun), Formals), -  MinFrame = defun_minframe(Defun), +frame(CFG) -> +  Formals = fix_formals(hipe_arm_cfg:params(CFG)), +  Temps0 = all_temps(CFG, Formals), +  MinFrame = defun_minframe(CFG),    Temps = ensure_minframe(MinFrame, Temps0), -  ClobbersLR = clobbers_lr(hipe_arm:defun_code(Defun)), -  CFG0 = hipe_arm_cfg:init(Defun), -  Liveness = ?LIVENESS_ALL:analyse(CFG0), -  CFG1 = do_body(CFG0, Liveness, Formals, Temps, ClobbersLR), -  hipe_arm_cfg:linearise(CFG1). +  ClobbersLR = clobbers_lr(CFG), +  Liveness = ?LIVENESS_ALL:analyse(CFG), +  do_body(CFG, Liveness, Formals, Temps, ClobbersLR).  fix_formals(Formals) ->    fix_formals(hipe_arm_registers:nr_args(), Formals). @@ -51,32 +42,21 @@ do_body(CFG0, Liveness, Formals, Temps, ClobbersLR) ->    do_prologue(CFG1, Context).  do_blocks(CFG, Context) -> -  Labels = hipe_arm_cfg:labels(CFG), -  do_blocks(Labels, CFG, Context). +  hipe_arm_cfg:map_bbs(fun(Lbl, BB) -> do_block(Lbl, BB, Context) end, CFG). -do_blocks([Label|Labels], CFG, Context) -> +do_block(Label, Block, Context) ->    Liveness = context_liveness(Context),    LiveOut = ?LIVENESS_ALL:liveout(Liveness, Label), -  Block = hipe_arm_cfg:bb(CFG, Label),    Code = hipe_bb:code(Block), -  NewCode = do_block(Code, LiveOut, Context), -  NewBlock = hipe_bb:code_update(Block, NewCode), -  NewCFG = hipe_arm_cfg:bb_add(CFG, Label, NewBlock), -  do_blocks(Labels, NewCFG, Context); -do_blocks([], CFG, _) -> -  CFG. - -do_block(Insns, LiveOut, Context) -> -  do_block(Insns, LiveOut, Context, context_framesize(Context), []). +  NewCode = do_block(Code, LiveOut, Context, context_framesize(Context), []), +  hipe_bb:code_update(Block, NewCode).  do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) ->    {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0),    do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode));  do_block([], _, Context, FPoff, RevCode) ->    FPoff0 = context_framesize(Context), -  if FPoff =:= FPoff0 -> []; -     true -> exit({?MODULE,do_block,FPoff}) -  end, +  FPoff0 = FPoff,    lists:reverse(RevCode, []).  do_insn(I, LiveOut, Context, FPoff) -> @@ -89,6 +69,8 @@ do_insn(I, LiveOut, Context, FPoff) ->        do_pseudo_call_prepare(I, FPoff);      #pseudo_move{} ->        {do_pseudo_move(I, Context, FPoff), FPoff}; +    #pseudo_spill_move{} -> +      {do_pseudo_spill_move(I, Context, FPoff), FPoff};      #pseudo_tailcall{} ->        {do_pseudo_tailcall(I, Context), context_framesize(Context)};      _ -> @@ -120,6 +102,26 @@ pseudo_offset(Temp, FPoff, Context) ->    FPoff + context_offset(Context, Temp).  %%% +%%% Moves from one spill slot to another +%%% + +do_pseudo_spill_move(I, Context, FPoff) -> +  #pseudo_spill_move{dst=Dst, temp=Temp, src=Src} = I, +  case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of +    false -> % Register allocator changed its mind, turn back to move +      do_pseudo_move(hipe_arm:mk_pseudo_move(Dst, Src), Context, FPoff); +    true -> +      SrcOffset = pseudo_offset(Src, FPoff, Context), +      DstOffset = pseudo_offset(Dst, FPoff, Context), +      case SrcOffset =:= DstOffset of +	true -> []; % omit move-to-self +	false -> +	  mk_load('ldr', Temp, SrcOffset, mk_sp(), +		  mk_store('str', Temp, DstOffset, mk_sp(), [])) +      end +  end. + +%%%  %%% Return - deallocate frame and emit 'ret $N' insn.  %%% @@ -543,39 +545,46 @@ temp_is_pseudo(Temp) ->  %%% Detect if a Defun's body clobbers LR.  %%% -clobbers_lr(Insns) -> +clobbers_lr(CFG) ->    LRreg = hipe_arm_registers:lr(),    LRtagged = hipe_arm:mk_temp(LRreg, 'tagged'),    LRuntagged = hipe_arm:mk_temp(LRreg, 'untagged'), -  clobbers_lr(Insns, LRtagged, LRuntagged). - -clobbers_lr([I|Insns], LRtagged, LRuntagged) -> -  Defs = hipe_arm_defuse:insn_def_gpr(I), -  case lists:member(LRtagged, Defs) of -    true -> true; -    false -> -      case lists:member(LRuntagged, Defs) of -	true -> true; -	false -> clobbers_lr(Insns, LRtagged, LRuntagged) -      end -  end; -clobbers_lr([], _LRtagged, _LRuntagged) -> false. +  any_insn(fun(I) -> +	       Defs = hipe_arm_defuse:insn_def_gpr(I), +	       lists:member(LRtagged, Defs) +		 orelse lists:member(LRuntagged, Defs) +	   end, CFG). + +any_insn(Pred, CFG) -> +  %% Abuse fold to do an efficient "any"-operation using nonlocal control flow +  FoundSatisfying = make_ref(), +  try fold_insns(fun (I, _) -> +		     case Pred(I) of +		       true -> throw(FoundSatisfying); +		       false -> false +		     end +		 end, false, CFG) +  of _ -> false +  catch FoundSatisfying -> true +  end.  %%%  %%% Build the set of all temps used in a Defun's body.  %%% -all_temps(Code, Formals) -> -  S0 = find_temps(Code, tset_empty()), +all_temps(CFG, Formals) -> +  S0 = fold_insns(fun find_temps/2, tset_empty(), CFG),    S1 = tset_del_list(S0, Formals),    tset_filter(S1, fun(T) -> temp_is_pseudo(T) end). -find_temps([I|Insns], S0) -> +find_temps(I, S0) ->    S1 = tset_add_list(S0, hipe_arm_defuse:insn_def_all(I)), -  S2 = tset_add_list(S1, hipe_arm_defuse:insn_use_all(I)), -  find_temps(Insns, S2); -find_temps([], S) -> -  S. +  tset_add_list(S1, hipe_arm_defuse:insn_use_all(I)). + +fold_insns(Fun, InitAcc, CFG) -> +  hipe_arm_cfg:fold_bbs( +    fun(_, BB, Acc0) -> lists:foldl(Fun, Acc0, hipe_bb:code(BB)) end, +    InitAcc, CFG).  tset_empty() ->    gb_sets:new(). @@ -604,16 +613,11 @@ tset_to_list(S) ->  %%% in the middle of a tailcall.  %%% -defun_minframe(Defun) -> -  MaxTailArity = body_mta(hipe_arm:defun_code(Defun), 0), -  MyArity = length(fix_formals(hipe_arm:defun_formals(Defun))), +defun_minframe(CFG) -> +  MaxTailArity = fold_insns(fun insn_mta/2, 0, CFG), +  MyArity = length(fix_formals(hipe_arm_cfg:params(CFG))),    erlang:max(MaxTailArity - MyArity, 0). -body_mta([I|Code], MTA) -> -  body_mta(Code, insn_mta(I, MTA)); -body_mta([], MTA) -> -  MTA. -  insn_mta(I, MTA) ->    case I of      #pseudo_tailcall{arity=Arity} -> diff --git a/lib/hipe/arm/hipe_arm_liveness_gpr.erl b/lib/hipe/arm/hipe_arm_liveness_gpr.erl index 82cc5a7a67..ae845e5385 100644 --- a/lib/hipe/arm/hipe_arm_liveness_gpr.erl +++ b/lib/hipe/arm/hipe_arm_liveness_gpr.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm_liveness_gpr).  -export([analyse/1]). diff --git a/lib/hipe/arm/hipe_arm_main.erl b/lib/hipe/arm/hipe_arm_main.erl index dce1193b24..b87a300a9d 100644 --- a/lib/hipe/arm/hipe_arm_main.erl +++ b/lib/hipe/arm/hipe_arm_main.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,24 +11,23 @@  %% 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% -%%  -module(hipe_arm_main).  -export([rtl_to_arm/3]).  rtl_to_arm(MFA, RTL, Options) ->    Defun1 = hipe_rtl_to_arm:translate(RTL), +  CFG1 = hipe_arm_cfg:init(Defun1),    %% io:format("~w: after translate\n", [?MODULE]),    %% hipe_arm_pp:pp(Defun1), -  Defun2 = hipe_arm_ra:ra(Defun1, Options), +  CFG2 = hipe_arm_ra:ra(CFG1, Options),    %% io:format("~w: after regalloc\n", [?MODULE]), -  %% hipe_arm_pp:pp(Defun2), -  Defun3 = hipe_arm_frame:frame(Defun2), +  %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG2)), +  CFG3 = hipe_arm_frame:frame(CFG2), +  Defun3 = hipe_arm_cfg:linearise(CFG3),    %% io:format("~w: after frame\n", [?MODULE]),    %% hipe_arm_pp:pp(Defun3), -  Defun4 = hipe_arm_finalise:finalise(Defun3), +  Defun4 = hipe_arm_finalise:finalise(Defun3, Options),    %% io:format("~w: after finalise\n", [?MODULE]),    pp(Defun4, MFA, Options),    {native, arm, {unprofiled, Defun4}}. diff --git a/lib/hipe/arm/hipe_arm_pp.erl b/lib/hipe/arm/hipe_arm_pp.erl index 18aca1fc6b..f49e998d06 100644 --- a/lib/hipe/arm/hipe_arm_pp.erl +++ b/lib/hipe/arm/hipe_arm_pp.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm_pp).  -export([pp/1, pp/2, pp_insn/1]). diff --git a/lib/hipe/arm/hipe_arm_ra.erl b/lib/hipe/arm/hipe_arm_ra.erl index 2f65e864fd..b360fc05c4 100644 --- a/lib/hipe/arm/hipe_arm_ra.erl +++ b/lib/hipe/arm/hipe_arm_ra.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,43 +11,44 @@  %% 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% -%%  -module(hipe_arm_ra).  -export([ra/2]). -ra(Defun0, Options) -> -  %% hipe_arm_pp:pp(Defun0), -  {Defun1, Coloring_fp, SpillIndex} +ra(CFG0, Options) -> +  %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG0)), +  {CFG1, _FPLiveness1, Coloring_fp, SpillIndex}      = case proplists:get_bool(inline_fp, Options) of  %%	true -> -%%	  hipe_regalloc_loop:ra_fp(Defun0, Options, +%%	  FPLiveness0 = hipe_arm_specific_fp:analyze(CFG0, no_context), +%%	  hipe_regalloc_loop:ra_fp(CFG0, FPLiveness0, Options,  %%				   hipe_coalescing_regalloc, -%%				   hipe_arm_specific_fp); +%%				   hipe_arm_specific_fp, no_context);  	false -> -	  {Defun0,[],0} +	  {CFG0,undefined,[],0}        end, -  %% hipe_arm_pp:pp(Defun1), -  {Defun2, Coloring} +  %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG1)), +  GPLiveness1 = hipe_arm_specific:analyze(CFG1, no_context), +  {CFG2, _GPLiveness2, Coloring}      = case proplists:get_value(regalloc, Options, coalescing) of  	coalescing -> -	  ra(Defun1, SpillIndex, Options, hipe_coalescing_regalloc); +	  ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_coalescing_regalloc);  	optimistic -> -	  ra(Defun1, SpillIndex, Options, hipe_optimistic_regalloc); +	  ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_optimistic_regalloc);  	graph_color -> -	  ra(Defun1, SpillIndex, Options, hipe_graph_coloring_regalloc); +	  ra(CFG1, GPLiveness1, SpillIndex, Options, +	     hipe_graph_coloring_regalloc);  	linear_scan -> -	  hipe_arm_ra_ls:ra(Defun1, SpillIndex, Options); +	  hipe_arm_ra_ls:ra(CFG1, GPLiveness1, SpillIndex, Options);  	naive -> -	  hipe_arm_ra_naive:ra(Defun1, Coloring_fp, Options); +	  hipe_arm_ra_naive:ra(CFG1, GPLiveness1, Coloring_fp, Options);          _ ->  	  exit({unknown_regalloc_compiler_option,  		proplists:get_value(regalloc,Options)})        end, -  %% hipe_arm_pp:pp(Defun2), -  hipe_arm_ra_finalise:finalise(Defun2, Coloring, Coloring_fp). +  %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG2)), +  hipe_arm_ra_finalise:finalise(CFG2, Coloring, Coloring_fp). -ra(Defun, SpillIndex, Options, RegAllocMod) -> -  hipe_regalloc_loop:ra(Defun, SpillIndex, Options, RegAllocMod, hipe_arm_specific). +ra(CFG, Liveness, SpillIndex, Options, RegAllocMod) -> +  hipe_regalloc_loop:ra(CFG, Liveness, SpillIndex, Options, RegAllocMod, +			hipe_arm_specific, no_context). diff --git a/lib/hipe/arm/hipe_arm_ra_finalise.erl b/lib/hipe/arm/hipe_arm_ra_finalise.erl index 4faeadcd7f..80cd470708 100644 --- a/lib/hipe/arm/hipe_arm_ra_finalise.erl +++ b/lib/hipe/arm/hipe_arm_ra_finalise.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,27 +11,31 @@  %% 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% -%%  -module(hipe_arm_ra_finalise).  -export([finalise/3]).  -include("hipe_arm.hrl"). -finalise(Defun, TempMap, _FPMap0=[]) -> -  Code = hipe_arm:defun_code(Defun), -  {_, SpillLimit} = hipe_arm:defun_var_range(Defun), +finalise(CFG, TempMap, _FPMap0=[]) -> +  {_, SpillLimit} = hipe_gensym:var_range(arm),    Map = mk_ra_map(TempMap, SpillLimit), -  NewCode = ra_code(Code, Map, []), -  Defun#defun{code=NewCode}. +  hipe_arm_cfg:map_bbs(fun(_Lbl, BB) -> ra_bb(BB, Map) end, CFG). + +ra_bb(BB, Map) -> +  hipe_bb:code_update(BB, ra_code(hipe_bb:code(BB), Map, [])).  ra_code([I|Insns], Map, Accum) -> -  ra_code(Insns, Map, [ra_insn(I, Map) | Accum]); +  ra_code(Insns, Map, ra_insn(I, Map, Accum));  ra_code([], _Map, Accum) ->    lists:reverse(Accum). -ra_insn(I, Map) -> +ra_insn(I, Map, Accum) -> +  case I of +    #pseudo_move{} -> ra_pseudo_move(I, Map, Accum); +    _ -> [ra_insn_1(I, Map) | Accum] +  end. + +ra_insn_1(I, Map) ->    case I of      #alu{} -> ra_alu(I, Map);      #cmp{} -> ra_cmp(I, Map); @@ -44,7 +44,7 @@ ra_insn(I, Map) ->      #move{} -> ra_move(I, Map);      #pseudo_call{} -> ra_pseudo_call(I, Map);      #pseudo_li{} -> ra_pseudo_li(I, Map); -    #pseudo_move{} -> ra_pseudo_move(I, Map); +    #pseudo_spill_move{} -> ra_pseudo_spill_move(I, Map);      #pseudo_switch{} -> ra_pseudo_switch(I, Map);      #pseudo_tailcall{} -> ra_pseudo_tailcall(I, Map);      #smull{} -> ra_smull(I, Map); @@ -86,10 +86,19 @@ ra_pseudo_li(I=#pseudo_li{dst=Dst}, Map) ->    NewDst = ra_temp(Dst, Map),    I#pseudo_li{dst=NewDst}. -ra_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, Map) -> +ra_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, Map, Accum) -> +  NewDst = ra_temp(Dst, Map), +  NewSrc = ra_temp(Src, Map), +  case NewSrc#arm_temp.reg =:= NewDst#arm_temp.reg of +    true -> Accum; +    false -> [I#pseudo_move{dst=NewDst,src=NewSrc} | Accum] +  end. + +ra_pseudo_spill_move(I=#pseudo_spill_move{dst=Dst,temp=Temp,src=Src}, Map) ->    NewDst = ra_temp(Dst, Map), +  NewTemp = ra_temp(Temp, Map),    NewSrc = ra_temp(Src, Map), -  I#pseudo_move{dst=NewDst,src=NewSrc}. +  I#pseudo_spill_move{dst=NewDst, temp=NewTemp, src=NewSrc}.  ra_pseudo_switch(I=#pseudo_switch{jtab=JTab,index=Index}, Map) ->    NewJTab = ra_temp(JTab, Map), diff --git a/lib/hipe/arm/hipe_arm_ra_ls.erl b/lib/hipe/arm/hipe_arm_ra_ls.erl index d9a360d00c..bbb75f9c55 100644 --- a/lib/hipe/arm/hipe_arm_ra_ls.erl +++ b/lib/hipe/arm/hipe_arm_ra_ls.erl @@ -1,9 +1,5 @@  %%% -*- erlang-indent-level: 2 -*-  %%% -%%% %CopyrightBegin% -%%%  -%%% Copyright Ericsson AB 2006-2016. 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 @@ -15,43 +11,39 @@  %%% 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%  %%%  %%% Linear Scan register allocator for ARM  -module(hipe_arm_ra_ls). --export([ra/3]). +-export([ra/4]). -ra(Defun, SpillIndex, Options) -> -  NewDefun = Defun, %% hipe_${ARCH}_ra_rename:rename(Defun,Options), -  CFG = hipe_arm_cfg:init(NewDefun), -  SpillLimit = hipe_arm_specific:number_of_temporaries(CFG), -  alloc(NewDefun, SpillIndex, SpillLimit, Options). +ra(CFG, Liveness, SpillIndex, Options) -> +  SpillLimit = hipe_arm_specific:number_of_temporaries(CFG, no_context), +  alloc(CFG, Liveness, SpillIndex, SpillLimit, Options). -alloc(Defun, SpillIndex, SpillLimit, Options) -> -  CFG = hipe_arm_cfg:init(Defun), +alloc(CFG, Liveness, SpillIndex, SpillLimit, Options) ->    {Coloring, _NewSpillIndex} =      regalloc( -      CFG, +      CFG, Liveness,        hipe_arm_registers:allocatable_gpr()--        [hipe_arm_registers:temp3(),         hipe_arm_registers:temp2(),         hipe_arm_registers:temp1()],        [hipe_arm_cfg:start_label(CFG)],        SpillIndex, SpillLimit, Options, -      hipe_arm_specific), -  {NewDefun, _DidSpill} = +      hipe_arm_specific, no_context), +  {NewCFG, _DidSpill} =      hipe_arm_ra_postconditions:check_and_rewrite( -      Defun, Coloring, 'linearscan'), -  TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific), +      CFG, Coloring, 'linearscan'), +  TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific, no_context),    {SpillMap, _NewSpillIndex2} = -    hipe_spillmin:stackalloc(CFG, [], SpillIndex, Options, -			     hipe_arm_specific, TempMap), +    hipe_spillmin:stackalloc(CFG, Liveness, [], SpillIndex, Options, +			     hipe_arm_specific, no_context, TempMap),    Coloring2 =      hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), SpillMap), -  {NewDefun, Coloring2}. +  {NewCFG, Liveness, Coloring2}. -regalloc(CFG, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options, Target) -> -  hipe_ls_regalloc:regalloc( -    CFG, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options, Target). +regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options, +	 TgtMod, TgtCtx) -> +  hipe_ls_regalloc:regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, +			    DontSpill, Options, TgtMod, TgtCtx). diff --git a/lib/hipe/arm/hipe_arm_ra_naive.erl b/lib/hipe/arm/hipe_arm_ra_naive.erl index 6201269f44..e3fe9877ad 100644 --- a/lib/hipe/arm/hipe_arm_ra_naive.erl +++ b/lib/hipe/arm/hipe_arm_ra_naive.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,16 +11,13 @@  %% 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% -%%  -module(hipe_arm_ra_naive). --export([ra/3]). +-export([ra/4]).  -include("hipe_arm.hrl"). -ra(Defun, _Coloring_fp, _Options) ->	% -> {Defun, Coloring} -  {NewDefun,_DidSpill} = -    hipe_arm_ra_postconditions:check_and_rewrite2(Defun, [], 'naive'), -  {NewDefun, []}. +ra(CFG, Liveness, _Coloring_fp, _Options) ->	% -> {CFG, Liveness, Coloring} +  {NewCFG,_DidSpill} = +    hipe_arm_ra_postconditions:check_and_rewrite2(CFG, [], 'naive'), +  {NewCFG, Liveness, []}. diff --git a/lib/hipe/arm/hipe_arm_ra_postconditions.erl b/lib/hipe/arm/hipe_arm_ra_postconditions.erl index 40978e65f6..23c305511f 100644 --- a/lib/hipe/arm/hipe_arm_ra_postconditions.erl +++ b/lib/hipe/arm/hipe_arm_ra_postconditions.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm_ra_postconditions). @@ -25,17 +18,13 @@  -include("hipe_arm.hrl"). -check_and_rewrite(Defun, Coloring, Allocator) -> -  TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific), -  check_and_rewrite2(Defun, TempMap, Allocator). +check_and_rewrite(CFG, Coloring, Allocator) -> +  TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific, no_context), +  check_and_rewrite2(CFG, TempMap, Allocator). -check_and_rewrite2(Defun, TempMap, Allocator) -> +check_and_rewrite2(CFG, TempMap, Allocator) ->    Strategy = strategy(Allocator), -  #defun{code=Code0} = Defun, -  {Code1,DidSpill} = do_insns(Code0, TempMap, Strategy, [], false), -  VarRange = {0, hipe_gensym:get_var(arm)}, -  {Defun#defun{code=Code1, var_range=VarRange}, -   DidSpill}. +  do_bbs(hipe_arm_cfg:labels(CFG), TempMap, Strategy, CFG, false).  strategy(Allocator) ->    case Allocator of @@ -44,6 +33,13 @@ strategy(Allocator) ->      'naive' -> 'fixed'    end. +do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill}; +do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) -> +  Code0 = hipe_bb:code(BB = hipe_arm_cfg:bb(CFG0, Lbl)), +  {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0), +  CFG = hipe_arm_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)), +  do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill). +  do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->    {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),    do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1); @@ -60,6 +56,7 @@ do_insn(I, TempMap, Strategy) ->      #pseudo_call{} -> do_pseudo_call(I, TempMap, Strategy);      #pseudo_li{} -> do_pseudo_li(I, TempMap, Strategy);      #pseudo_move{} -> do_pseudo_move(I, TempMap, Strategy); +    #pseudo_spill_move{} -> do_pseudo_spill_move(I, TempMap, Strategy);      #pseudo_switch{} -> do_pseudo_switch(I, TempMap, Strategy);      #pseudo_tailcall{} -> do_pseudo_tailcall(I, TempMap, Strategy);      #smull{} -> do_smull(I, TempMap, Strategy); @@ -112,18 +109,25 @@ do_pseudo_li(I=#pseudo_li{dst=Dst}, TempMap, Strategy) ->  do_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, TempMap, Strategy) ->    %% Either Dst or Src (but not both) may be a pseudo temp. -  %% pseudo_move and pseudo_tailcall are special cases: in -  %% all other instructions, all temps must be non-pseudos -  %% after register allocation. -  case temp_is_spilled(Dst, TempMap) of -    true -> % Src must not be a pseudo -      {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy), -      NewI = I#pseudo_move{src=NewSrc}, -      {FixSrc ++ [NewI], DidSpill}; +  %% pseudo_move, pseudo_spill_move, and pseudo_tailcall +  %% are special cases: in all other instructions, all +  %% temps must be non-pseudos after register allocation. +  case temp_is_spilled(Dst, TempMap) +    andalso temp_is_spilled(Dst, TempMap) +  of +    true -> % Turn into pseudo_spill_move +      Temp = clone(Src, temp1(Strategy)), +      NewI = #pseudo_spill_move{dst=Dst, temp=Temp, src=Src}, +      {[NewI], true};      _ ->        {[I], false}    end. +do_pseudo_spill_move(I = #pseudo_spill_move{temp=Temp}, TempMap, _Strategy) -> +  %% Temp is above the low water mark and must not have been spilled +  false = temp_is_spilled(Temp, TempMap), +  {[I], false}. % nothing to do +  do_pseudo_switch(I=#pseudo_switch{jtab=JTab,index=Index}, TempMap, Strategy) ->    {FixJTab,NewJTab,DidSpill1} = fix_src1(JTab, TempMap, Strategy),    {FixIndex,NewIndex,DidSpill2} = fix_src2(Index, TempMap, Strategy), diff --git a/lib/hipe/arm/hipe_arm_registers.erl b/lib/hipe/arm/hipe_arm_registers.erl index dcf039676b..59545c2e64 100644 --- a/lib/hipe/arm/hipe_arm_registers.erl +++ b/lib/hipe/arm/hipe_arm_registers.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_arm_registers). @@ -180,6 +173,8 @@ is_arg(R) ->      _ -> false    end. +%% Note: the fact that allocatable_gpr() is a subset of call_clobbered() is +%% hard-coded in hipe_arm_defuse:insn_defs_all_gpr/1  call_clobbered() ->		% does the RA strip the type or not?    [{?R0,tagged},{?R0,untagged},     {?R1,tagged},{?R1,untagged}, diff --git a/lib/hipe/arm/hipe_arm_subst.erl b/lib/hipe/arm/hipe_arm_subst.erl new file mode 100644 index 0000000000..4ff245f414 --- /dev/null +++ b/lib/hipe/arm/hipe_arm_subst.erl @@ -0,0 +1,127 @@ +%% -*- erlang-indent-level: 2 -*- +%% +%% 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. + +-module(hipe_arm_subst). +-export([insn_temps/2, insn_lbls/2]). +-include("hipe_arm.hrl"). + +%% These should be moved to hipe_arm and exported +-type temp()    :: #arm_temp{}. +-type shiftop() :: lsl | lsr | asr | ror. +-type imm4()    :: 0..15. +-type imm5()    :: 0..31. +-type imm8()    :: 0..255. +-type am1()     :: {imm8(),imm4()} +		 | temp() +		 | {temp(), rrx} +		 | {temp(), shiftop(), imm5()} +		 | {temp(), shiftop(), temp()}. +-type am2()     :: #am2{}. +-type am3()     :: #am3{}. +-type arg()     :: temp() | integer(). +-type funv()    :: #arm_mfa{} | #arm_prim{} | temp(). +-type label()   :: non_neg_integer(). +-type insn()    :: tuple(). % for now + +-type subst_fun() :: fun((temp()) -> temp()). + +%% @doc Maps over the temporaries in an instruction +-spec insn_temps(subst_fun(), insn()) -> insn(). +insn_temps(T, I) -> +  AM1 = fun(O) -> am1_temps(T, O) end, +  AM2 = fun(O) -> am2_temps(T, O) end, +  AM3 = fun(O) -> am3_temps(T, O) end, +  Arg = fun(O) -> arg_temps(T, O) end, +  case I of +      #alu  {dst=D,src=L,am1=R} -> I#alu{dst=T(D),src=T(L),am1=AM1(R)}; +      #cmp        {src=L,am1=R} -> I#cmp         {src=T(L),am1=AM1(R)}; +      #load       {dst=D,am2=S} -> I#load        {dst=T(D),am2=AM2(S)}; +      #ldrsb      {dst=D,am3=S} -> I#ldrsb       {dst=T(D),am3=AM3(S)}; +      #move       {dst=D,am1=S} -> I#move        {dst=T(D),am1=AM1(S)}; +      #pseudo_move{dst=D,src=S} -> I#pseudo_move {dst=T(D),src=T(S)}; +      #store      {src=S,am2=D} -> I#store       {src=T(S),am2=AM2(D)}; +      #b_label{} -> I; +      #comment{} -> I; +      #label{} -> I; +      #pseudo_bc{} -> I; +      #pseudo_blr{} -> I; +      #pseudo_call{funv=F} -> I#pseudo_call{funv=funv_temps(T, F)}; +      #pseudo_call_prepare{} -> I; +      #pseudo_li{dst=D} -> I#pseudo_li{dst=T(D)}; +      #pseudo_spill_move{dst=D,temp=U,src=S} -> +	  I#pseudo_spill_move{dst=T(D),temp=T(U),src=T(S)}; +      #pseudo_switch{jtab=J=#arm_temp{},index=Ix=#arm_temp{}} -> +	  I#pseudo_switch{jtab=T(J),index=T(Ix)}; +      #pseudo_tailcall{funv=F,stkargs=Stk} -> +	  I#pseudo_tailcall{funv=funv_temps(T,F),stkargs=lists:map(Arg,Stk)}; +      #pseudo_tailcall_prepare{} -> I; +      #smull{dstlo=DL,dsthi=DH,src1=L,src2=R} -> +	  I#smull{dstlo=T(DL),dsthi=T(DH),src1=T(L),src2=T(R)} +  end. + +-spec am1_temps(subst_fun(), am1()) -> am1(). +am1_temps(_SubstTemp, T={C,R}) when is_integer(C), is_integer(R) -> T; +am1_temps(SubstTemp, T=#arm_temp{}) -> SubstTemp(T); +am1_temps(SubstTemp, {T=#arm_temp{},rrx}) -> {SubstTemp(T),rrx}; +am1_temps(SubstTemp, {A=#arm_temp{},Op,B=#arm_temp{}}) when is_atom(Op) -> +    {SubstTemp(A),Op,SubstTemp(B)}; +am1_temps(SubstTemp, {T=#arm_temp{},Op,I}) when is_atom(Op), is_integer(I) -> +    {SubstTemp(T),Op,I}. + +-spec am2_temps(subst_fun(), am2()) -> am2(). +am2_temps(SubstTemp, T=#am2{src=A=#arm_temp{},offset=O0}) -> +    O = case O0 of +	    _ when is_integer(O0) -> O0; +	    #arm_temp{} -> SubstTemp(O0); +	    {B=#arm_temp{},rrx} -> {SubstTemp(B),rrx}; +	    {B=#arm_temp{},Op,I} when is_atom(Op), is_integer(I) -> +		{SubstTemp(B),Op,I} +	end, +    T#am2{src=SubstTemp(A),offset=O}. + +-spec am3_temps(subst_fun(), am3()) -> am3(). +am3_temps(SubstTemp, T=#am3{src=A=#arm_temp{},offset=O0}) -> +    O = case O0 of +	    _ when is_integer(O0) -> O0; +	    #arm_temp{} -> SubstTemp(O0) +	end, +    T#am3{src=SubstTemp(A),offset=O}. + +-spec funv_temps(subst_fun(), funv()) -> funv(). +funv_temps(_SubstTemp, M=#arm_mfa{}) -> M; +funv_temps(_SubstTemp, P=#arm_prim{}) -> P; +funv_temps(SubstTemp,  T=#arm_temp{}) -> SubstTemp(T). + +-spec arg_temps(subst_fun(), arg()) -> arg(). +arg_temps(_SubstTemp, Imm) when is_integer(Imm) -> Imm; +arg_temps(SubstTemp,  T=#arm_temp{}) -> SubstTemp(T). + +-type lbl_subst_fun() :: fun((label()) -> label()). + +%% @doc Maps over the branch targets in an instruction +-spec insn_lbls(lbl_subst_fun(), insn()) -> insn(). +insn_lbls(SubstLbl, I) -> +  case I of +    #b_label{label=Label} -> +      I#b_label{label=SubstLbl(Label)}; +    #pseudo_bc{true_label=T, false_label=F} -> +      I#pseudo_bc{true_label=SubstLbl(T), false_label=SubstLbl(F)}; +    #pseudo_call{sdesc=Sdesc, contlab=Contlab} -> +      I#pseudo_call{sdesc=sdesc_lbls(SubstLbl, Sdesc), +		    contlab=SubstLbl(Contlab)} +  end. + +sdesc_lbls(_SubstLbl, Sdesc=#arm_sdesc{exnlab=[]}) -> Sdesc; +sdesc_lbls(SubstLbl, Sdesc=#arm_sdesc{exnlab=Exnlab}) -> +  Sdesc#arm_sdesc{exnlab=SubstLbl(Exnlab)}. diff --git a/lib/hipe/arm/hipe_rtl_to_arm.erl b/lib/hipe/arm/hipe_rtl_to_arm.erl index 93342aba33..59e0a79b0d 100644 --- a/lib/hipe/arm/hipe_rtl_to_arm.erl +++ b/lib/hipe/arm/hipe_rtl_to_arm.erl @@ -1,9 +1,5 @@  %% -*- erlang-indent-level: 2 -*-  %% -%% %CopyrightBegin% -%%  -%% Copyright Ericsson AB 2005-2016. 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 @@ -15,9 +11,6 @@  %% 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% -%%  -module(hipe_rtl_to_arm).  -export([translate/1]). @@ -62,7 +55,6 @@ conv_insn(I, Map, Data) ->    case I of      #alu{} -> conv_alu(I, Map, Data);      #alub{} -> conv_alub(I, Map, Data); -    #branch{} -> conv_branch(I, Map, Data);      #call{} -> conv_call(I, Map, Data);      #comment{} -> conv_comment(I, Map, Data);      #enter{} -> conv_enter(I, Map, Data); @@ -111,6 +103,17 @@ commute_arithop(ArithOp) ->      _ -> ArithOp    end. +conv_cmpop('add') -> 'cmn'; +conv_cmpop('sub') -> 'cmp'; +conv_cmpop('and') -> 'tst'; +conv_cmpop('xor') -> 'teq'; +conv_cmpop(_) -> none. + +cmpop_commutes('cmp') -> false; +cmpop_commutes('cmn') -> true; +cmpop_commutes('tst') -> true; +cmpop_commutes('teq') -> true. +  mk_alu(S, Dst, Src1, RtlAluOp, Src2) ->    case hipe_rtl:is_shift_op(RtlAluOp) of      true -> @@ -138,7 +141,6 @@ mk_shift(S, Dst, Src1, ShiftOp, Src2) ->    end.  mk_shift_ii(S, Dst, Src1, ShiftOp, Src2) -> -  io:format("~w: RTL alu with two immediates\n", [?MODULE]),    Tmp = new_untagged_temp(),    mk_li(Tmp, Src1,  	mk_shift_ri(S, Dst, Tmp, ShiftOp, Src2)). @@ -179,7 +181,6 @@ mk_arith(S, Dst, Src1, ArithOp, Src2) ->    end.  mk_arith_ii(S, Dst, Src1, ArithOp, Src2) -> -  io:format("~w: RTL alu with two immediates\n", [?MODULE]),    Tmp = new_untagged_temp(),    mk_li(Tmp, Src1,  	mk_arith_ri(S, Dst, Tmp, ArithOp, Src2)). @@ -225,72 +226,77 @@ fix_aluop_imm(AluOp, Imm) -> % {FixAm1,NewAluOp,Am1}  conv_alub(I, Map, Data) ->    %% dst = src1 aluop src2; if COND goto label -  {Dst, Map0} = conv_dst(hipe_rtl:alub_dst(I), Map), -  {Src1, Map1} = conv_src(hipe_rtl:alub_src1(I), Map0), -  {Src2, Map2} = conv_src(hipe_rtl:alub_src2(I), Map1), +  {Src1, Map0} = conv_src(hipe_rtl:alub_src1(I), Map), +  {Src2, Map1} = conv_src(hipe_rtl:alub_src2(I), Map0),    RtlAluOp = hipe_rtl:alub_op(I), -  Cond0 = conv_alub_cond(RtlAluOp, hipe_rtl:alub_cond(I)), -  Cond = -    case {RtlAluOp,Cond0} of -      {'mul','vs'} -> 'ne';	% overflow becomes not-equal -      {'mul','vc'} -> 'eq';	% no-overflow becomes equal -      {'mul',_} -> exit({?MODULE,I}); -      {_,_} -> Cond0 -    end, -  I2 = mk_pseudo_bc( -	  Cond, -	  hipe_rtl:alub_true_label(I), -	  hipe_rtl:alub_false_label(I), -	  hipe_rtl:alub_pred(I)), -  S = true, -  I1 = mk_alu(S, Dst, Src1, RtlAluOp, Src2), -  {I1 ++ I2, Map2, Data}. - -conv_branch(I, Map, Data) -> -  %% <unused> = src1 - src2; if COND goto label -  {Src1, Map0} = conv_src(hipe_rtl:branch_src1(I), Map), -  {Src2, Map1} = conv_src(hipe_rtl:branch_src2(I), Map0), -  Cond = conv_branch_cond(hipe_rtl:branch_cond(I)), -  I2 = mk_branch(Src1, Cond, Src2, -		 hipe_rtl:branch_true_label(I), -		 hipe_rtl:branch_false_label(I), -		 hipe_rtl:branch_pred(I)), -  {I2, Map1, Data}. +  RtlCond = hipe_rtl:alub_cond(I), +  HasDst = hipe_rtl:alub_has_dst(I), +  CmpOp = conv_cmpop(RtlAluOp), +  Cond0 = conv_alub_cond(RtlAluOp, RtlCond), +  case (not HasDst) andalso CmpOp =/= none of +    true -> +      I1 = mk_branch(Src1, CmpOp, Src2, Cond0, +		     hipe_rtl:alub_true_label(I), +		     hipe_rtl:alub_false_label(I), +		     hipe_rtl:alub_pred(I)), +      {I1, Map1, Data}; +    false -> +      {Dst, Map2} = +	case HasDst of +	  false -> {new_untagged_temp(), Map1}; +	  true -> conv_dst(hipe_rtl:alub_dst(I), Map1) +	end, +      Cond = +	case {RtlAluOp,Cond0} of +	  {'mul','vs'} -> 'ne';	% overflow becomes not-equal +	  {'mul','vc'} -> 'eq';	% no-overflow becomes equal +	  {'mul',_} -> exit({?MODULE,I}); +	  {_,_} -> Cond0 +	end, +      I2 = mk_pseudo_bc( +	     Cond, +	     hipe_rtl:alub_true_label(I), +	     hipe_rtl:alub_false_label(I), +	     hipe_rtl:alub_pred(I)), +      S = true, +      I1 = mk_alu(S, Dst, Src1, RtlAluOp, Src2), +      {I1 ++ I2, Map2, Data} +  end. -mk_branch(Src1, Cond, Src2, TrueLab, FalseLab, Pred) -> +mk_branch(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred) ->    case hipe_arm:is_temp(Src1) of      true ->        case hipe_arm:is_temp(Src2) of  	true -> -	  mk_branch_rr(Src1, Src2, Cond, TrueLab, FalseLab, Pred); +	  mk_branch_rr(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred);  	_ -> -	  mk_branch_ri(Src1, Cond, Src2, TrueLab, FalseLab, Pred) +	  mk_branch_ri(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred)        end;      _ ->        case hipe_arm:is_temp(Src2) of  	true -> -	  NewCond = commute_cond(Cond), -	  mk_branch_ri(Src2, NewCond, Src1, TrueLab, FalseLab, Pred); +	  NewCond = +	    case cmpop_commutes(CmpOp) of +	      true -> Cond; +	      false ->  commute_cond(Cond) +	    end, +	  mk_branch_ri(Src2, CmpOp, Src1, NewCond, TrueLab, FalseLab, Pred);  	_ -> -	  mk_branch_ii(Src1, Cond, Src2, TrueLab, FalseLab, Pred) +	  mk_branch_ii(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred)        end    end. -mk_branch_ii(Imm1, Cond, Imm2, TrueLab, FalseLab, Pred) -> -  io:format("~w: RTL branch with two immediates\n", [?MODULE]), +mk_branch_ii(Imm1, CmpOp, Imm2, Cond, TrueLab, FalseLab, Pred) ->    Tmp = new_untagged_temp(),    mk_li(Tmp, Imm1, -	mk_branch_ri(Tmp, Cond, Imm2, +	mk_branch_ri(Tmp, CmpOp, Imm2, Cond,  		     TrueLab, FalseLab, Pred)). -mk_branch_ri(Src, Cond, Imm, TrueLab, FalseLab, Pred) -> -  {FixAm1,NewCmpOp,Am1} = fix_aluop_imm('cmp', Imm), -  FixAm1 ++ mk_cmp_bc(NewCmpOp, Src, Am1, Cond, TrueLab, FalseLab, Pred). - -mk_branch_rr(Src1, Src2, Cond, TrueLab, FalseLab, Pred) -> -  mk_cmp_bc('cmp', Src1, Src2, Cond, TrueLab, FalseLab, Pred). +mk_branch_ri(Src, CmpOp, Imm, Cond, TrueLab, FalseLab, Pred) -> +  {FixAm1,NewCmpOp,Am1} = fix_aluop_imm(CmpOp, Imm), +  FixAm1 ++ mk_branch_rr(Src, NewCmpOp, Am1, Cond, TrueLab, FalseLab, Pred). -mk_cmp_bc(CmpOp, Src, Am1, Cond, TrueLab, FalseLab, Pred) -> +mk_branch_rr(Src, CmpOp, Am1, Cond, TrueLab, FalseLab, Pred) ->    [hipe_arm:mk_cmp(CmpOp, Src, Am1) |     mk_pseudo_bc(Cond, TrueLab, FalseLab, Pred)]. @@ -472,7 +478,6 @@ mk_load(Dst, Base1, Base2, LoadSize, LoadSign) ->    end.  mk_load_ii(Dst, Base1, Base2, LdOp) -> -  io:format("~w: RTL load with two immediates\n", [?MODULE]),    Tmp = new_untagged_temp(),    mk_li(Tmp, Base1,  	mk_load_ri(Dst, Tmp, Base2, LdOp)). @@ -485,7 +490,6 @@ mk_load_rr(Dst, Base1, Base2, LdOp) ->    [hipe_arm:mk_load(LdOp, Dst, Am2)].  mk_ldrsb_ii(Dst, Base1, Base2) -> -  io:format("~w: RTL load signed byte with two immediates\n", [?MODULE]),    Tmp = new_untagged_temp(),    mk_li(Tmp, Base1,  	mk_ldrsb_ri(Dst, Tmp, Base2)). @@ -543,7 +547,7 @@ conv_return(I, Map, Data) ->    {I2, Map0, Data}.  conv_store(I, Map, Data) -> -  {Base, Map0} = conv_dst(hipe_rtl:store_base(I), Map), +  {Base, Map0} = conv_src(hipe_rtl:store_base(I), Map),    {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),    {Offset, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),    StoreSize = hipe_rtl:store_size(I), @@ -567,13 +571,28 @@ mk_store(Src, Base, Offset, StoreSize) ->    end.  mk_store2(Src, Base, Offset, StOp) -> -  case hipe_arm:is_temp(Offset) of +  case hipe_arm:is_temp(Base) of      true -> -      mk_store_rr(Src, Base, Offset, StOp); -    _ -> -      mk_store_ri(Src, Base, Offset, StOp) +      case hipe_arm:is_temp(Offset) of +	true -> +	  mk_store_rr(Src, Base, Offset, StOp); +	_ -> +	  mk_store_ri(Src, Base, Offset, StOp) +      end; +    false -> +      case hipe_arm:is_temp(Offset) of +	true -> +	  mk_store_ri(Src, Offset, Base, StOp); +	_ -> +	  mk_store_ii(Src, Base, Offset, StOp) +      end    end. -   + +mk_store_ii(Src, Base, Offset, StOp) -> +  Tmp = new_untagged_temp(), +  mk_li(Tmp, Base, +	mk_store_ri(Src, Tmp, Offset, StOp)). +  mk_store_ri(Src, Base, Offset, StOp) ->    hipe_arm:mk_store(StOp, Src, Base, Offset, 'new', []). @@ -627,6 +646,7 @@ conv_alub_cond(RtlAluOp, Cond) ->	% may be unsigned, depends on aluop    case {RtlAluOp, Cond} of	% handle allowed alub unsigned conditions      {'add', 'ltu'} -> 'hs';	% add+ltu == unsigned overflow == carry set == hs      %% add more cases when needed +    {'sub', _} -> conv_branch_cond(Cond);      _ -> conv_cond(Cond)    end. | 
