%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2001-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_registers).
-export([reg_name_gpr/1,
reg_name_fpr/1,
first_virtual/0,
is_precoloured_gpr/1,
is_precoloured_fpr/1,
all_precoloured/0, % for coalescing ra
return_value/0,
temp1/0,
temp2/0,
temp3/0,
heap_pointer/0,
stack_pointer/0,
proc_pointer/0,
return_address/0,
g0/0,
%% heap_limit/0,
%% fcalls/0,
allocatable_gpr/0, % for coalescing ra
allocatable_fpr/0,
is_fixed/1, % for graph_coloring ra
nr_args/0,
arg/1,
args/1,
is_arg/1, % for linear_scan ra
call_clobbered/0,
tailcall_clobbered/0,
live_at_return/0
]).
-include("../rtl/hipe_literals.hrl").
-define(G0, 0).
-define(G1, 1).
-define(G2, 2).
-define(G3, 3).
-define(G4, 4).
-define(G5, 5).
-define(G6, 6).
-define(G7, 7).
-define(O0, 8).
-define(O1, 9).
-define(O2, 10).
-define(O3, 11).
-define(O4, 12).
-define(O5, 13).
-define(O6, 14).
-define(O7, 15).
-define(L0, 16).
-define(L1, 17).
-define(L2, 18).
-define(L3, 19).
-define(L4, 20).
-define(L5, 21).
-define(L6, 22).
-define(L7, 23).
-define(I0, 24).
-define(I1, 25).
-define(I2, 26).
-define(I3, 27).
-define(I4, 28).
-define(I5, 29).
-define(I6, 30).
-define(I7, 31).
-define(LAST_PRECOLOURED,31). % must handle both GRP and FPR ranges
-define(ARG0, ?O1).
-define(ARG1, ?O2).
-define(ARG2, ?O3).
-define(ARG3, ?O4).
-define(ARG4, ?O5).
-define(ARG5, ?O0).
-define(TEMP1, ?I3). % stores RA around inc_stack calls, must be C calleE-save
-define(TEMP2, ?I4).
-define(TEMP3, ?I5).
-define(RETURN_VALUE, ?O0).
-define(HEAP_POINTER, ?I2).
-define(STACK_POINTER, ?I1).
-define(PROC_POINTER, ?I0).
reg_name_gpr(R) ->
case R of
?G0 -> "%g0";
?G1 -> "%g1";
?G2 -> "%g2";
?G3 -> "%g3";
?G4 -> "%g4";
?G5 -> "%g5";
?G6 -> "%g6";
?G7 -> "%g7";
?O0 -> "%o0";
?O1 -> "%o1";
?O2 -> "%o2";
?O3 -> "%o3";
?O4 -> "%o4";
?O5 -> "%o5";
?O6 -> "%sp";
?O7 -> "%o7";
?L0 -> "%l0";
?L1 -> "%l1";
?L2 -> "%l2";
?L3 -> "%l3";
?L4 -> "%l4";
?L5 -> "%l5";
?L6 -> "%l6";
?L7 -> "%l7";
?I0 -> "%i0";
?I1 -> "%i1";
?I2 -> "%i2";
?I3 -> "%i3";
?I4 -> "%i4";
?I5 -> "%i5";
?I6 -> "%fp";
?I7 -> "%i7";
%% to handle code before regalloc:
_ -> "%r" ++ integer_to_list(R)
end.
reg_name_fpr(R) -> [$f | integer_to_list(2*R)].
%%% Must handle both GPR and FPR ranges.
first_virtual() -> ?LAST_PRECOLOURED + 1.
%%% These two tests have the same implementation, but that's
%%% not something we should cast in stone in the interface.
is_precoloured_gpr(R) -> R =< ?LAST_PRECOLOURED.
is_precoloured_fpr(R) -> R =< ?LAST_PRECOLOURED.
all_precoloured() ->
%% <%g6, %g7, %o6, %i6> should be skipped as they are unused.
%% Unfortunately, gaps in the list of precoloured registers
%% cause the graph_color register allocator to create bogus
%% assignments for those "registers", which in turn causes
%% the "precoloured reg must map to itself" sanity check in
%% the frame module to signal errors.
[?G0, ?G1, ?G2, ?G3, ?G4, ?G5, ?G6, ?G7,
?O0, ?O1, ?O2, ?O3, ?O4, ?O5, ?O6, ?O7,
?L0, ?L1, ?L2, ?L3, ?L4, ?L5, ?L6, ?L7,
?I0, ?I1, ?I2, ?I3, ?I4, ?I5, ?I6, ?I7].
return_value() -> ?RETURN_VALUE.
temp1() -> ?TEMP1.
temp2() -> ?TEMP2.
temp3() -> ?TEMP3.
heap_pointer() -> ?HEAP_POINTER.
stack_pointer() -> ?STACK_POINTER.
proc_pointer() -> ?PROC_POINTER.
return_address() -> ?O7.
g0() -> ?G0.
allocatable_gpr() ->
%% %g0 is not writable
%% %g6, %g7, %o6, and %i6 are reserved for C
%% %i0, %i1, and %i2 are fixed global registers
%% %i4 may be used by the frame module for large load/store offsets
[ ?G1, ?G2, ?G3, ?G4, ?G5,
?O0, ?O1, ?O2, ?O3, ?O4, ?O5, ?O7,
?L0, ?L1, ?L2, ?L3, ?L4, ?L5, ?L6, ?L7,
?I3, ?I5, ?I7].
allocatable_fpr() ->
%% We expose 16 virtual fp regs, 0-15, corresponding to the
%% f0/f2/f4/.../f28/f30 double-precision hardware fp regs.
%% The mapping is done by reg_name_fpr/1 and the assembler.
%% We ignore f32/.../f60 since they cannot be used in loads
%% or stores for non 8-byte aligned addresses.
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].
%% Needed for hipe_graph_coloring_regalloc.
%% Presumably true for Reg in AllPrecoloured \ Allocatable.
is_fixed(Reg) ->
case Reg of
?HEAP_POINTER -> true;
?STACK_POINTER -> true;
?PROC_POINTER -> true;
%% The following cases are required for linear scan:
%% it gets confused if it sees a register which is
%% neither allocatable nor global (fixed or one of
%% the scratch registers set aside for linear scan).
?G0 -> true;
?G6 -> true;
?G7 -> true;
?O6 -> true;
?I6 -> true;
_ -> false
end.
nr_args() -> ?SPARC_NR_ARG_REGS.
args(Arity) when is_integer(Arity) ->
N = erlang:min(Arity, ?SPARC_NR_ARG_REGS),
args(N-1, []).
args(I, Rest) when is_integer(I), I < 0 -> Rest;
args(I, Rest) -> args(I-1, [arg(I) | Rest]).
arg(N) ->
if N < ?SPARC_NR_ARG_REGS ->
case N of
0 -> ?ARG0;
1 -> ?ARG1;
2 -> ?ARG2;
3 -> ?ARG3;
4 -> ?ARG4;
5 -> ?ARG5
end
end.
is_arg(R) ->
case R of
?ARG0 -> ?SPARC_NR_ARG_REGS > 0;
?ARG1 -> ?SPARC_NR_ARG_REGS > 1;
?ARG2 -> ?SPARC_NR_ARG_REGS > 2;
?ARG3 -> ?SPARC_NR_ARG_REGS > 3;
?ARG4 -> ?SPARC_NR_ARG_REGS > 4;
?ARG5 -> ?SPARC_NR_ARG_REGS > 5;
_ -> false
end.
call_clobbered() -> % does the RA strip the type or not?
[%% ?G0 is the non-allocatable constant zero
{?G1,tagged},{?G1,untagged},
{?G2,tagged},{?G2,untagged},
{?G3,tagged},{?G3,untagged},
{?G4,tagged},{?G4,untagged},
{?G5,tagged},{?G5,untagged},
%% ?G6 is reserved for C
%% ?G7 is reserved for C
{?O0,tagged},{?O0,untagged},
{?O1,tagged},{?O1,untagged},
{?O2,tagged},{?O2,untagged},
{?O3,tagged},{?O3,untagged},
{?O4,tagged},{?O4,untagged},
{?O5,tagged},{?O5,untagged},
%% ?O6 is reserved for C
{?O7,tagged},{?O7,untagged},
{?L0,tagged},{?L0,untagged},
{?L1,tagged},{?L1,untagged},
{?L2,tagged},{?L2,untagged},
{?L3,tagged},{?L3,untagged},
{?L4,tagged},{?L4,untagged},
{?L5,tagged},{?L5,untagged},
{?L6,tagged},{?L6,untagged},
{?L7,tagged},{?L7,untagged},
%% ?I0 is fixed (P)
%% ?I1 is fixed (NSP)
%% ?I2 is fixed (HP)
{?I3,tagged},{?I3,untagged},
{?I4,tagged},{?I4,untagged},
{?I5,tagged},{?I5,untagged},
%% ?I6 is reserved for C
{?I7,tagged},{?I7,untagged}
].
tailcall_clobbered() -> % tailcall crapola needs one temp
[{?TEMP1,tagged},{?TEMP1,untagged}].
live_at_return() ->
[{?HEAP_POINTER,untagged},
{?STACK_POINTER,untagged},
{?PROC_POINTER,untagged}
].