aboutsummaryrefslogblamecommitdiffstats
path: root/lib/hipe/sparc/hipe_sparc_finalise.erl
blob: b44a21f7c05d2044df15ae9896f02c94c93a4518 (plain) (tree)









































































































































                                                                                                                                                    
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 2007-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%
%%

-module(hipe_sparc_finalise).
-export([finalise/1]).
-include("hipe_sparc.hrl").

finalise(Defun) ->
  #defun{code=Code0} = Defun,
  Code1 = peep(expand(Code0)),
  Defun#defun{code=Code1}.

expand(Insns) ->
  expand_list(Insns, []).

expand_list([I|Insns], Accum) ->
  expand_list(Insns, expand_insn(I, Accum));
expand_list([], Accum) ->
  lists:reverse(Accum).

expand_insn(I, Accum) ->
  case I of
    #bp{'cond'='a'} ->
      [hipe_sparc:mk_nop(),
       I |
       Accum];
    #call_rec{} ->
      [hipe_sparc:mk_nop(),
       I |
       Accum];
    #call_tail{} ->
      RA = hipe_sparc:mk_ra(),
      TempRA = hipe_sparc:mk_temp1(),
      [hipe_sparc:mk_mov(TempRA, RA),
       I,	% becomes a call, which clobbers RA
       hipe_sparc:mk_mov(RA, TempRA) |
       Accum];
    #jmp{} ->
      [hipe_sparc:mk_nop(),
       I |
       Accum];
    #pseudo_bp{'cond'=Cond,true_label=TrueLab,false_label=FalseLab, pred=Pred} ->
      [hipe_sparc:mk_nop(),
       hipe_sparc:mk_b_label(FalseLab),
       hipe_sparc:mk_nop(),
       hipe_sparc:mk_bp(Cond, TrueLab, Pred) |
       Accum];
    %% #pseudo_br{} -> expand_pseudo_br(I, Accum);
    #pseudo_call{funv=FunV,sdesc=SDesc,contlab=ContLab,linkage=Linkage} ->
      [hipe_sparc:mk_nop(),
       hipe_sparc:mk_b_label(ContLab),
       hipe_sparc:mk_nop(),
       case FunV of
	 #sparc_temp{} ->
	   hipe_sparc:mk_jmpl(FunV, SDesc);
	 _ ->
	   hipe_sparc:mk_call_rec(FunV, SDesc, Linkage)
       end |
       Accum];
    #pseudo_ret{} ->
      RA = hipe_sparc:mk_ra(),
      [hipe_sparc:mk_nop(),
       hipe_sparc:mk_jmp(RA, hipe_sparc:mk_simm13(8), []) |
       Accum];
    #pseudo_tailcall_prepare{} ->
      Accum;
    _ ->
      XXX =
	case I of
	  #alu{} -> true;
	  #comment{} -> true;
	  #label{} -> true;
	  #pseudo_set{} -> true;
	  #rdy{} -> true;
	  #sethi{} -> true;
	  #store{} -> true;
	  #bp{} -> false;
	  %% #br{} -> false;
	  #call_rec{} -> false;
	  #call_tail{} -> false;
	  #jmp{} -> false;
	  #jmpl{} -> false;
	  #pseudo_bp{} -> false;
	  %% #pseudo_br{} -> false;
	  #pseudo_call{} -> false;
	  #pseudo_call_prepare{} -> false;
	  #pseudo_move{} -> false;
	  #pseudo_ret{} -> false;
	  #pseudo_tailcall{} -> false;
	  #pseudo_tailcall_prepare{} -> false;
	  #fp_binary{} -> true;
	  #fp_unary{} -> true;
	  #pseudo_fload{} -> true;
	  #pseudo_fstore{} -> true
	end,
      case XXX of
	true -> [];
	false -> exit({?MODULE,expand_insn,I})
      end,
      [I|Accum]
  end.

-ifdef(notdef).	% XXX: only for sparc64, alas
expand_pseudo_br(I, Accum) ->
  #pseudo_br{rcond=RCond,src=Src,true_label=TrueLab,false_label=FalseLab, pred=Pred} = I,
  [hipe_sparc:mk_nop(),
   hipe_sparc:mk_b_label(FalseLab),
   hipe_sparc:mk_nop(),
   hipe_sparc:mk_br(RCond, Src, TrueLab, Pred) |
   Accum].
-endif.

peep(Insns) ->
  peep_list(Insns, []).

peep_list([#bp{'cond'='a',label=Label}, #sethi{uimm22=#sparc_uimm22{value=0},dst=#sparc_temp{reg=0}} | (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).