aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/rtl/hipe_rtl_arch.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/hipe/rtl/hipe_rtl_arch.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/hipe/rtl/hipe_rtl_arch.erl')
-rw-r--r--lib/hipe/rtl/hipe_rtl_arch.erl612
1 files changed, 612 insertions, 0 deletions
diff --git a/lib/hipe/rtl/hipe_rtl_arch.erl b/lib/hipe/rtl/hipe_rtl_arch.erl
new file mode 100644
index 0000000000..2afdf4eb6b
--- /dev/null
+++ b/lib/hipe/rtl/hipe_rtl_arch.erl
@@ -0,0 +1,612 @@
+%% -*- 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%
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Copyright (c) 2001 by Erik Johansson.
+%%=====================================================================
+%% Filename : hipe_rtl_arch.erl
+%% History : * 2001-04-10 Erik Johansson ([email protected]): Created.
+%%=====================================================================
+%% @doc
+%%
+%% This module contains interface functions whose semantics and
+%% implementation depend on the target architecture.
+%%
+%% @end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-module(hipe_rtl_arch).
+
+-export([first_virtual_reg/0,
+ heap_pointer/0,
+ heap_limit/0,
+ fcalls/0,
+ reg_name/1,
+ is_precoloured/1,
+ call_defined/0,
+ call_used/0,
+ tailcall_used/0,
+ return_used/0,
+ live_at_return/0,
+ endianess/0,
+ load_big_2/4,
+ load_little_2/4,
+ load_big_4/4,
+ load_little_4/4,
+ %% store_4/3,
+ eval_alu/3,
+ %% eval_alub/4,
+ eval_cond/3,
+ eval_cond_bits/5,
+ fwait/0,
+ handle_fp_exception/0,
+ pcb_load/2,
+ pcb_load/3,
+ pcb_store/2,
+ pcb_store/3,
+ pcb_address/2,
+ call_bif/5,
+ %% alignment/0,
+ nr_of_return_regs/0,
+ log2_word_size/0,
+ word_size/0
+ ]).
+
+-include("hipe_literals.hrl").
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ____________________________________________________________________
+%%
+%% ARCH-specific stuff
+%% ____________________________________________________________________
+%%
+%%
+%% XXX: x86 might not _have_ real registers for some of these things
+%%
+
+first_virtual_reg() ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_sparc_registers:first_virtual();
+ powerpc ->
+ hipe_ppc_registers:first_virtual();
+ arm ->
+ hipe_arm_registers:first_virtual();
+ x86 ->
+ hipe_x86_registers:first_virtual();
+ amd64 ->
+ hipe_amd64_registers:first_virtual()
+ end.
+
+heap_pointer() -> % {GetHPInsn, HPReg, PutHPInsn}
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ heap_pointer_from_reg(hipe_sparc_registers:heap_pointer());
+ powerpc ->
+ heap_pointer_from_reg(hipe_ppc_registers:heap_pointer());
+ arm ->
+ heap_pointer_from_reg(hipe_arm_registers:heap_pointer());
+ x86 ->
+ x86_heap_pointer();
+ amd64 ->
+ amd64_heap_pointer()
+ end.
+
+heap_pointer_from_reg(Reg) ->
+ {hipe_rtl:mk_comment('get_heap_pointer'),
+ hipe_rtl:mk_reg(Reg),
+ hipe_rtl:mk_comment('put_heap_pointer')}.
+
+-ifdef(AMD64_HP_IN_REGISTER).
+amd64_heap_pointer() ->
+ heap_pointer_from_reg(hipe_amd64_registers:heap_pointer()).
+-else.
+-define(HEAP_POINTER_FROM_PCB_NEEDED,1).
+amd64_heap_pointer() ->
+ heap_pointer_from_pcb().
+-endif.
+
+-ifdef(X86_HP_IN_ESI).
+x86_heap_pointer() ->
+ heap_pointer_from_reg(hipe_x86_registers:heap_pointer()).
+-else.
+-define(HEAP_POINTER_FROM_PCB_NEEDED,1).
+x86_heap_pointer() ->
+ heap_pointer_from_pcb().
+-endif.
+
+-ifdef(HEAP_POINTER_FROM_PCB_NEEDED).
+heap_pointer_from_pcb() ->
+ Reg = hipe_rtl:mk_new_reg(),
+ {pcb_load(Reg, ?P_HP), Reg, pcb_store(?P_HP, Reg)}.
+-endif.
+
+heap_limit() -> % {GetHLIMITInsn, HLIMITReg}
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ heap_limit_from_pcb();
+ powerpc ->
+ heap_limit_from_pcb();
+ arm ->
+ heap_limit_from_pcb();
+ x86 ->
+ heap_limit_from_reg(hipe_x86_registers:heap_limit());
+ amd64 ->
+ heap_limit_from_reg(hipe_amd64_registers:heap_limit())
+ end.
+
+heap_limit_from_reg(Reg) ->
+ {hipe_rtl:mk_comment('get_heap_limit'),
+ hipe_rtl:mk_reg(Reg)}.
+
+heap_limit_from_pcb() ->
+ Reg = hipe_rtl:mk_new_reg(),
+ {pcb_load(Reg, ?P_HP_LIMIT), Reg}.
+
+fcalls() -> % {GetFCallsInsn, FCallsReg, PutFCallsInsn}
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ fcalls_from_pcb();
+ powerpc ->
+ fcalls_from_pcb();
+ arm ->
+ fcalls_from_pcb();
+ x86 ->
+ fcalls_from_reg(hipe_x86_registers:fcalls());
+ amd64 ->
+ fcalls_from_reg(hipe_amd64_registers:fcalls())
+ end.
+
+fcalls_from_reg(Reg) ->
+ {hipe_rtl:mk_comment('get_fcalls'),
+ hipe_rtl:mk_reg(Reg),
+ hipe_rtl:mk_comment('put_fcalls')}.
+
+fcalls_from_pcb() ->
+ Reg = hipe_rtl:mk_new_reg(),
+ {pcb_load(Reg, ?P_FCALLS), Reg, pcb_store(?P_FCALLS, Reg)}.
+
+reg_name(Reg) ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_sparc_registers:reg_name_gpr(Reg);
+ powerpc ->
+ hipe_ppc_registers:reg_name_gpr(Reg);
+ arm ->
+ hipe_arm_registers:reg_name_gpr(Reg);
+ x86 ->
+ hipe_x86_registers:reg_name(Reg);
+ amd64 ->
+ hipe_amd64_registers:reg_name(Reg)
+ end.
+
+%% @spec is_precoloured(rtl_arg()) -> boolean()
+%%
+%% @doc Succeeds if Arg is mapped to a precoloured register in the target.
+%%
+is_precoloured(Arg) ->
+ case hipe_rtl:is_reg(Arg) of
+ true ->
+ is_precolored_regnum(hipe_rtl:reg_index(Arg));
+ false ->
+ hipe_rtl:is_var(Arg) andalso
+ is_precolored_regnum(hipe_rtl:var_index(Arg))
+ end.
+
+is_precolored_regnum(RegNum) ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_sparc_registers:is_precoloured_gpr(RegNum);
+ powerpc ->
+ hipe_ppc_registers:is_precoloured_gpr(RegNum);
+ arm ->
+ hipe_arm_registers:is_precoloured_gpr(RegNum);
+ x86 ->
+ hipe_x86_registers:is_precoloured(RegNum);
+ amd64 ->
+ hipe_amd64_registers:is_precoloured(RegNum)
+ end.
+
+call_defined() ->
+ call_used().
+
+call_used() ->
+ live_at_return().
+
+tailcall_used() ->
+ call_used().
+
+return_used() ->
+ tailcall_used().
+
+live_at_return() ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ ordsets:from_list([hipe_rtl:mk_reg(R)
+ || {R,_} <- hipe_sparc_registers:live_at_return()]);
+ powerpc ->
+ ordsets:from_list([hipe_rtl:mk_reg(R)
+ || {R,_} <- hipe_ppc_registers:live_at_return()]);
+ arm ->
+ ordsets:from_list([hipe_rtl:mk_reg(R)
+ || {R,_} <- hipe_arm_registers:live_at_return()]);
+ x86 ->
+ ordsets:from_list([hipe_rtl:mk_reg(R)
+ || {R,_} <- hipe_x86_registers:live_at_return()]);
+ amd64 ->
+ ordsets:from_list([hipe_rtl:mk_reg(R)
+ || {R,_} <- hipe_amd64_registers:live_at_return()])
+ end.
+
+%% @spec word_size() -> integer()
+%%
+%% @doc Returns the target's word size.
+%%
+word_size() ->
+ case get(hipe_target_arch) of
+ ultrasparc -> 4;
+ powerpc -> 4;
+ arm -> 4;
+ x86 -> 4;
+ amd64 -> 8
+ end.
+
+%% alignment() ->
+%% case get(hipe_target_arch) of
+%% ultrasparc -> 4;
+%% powerpc -> 4;
+%% arm -> 4;
+%% x86 -> 4;
+%% amd64 -> 8
+%% end.
+
+%% @spec log2_word_size() -> integer()
+%%
+%% @doc Returns log2 of the target's word size.
+%%
+log2_word_size() ->
+ case get(hipe_target_arch) of
+ ultrasparc -> 2;
+ powerpc -> 2;
+ arm -> 2;
+ x86 -> 2;
+ amd64 -> 3
+ end.
+
+%% @spec endianess() -> big | little
+%%
+%% @doc Returns the target's endianess.
+%%
+endianess() ->
+ case get(hipe_target_arch) of
+ ultrasparc -> big;
+ powerpc -> big;
+ x86 -> little;
+ amd64 -> little;
+ arm -> ?ARM_ENDIANESS
+ end.
+
+%%%------------------------------------------------------------------------
+%%% Reading integers from binaries, in various sizes and endianesses.
+%%% Operand-sized alignment is NOT guaranteed, only byte alignment.
+%%%------------------------------------------------------------------------
+
+%%% Load a 2-byte big-endian integer from a binary.
+%%% Increment Offset by 2.
+load_big_2(Dst, Base, Offset, Signedness) ->
+ case get(hipe_target_arch) of
+ powerpc ->
+ load_2_directly(Dst, Base, Offset, Signedness);
+ %% Note: x86 could use a "load;xchgb" or "load;rol $8,<16-bit reg>"
+ %% sequence here. This has been implemented, but unfortunately didn't
+ %% make consistent improvements to our benchmarks.
+ _ ->
+ load_big_2_in_pieces(Dst, Base, Offset, Signedness)
+ end.
+
+%%% Load a 2-byte little-endian integer from a binary.
+%%% Increment Offset by 2.
+load_little_2(Dst, Base, Offset, Signedness) ->
+ case get(hipe_target_arch) of
+ x86 ->
+ load_2_directly(Dst, Base, Offset, Signedness);
+ powerpc ->
+ [hipe_rtl:mk_call([Dst], 'lhbrx', [Base,Offset], [], [], not_remote),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(2)) |
+ case Signedness of
+ unsigned -> [];
+ signed -> [hipe_rtl:mk_call([Dst], 'extsh', [Dst], [], [], not_remote)]
+ end];
+ _ ->
+ load_little_2_in_pieces(Dst, Base, Offset, Signedness)
+ end.
+
+load_2_directly(Dst, Base, Offset, Signedness) ->
+ [hipe_rtl:mk_load(Dst, Base, Offset, int16, Signedness),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(2))].
+
+load_big_2_in_pieces(Dst, Base, Offset, Signedness) ->
+ Tmp1 = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
+
+load_little_2_in_pieces(Dst, Base, Offset, Signedness) ->
+ Tmp1 = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, Signedness),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
+
+%%% Load a 4-byte big-endian integer from a binary.
+%%% Increment Offset by 4.
+load_big_4(Dst, Base, Offset, Signedness) ->
+ case get(hipe_target_arch) of
+ powerpc ->
+ load_4_directly(Dst, Base, Offset, Signedness);
+ %% Note: x86 could use a "load;bswap" sequence here.
+ %% This has been implemented, but unfortunately didn't
+ %% make any noticeable improvements in our benchmarks.
+ arm ->
+ %% When loading 4 bytes into a 32-bit register, the
+ %% signedness of the high-order byte doesn't matter.
+ %% ARM prefers unsigned byte loads so we'll use that.
+ load_big_4_in_pieces(Dst, Base, Offset, unsigned);
+ _ ->
+ load_big_4_in_pieces(Dst, Base, Offset, Signedness)
+ end.
+
+%%% Load a 4-byte little-endian integer from a binary.
+%%% Increment Offset by 4.
+load_little_4(Dst, Base, Offset, Signedness) ->
+ case get(hipe_target_arch) of
+ x86 ->
+ load_4_directly(Dst, Base, Offset, Signedness);
+ powerpc ->
+ [hipe_rtl:mk_call([Dst], 'lwbrx', [Base,Offset], [], [], not_remote),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))];
+ arm ->
+ %% When loading 4 bytes into a 32-bit register, the
+ %% signedness of the high-order byte doesn't matter.
+ %% ARM prefers unsigned byte loads so we'll use that.
+ load_little_4_in_pieces(Dst, Base, Offset, unsigned);
+ _ ->
+ load_little_4_in_pieces(Dst, Base, Offset, Signedness)
+ end.
+
+load_4_directly(Dst, Base, Offset, Signedness) ->
+ [hipe_rtl:mk_load(Dst, Base, Offset, word, Signedness),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
+
+load_big_4_in_pieces(Dst, Base, Offset, Signedness) ->
+ Tmp1 = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
+
+load_little_4_in_pieces(Dst, Base, Offset, Signedness) ->
+ Tmp1 = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(16)),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_load(Tmp1, Base, Offset, byte, Signedness),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(24)),
+ hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
+
+-ifdef(STORE_4_NEEDED).
+store_4(Base, Offset, Src) ->
+ case get(hipe_target_arch) of
+ x86 ->
+ store_4_directly(Base, Offset, Src);
+ powerpc ->
+ store_4_directly(Base, Offset, Src);
+ arm ->
+ store_big_4_in_pieces(Base, Offset, Src);
+ ultrasparc ->
+ store_big_4_in_pieces(Base, Offset, Src);
+ amd64 ->
+ store_4_directly(Base, Offset, Src)
+ end.
+
+store_4_directly(Base, Offset, Src) ->
+ [hipe_rtl:mk_store(Base, Offset, Src, int32),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
+
+store_big_4_in_pieces(Base, Offset, Src) ->
+ [hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_store(Base, Offset, Src, byte),
+ hipe_rtl:mk_alu(Offset, Offset, sub, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, Offset, Src, byte),
+ hipe_rtl:mk_alu(Offset, Offset, sub, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, Offset, Src, byte),
+ hipe_rtl:mk_alu(Offset, Offset, sub, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, Offset, Src, byte),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
+-endif.
+
+%%----------------------------------------------------------------------
+%% Handling of arithmetic -- depends on the size of word.
+%%----------------------------------------------------------------------
+
+eval_alu(Op, Arg1, Arg2) ->
+ %% io:format("Evaluated alu: ~w ~w ~w = ",[Arg1, Op, Arg2]),
+ Res = case word_size() of
+ 4 ->
+ hipe_rtl_arith_32:eval_alu(Op, Arg1, Arg2);
+ 8 ->
+ hipe_rtl_arith_64:eval_alu(Op, Arg1, Arg2)
+ end,
+ %% io:format("~w~n ",[Res]),
+ Res.
+
+-ifdef(EVAL_ALUB_NEEDED).
+eval_alub(Op, Cond, Arg1, Arg2) ->
+ %% io:format("Evaluated alub: ~w ~w ~w cond ~w = ",[Arg1, Op, Arg2, Cond]),
+ Res = case word_size() of
+ 4 ->
+ hipe_rtl_arith_32:eval_alub(Op, Cond, Arg1, Arg2);
+ 8 ->
+ hipe_rtl_arith_64:eval_alub(Op, Cond, Arg1, Arg2)
+ end,
+ %% io:format("~w~n ",[Res]),
+ Res.
+-endif.
+
+eval_cond(Cond, Arg1, Arg2) ->
+ %% io:format("Evaluated cond: ~w ~w ~w = ",[Arg1, Cond, Arg2]),
+ Res = case word_size() of
+ 4 ->
+ hipe_rtl_arith_32:eval_cond(Cond, Arg1, Arg2);
+ 8 ->
+ hipe_rtl_arith_64:eval_cond(Cond, Arg1, Arg2)
+ end,
+ %% io:format("~w~n ",[Res]),
+ Res.
+
+eval_cond_bits(Cond, N, Z, V, C) ->
+ %% io:format("Evaluated cond: ~w ~w ~w = ",[Arg1, Cond, Arg2]),
+ Res = case word_size() of
+ 4 ->
+ hipe_rtl_arith_32:eval_cond_bits(Cond, N, Z, V, C);
+ 8 ->
+ hipe_rtl_arith_64:eval_cond_bits(Cond, N, Z, V, C)
+ end,
+ %% io:format("~w~n ",[Res]),
+ Res.
+
+%%----------------------------------------------------------------------
+
+fwait() ->
+ case get(hipe_target_arch) of
+ x86 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
+ amd64 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
+ arm -> [];
+ powerpc -> [];
+ ultrasparc -> []
+ end.
+
+%% @spec handle_fp_exception() -> [term()]
+%%
+%% @doc
+%% Returns RTL code to restore the FPU after a floating-point exception.
+%% @end
+handle_fp_exception() ->
+ case get(hipe_target_arch) of
+ x86 ->
+ ContLbl = hipe_rtl:mk_new_label(),
+ [hipe_rtl:mk_call([], handle_fp_exception, [],
+ hipe_rtl:label_name(ContLbl), [], not_remote),
+ ContLbl];
+ amd64 ->
+ ContLbl = hipe_rtl:mk_new_label(),
+ [hipe_rtl:mk_call([], handle_fp_exception, [],
+ hipe_rtl:label_name(ContLbl), [], not_remote),
+ ContLbl];
+ arm ->
+ [];
+ powerpc ->
+ [];
+ ultrasparc ->
+ []
+ end.
+
+%%
+%% PCB accesses.
+%% Wrapped to avoid leaking the PCB pointer to the wrong places.
+%%
+
+pcb_load(Dst, Off) -> pcb_load(Dst, Off, word).
+
+pcb_load(Dst, Off, Size) ->
+ hipe_rtl:mk_load(Dst, proc_pointer(), hipe_rtl:mk_imm(Off), Size, unsigned).
+
+pcb_store(Off, Src) -> pcb_store(Off, Src, word).
+
+pcb_store(Off, Src, Size) ->
+ hipe_rtl:mk_store(proc_pointer(), hipe_rtl:mk_imm(Off), Src, Size).
+
+pcb_address(Dst, Off) ->
+ hipe_rtl:mk_alu(Dst, proc_pointer(), 'add', hipe_rtl:mk_imm(Off)).
+
+proc_pointer() -> % must not be exported
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_rtl:mk_reg_gcsafe(hipe_sparc_registers:proc_pointer());
+ powerpc ->
+ hipe_rtl:mk_reg_gcsafe(hipe_ppc_registers:proc_pointer());
+ arm ->
+ hipe_rtl:mk_reg_gcsafe(hipe_arm_registers:proc_pointer());
+ x86 ->
+ hipe_rtl:mk_reg_gcsafe(hipe_x86_registers:proc_pointer());
+ amd64 ->
+ hipe_rtl:mk_reg_gcsafe(hipe_amd64_registers:proc_pointer())
+ end.
+
+%%
+%% Special BIF calls.
+%% Wrapped to avoid leaking the PCB pointer to the wrong places,
+%% and to allow ARCH-specific expansion.
+%%
+
+call_bif(Dst, Name, Args, Cont, Fail) ->
+ hipe_rtl:mk_call(Dst, Name, Args, Cont, Fail, not_remote).
+
+nr_of_return_regs() ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ 1;
+ %% hipe_sparc_registers:nr_rets();
+ powerpc ->
+ 1;
+ %% hipe_ppc_registers:nr_rets();
+ arm ->
+ 1;
+ x86 ->
+ hipe_x86_registers:nr_rets();
+ amd64 ->
+ 1
+ %% hipe_amd64_registers:nr_rets();
+ end.