%% -*- erlang-indent-level: 2 -*-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Copyright (c) 2001 by Erik Johansson.  All Rights Reserved 
%% Time-stamp: <02/09/28 21:59:55 happi>
%% ====================================================================
%%  Filename : 	hipe_rtl_varmap.erl
%%  Module   :	hipe_rtl_varmap
%%  Purpose  :  
%%  Notes    : 
%%  History  :	* 2001-04-10 Erik Johansson (happi@csd.uu.se): 
%%               Created.
%%  CVS      :
%%              $Author: kostis $
%%              $Date: 2005/09/16 16:59:34 $
%%              $Revision: 1.16 $
%% ====================================================================
%%  Exports  :
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(hipe_rtl_varmap).
-export([init/1,
	 ivs2rvs/2,
	 icode_var2rtl_var/2,
	 icode_label2rtl_label/2]).

%-------------------------------------------------------------------------

-include("../main/hipe.hrl").

%-------------------------------------------------------------------------

%% @spec init(IcodeRecord::term()) -> {Args,VarMap}
%%
%% @doc Initializes gensym for RTL.
%%
init(IcodeRecord) ->
  hipe_gensym:init(rtl),
  hipe_gensym:set_var(rtl,hipe_rtl_arch:first_virtual_reg()),
  hipe_gensym:set_label(rtl,0),
  VarMap = new_var_map(),
  {_Args,_VarMap1} = ivs2rvs(hipe_icode:icode_params(IcodeRecord), VarMap).


%%------------------------------------------------------------------------
%%
%% Mapping of labels and variables from Icode to RTL.
%%
%%------------------------------------------------------------------------


%% @spec icode_label2rtl_label(Icode_Label::term(), LabelMap::term()) ->
%%           {RTL_Label,NewLabelMap}
%%
%% @doc Converts an Icode label to an RTL label.
%%
icode_label2rtl_label(LabelName, Map) ->
  case lookup(LabelName, Map) of
    {value,NewLabel} ->
      {NewLabel,Map};
    none ->
      NewLabel = hipe_rtl:mk_new_label(),
      {NewLabel,insert(LabelName, NewLabel, Map)}
  end.


%% @spec ivs2rvs(Icode_Vars::[term()], VarMap::term()) -> {[RTL_Var],NewVarMap}
%%
%% @doc Converts a list of Icode variables to a list of RTL variables.
%%
ivs2rvs([], VarMap) ->
  {[],VarMap};
ivs2rvs([V|Vs], VarMap) ->
  {NewV,VarMap0} = icode_var2rtl_var(V, VarMap),
  {NewVs,VarMap1} = ivs2rvs(Vs, VarMap0),
  {[NewV|NewVs],VarMap1}.


%% @spec icode_var2rtl_var(Icode_Var::term(), VarMap::term()) ->
%%           {RTL_Var,NewVarMap}
%%
%% @doc Converts an Icode variable to an RTL variable.
%%
icode_var2rtl_var(Var, Map) ->
  Value = lookup(Var, Map),
  case Value of
    none ->
      case type_of_var(Var) of
	fvar ->
	  NewVar = hipe_rtl:mk_new_fpreg(),
	  {NewVar,insert(Var, NewVar, Map)};
	var ->
	  NewVar = hipe_rtl:mk_new_var(),
	  {NewVar,insert(Var, NewVar, Map)};
	{reg,IsGcSafe} ->
	  NewVar =
	    case IsGcSafe of
	      %% true -> hipe_rtl:mk_new_reg_gcsafe();
	      false -> hipe_rtl:mk_new_reg()
	    end,
	  {NewVar,insert(Var, NewVar, Map)}
      end;
    {value,NewVar} ->
      {NewVar,Map}
  end.

%%
%% Simple type test
%%

type_of_var(X) ->
  case hipe_icode:is_fvar(X) of
    true ->
      fvar;
    false ->
      case hipe_icode:is_var(X) of
	true ->
	  var;
	false ->
	  case hipe_icode:is_reg(X) of
	    true ->
	      {reg, hipe_icode:reg_is_gcsafe(X)};
	    false ->
	      %% Sanity check
	      case hipe_icode:is_const(X) of
		true -> const;
		false ->
		  exit({"Unknown icode variable", X})
	      end
	  end
      end
  end.

%%
%% Helping utilities
%% 

new_var_map() ->
  gb_trees:empty().

lookup(V, Map) ->
  gb_trees:lookup(V, Map).

insert(Key, Val, Map) ->
  gb_trees:insert(Key, Val, Map).
