aboutsummaryrefslogblamecommitdiffstats
path: root/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
blob: 9ed3d01a56b21aea33d06df354d46c3173dc3303 (plain) (tree)



























































































































































































                                                                                
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 2004-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_amd64_ra_sse2_postconditions).

-export([check_and_rewrite/2]).

-include("../x86/hipe_x86.hrl").
-define(HIPE_INSTRUMENT_COMPILER, true).
-include("../main/hipe.hrl").
-define(count_temp(T), ?cons_counter(counter_mfa_mem_temps, T)).


check_and_rewrite(AMD64Defun, Coloring) ->
  %%io:format("Converting\n"),
  TempMap = hipe_temp_map:cols2tuple(Coloring,hipe_amd64_specific_sse2),
  %%io:format("Rewriting\n"),
  #defun{code=Code0} = AMD64Defun,
  {Code1, DidSpill} = do_insns(Code0, TempMap, [], false),
  {AMD64Defun#defun{code=Code1, var_range={0, hipe_gensym:get_var(x86)}}, 
   DidSpill}.

do_insns([I|Insns], TempMap, Accum, DidSpill0) ->
  {NewIs, DidSpill1} = do_insn(I, TempMap),
  do_insns(Insns, TempMap, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
do_insns([], _TempMap, Accum, DidSpill) ->
  {lists:reverse(Accum), DidSpill}.

do_insn(I, TempMap) ->	% Insn -> {Insn list, DidSpill}
  case I of
    #fmove{} ->
      do_fmove(I, TempMap);
    #fp_unop{} ->
      do_fp_unop(I, TempMap);
    #fp_binop{} ->
      do_fp_binop(I, TempMap);
    _ ->
      %% All non sse2 ops
      {[I], false}
  end.

%%% Fix an fp_binop.
do_fp_binop(I, TempMap) ->
  #fp_binop{src=Src,dst=Dst} = I,
  case is_mem_opnd(Dst, TempMap) of
    true ->
      Tmp = clone(Dst),
      {[#fmove{src=Dst, dst=Tmp},
	I#fp_binop{src=Src,dst=Tmp},
	#fmove{src=Tmp,dst=Dst}],
       true};
    false ->
      {[I], false}
  end.

do_fp_unop(I, TempMap) ->
  #fp_unop{arg=Arg} = I,
  case is_mem_opnd(Arg, TempMap) of
    true ->
      Tmp = clone(Arg),
      {[#fmove{src=Arg, dst=Tmp},
	I#fp_unop{arg=Tmp},
	#fmove{src=Tmp,dst=Arg}],
       true};
    false ->
      {[I], false}
  end.

%%% Fix an fmove op.
do_fmove(I, TempMap) ->
  #fmove{src=Src,dst=Dst} = I,
  case is_mem_opnd(Dst, TempMap) and is_mem_opnd(Src, TempMap) of
    true ->
      Tmp = clone(Src),
      {[#fmove{src=Src, dst=Tmp},I#fmove{src=Tmp,dst=Dst}],
       true};
    false ->
      {[I], false}
  end.

%%% Check if an operand denotes a memory cell (mem or pseudo).

is_mem_opnd(Opnd, TempMap) ->
  R =
    case Opnd of
      #x86_mem{} -> true;
      #x86_temp{} -> 
	Reg = hipe_x86:temp_reg(Opnd),
	case hipe_x86:temp_is_allocatable(Opnd) of
	  true -> 
	    case tuple_size(TempMap) > Reg of 
	      true ->
		case 
		  hipe_temp_map:is_spilled(Reg, TempMap) of
		  true ->
		    ?count_temp(Reg),
		    true;
		  false -> false
		end;
	      _ -> false
	    end;
	  false -> true
	end;
      _ -> false
    end,
  %% io:format("Op ~w mem: ~w\n",[Opnd,R]),
  R.

%%% Check if an operand is a spilled Temp.

%%src_is_spilled(Src, TempMap) ->
%%  case hipe_x86:is_temp(Src) of
%%    true ->
%%      Reg = hipe_x86:temp_reg(Src),
%%      case hipe_x86:temp_is_allocatable(Src) of
%%	true -> 
%%	  case tuple_size(TempMap) > Reg of 
%%	    true ->
%%	      case hipe_temp_map:is_spilled(Reg, TempMap) of
%%		true ->
%%		  ?count_temp(Reg),
%%		  true;
%%		false ->
%%		  false
%%	      end;
%%	    false ->
%%	      false
%%	  end;
%%	false -> true
%%      end;
%%    false -> false
%%  end.

%% is_spilled(Temp, TempMap) ->
%%   case hipe_x86:temp_is_allocatable(Temp) of
%%     true ->
%%       Reg = hipe_x86:temp_reg(Temp),
%%       case tuple_size(TempMap) > Reg of 
%%  	true ->
%%  	  case hipe_temp_map:is_spilled(Reg, TempMap) of
%%  	    true ->
%%  	      ?count_temp(Reg),
%%  	      true;
%%  	    false ->
%%  	      false
%%  	  end;
%%  	false ->
%%  	  false
%%       end;
%%     false -> true
%%   end.

%%% Make Reg a clone of Dst (attach Dst's type to Reg).

clone(Dst) ->
  Type =
    case Dst of
      #x86_mem{} -> hipe_x86:mem_type(Dst);
      #x86_temp{} -> hipe_x86:temp_type(Dst)
    end,
  hipe_x86:mk_new_temp(Type).

%%% Make a certain reg into a clone of Dst

%% clone2(Dst, Reg) ->
%%   Type =
%%     case Dst of
%%       #x86_mem{} -> hipe_x86:mem_type(Dst);
%%       #x86_temp{} -> hipe_x86:temp_type(Dst)
%%     end,
%%   hipe_x86:mk_temp(Reg,Type).