%% -*- 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} ].