%%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. %%% You may obtain a copy of the License at %%% %%% http://www.apache.org/licenses/LICENSE-2.0 %%% %%% Unless required by applicable law or agreed to in writing, software %%% distributed under the License is distributed on an "AS IS" BASIS, %%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %%% See the License for the specific language governing permissions and %%% limitations under the License. %%% %%% TODO: %%% - Do we need a pseudo reg for the condition codes? -module(hipe_x86_registers). -export([reg_name/1, first_virtual/0, is_precoloured/1, is_precoloured_x87/1, all_precoloured/0, eax/0, ecx/0, temp0/0, temp1/0, sp/0, proc_pointer/0, heap_limit/0, fcalls/0, proc_offset/1, sp_limit_offset/0, is_fixed/1, %% fixed/0, allocatable/0, allocatable_x87/0, nr_args/0, arg/1, is_arg/1, args/1, nr_rets/0, ret/1, call_clobbered/0, tailcall_clobbered/0, live_at_return/0, float_size/0, wordsize/0, alignment/0]). -include("../rtl/hipe_literals.hrl"). -ifdef(X86_HP_IN_ESI). -export([heap_pointer/0]). -endif. -define(EAX, 0). -define(ECX, 1). -define(EDX, 2). -define(EBX, 3). -define(ESP, 4). -define(EBP, 5). -define(ESI, 6). -define(EDI, 7). -define(FCALLS, 8). % proc field alias -define(HEAP_LIMIT, 9). % proc field alias -define(LAST_PRECOLOURED, 9). -define(ARG0, ?EAX). -define(ARG1, ?EDX). -define(ARG2, ?ECX). -define(ARG3, ?EBX). -define(ARG4, ?EDI). -define(RET0, ?EAX). -define(RET1, ?EDX). -define(RET2, ?ECX). -define(RET3, ?EBX). -define(RET4, ?EDI). -define(TEMP0, ?EBX). % XXX: was EAX -define(TEMP1, ?EDI). % XXX: was EDX then EDI -define(PROC_POINTER, ?EBP). reg_name(R) -> case R of ?EAX -> "%eax"; ?ECX -> "%ecx"; ?EDX -> "%edx"; ?EBX -> "%ebx"; ?ESP -> "%esp"; ?EBP -> "%ebp"; ?ESI -> "%esi"; ?EDI -> "%edi"; ?FCALLS -> "%fcalls"; ?HEAP_LIMIT -> "%hplim"; Other -> "%r" ++ integer_to_list(Other) end. first_virtual() -> ?LAST_PRECOLOURED + 1. is_precoloured(X) -> X =< ?LAST_PRECOLOURED. is_precoloured_x87(X) -> X =< 6. all_precoloured() -> [?EAX, ?ECX, ?EDX, ?EBX, ?ESP, ?EBP, ?ESI, ?EDI, ?FCALLS, ?HEAP_LIMIT]. eax() -> ?EAX. ecx() -> ?ECX. temp0() -> ?TEMP0. temp1() -> ?TEMP1. sp() -> ?ESP. proc_pointer() -> ?PROC_POINTER. fcalls() -> ?FCALLS. heap_limit() -> ?HEAP_LIMIT. -ifdef(X86_HP_IN_ESI). -define(ESI_IS_FIXED,1). -define(HEAP_POINTER, ?ESI). heap_pointer() -> ?HEAP_POINTER. is_heap_pointer(?HEAP_POINTER) -> true; is_heap_pointer(_) -> false. -define(LIST_HP_FIXED,[?HEAP_POINTER]). -define(LIST_HP_LIVE_AT_RETURN,[{?HEAP_POINTER,untagged}]). -else. is_heap_pointer(_) -> false. -define(LIST_HP_FIXED,[]). -define(LIST_HP_LIVE_AT_RETURN,[]). -endif. -ifdef(ESI_IS_FIXED). -define(LIST_ESI_ALLOCATABLE,[]). -define(LIST_ESI_CALL_CLOBBERED,[]). -else. -define(LIST_ESI_ALLOCATABLE,[?ESI]). -define(LIST_ESI_CALL_CLOBBERED,[{?ESI,tagged},{?ESI,untagged}]). -endif. proc_offset(?FCALLS) -> ?P_FCALLS; proc_offset(?HEAP_LIMIT) -> ?P_HP_LIMIT; proc_offset(_) -> false. sp_limit_offset() -> ?P_NSP_LIMIT. is_fixed(?ESP) -> true; is_fixed(?PROC_POINTER) -> true; is_fixed(?FCALLS) -> true; is_fixed(?HEAP_LIMIT) -> true; is_fixed(R) -> is_heap_pointer(R). %% fixed() -> %% [?ESP, ?PROC_POINTER, ?FCALLS, ?HEAP_LIMIT | ?LIST_HP_FIXED]. allocatable() -> [?EDX, ?ECX, ?EBX, ?EAX, ?EDI| ?LIST_ESI_ALLOCATABLE]. allocatable_x87() -> [0,1,2,3,4,5,6]. nr_args() -> ?X86_NR_ARG_REGS. arg(N) -> if N < ?X86_NR_ARG_REGS -> case N of 0 -> ?ARG0; 1 -> ?ARG1; 2 -> ?ARG2; 3 -> ?ARG3; 4 -> ?ARG4; _ -> exit({?MODULE, arg, N}) end; true -> exit({?MODULE, arg, N}) end. is_arg(R) -> case R of ?ARG0 -> ?X86_NR_ARG_REGS > 0; ?ARG1 -> ?X86_NR_ARG_REGS > 1; ?ARG2 -> ?X86_NR_ARG_REGS > 2; ?ARG3 -> ?X86_NR_ARG_REGS > 3; ?ARG4 -> ?X86_NR_ARG_REGS > 4; _ -> false end. args(Arity) when is_integer(Arity), Arity >= 0 -> N = erlang:min(Arity, ?X86_NR_ARG_REGS), args(N-1, []). args(I, Rest) when I < 0 -> Rest; args(I, Rest) -> args(I-1, [arg(I) | Rest]). nr_rets() -> ?X86_NR_RET_REGS. ret(N) -> if N < ?X86_NR_RET_REGS -> case N of 0 -> ?RET0; 1 -> ?RET1; 2 -> ?RET2; 3 -> ?RET3; 4 -> ?RET4; _ -> exit({?MODULE, ret, N}) end; true -> exit({?MODULE, ret, N}) end. %% Note: the fact that (allocatable() UNION allocatable_x87()) is a subset of %% call_clobbered() is hard-coded in hipe_x86_defuse:insn_defs_all/1 call_clobbered() -> [{?EAX,tagged},{?EAX,untagged}, % does the RA strip the type or not? {?EDX,tagged},{?EDX,untagged}, {?ECX,tagged},{?ECX,untagged}, {?EBX,tagged},{?EBX,untagged}, {?EDI,tagged},{?EDI,untagged} | ?LIST_ESI_CALL_CLOBBERED] ++ all_x87_pseudos(). tailcall_clobbered() -> % tailcall crapola needs two temps [{?TEMP0,tagged},{?TEMP0,untagged}, {?TEMP1,tagged},{?TEMP1,untagged}] ++ all_x87_pseudos(). all_x87_pseudos() -> [{0,double}, {1,double}, {2,double}, {3,double}, {4,double}, {5,double}, {6,double}]. live_at_return() -> [{?ESP,untagged} ,{?PROC_POINTER,untagged} ,{?FCALLS,untagged} ,{?HEAP_LIMIT,untagged} | ?LIST_HP_LIVE_AT_RETURN ]. alignment() -> 4. float_size() -> 8. wordsize() -> 4.