diff options
Diffstat (limited to 'lib/hipe/arm/hipe_arm_defuse.erl')
-rw-r--r-- | lib/hipe/arm/hipe_arm_defuse.erl | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/lib/hipe/arm/hipe_arm_defuse.erl b/lib/hipe/arm/hipe_arm_defuse.erl new file mode 100644 index 0000000000..8d6efebc21 --- /dev/null +++ b/lib/hipe/arm/hipe_arm_defuse.erl @@ -0,0 +1,157 @@ +%% -*- erlang-indent-level: 2 -*- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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_arm_defuse). +-export([insn_def_all/1, insn_use_all/1]). +-export([insn_def_gpr/1, insn_use_gpr/1]). +-include("hipe_arm.hrl"). + +%%% +%%% Defs and uses for both general-purpose and floating-point registers. +%%% This is needed for the frame module, alas. +%%% +insn_def_all(I) -> + insn_def_gpr(I). + +insn_use_all(I) -> + insn_use_gpr(I). + +%%% +%%% Defs and uses for general-purpose (integer) registers only. +%%% +insn_def_gpr(I) -> + case I of + #alu{dst=Dst} -> [Dst]; + #load{dst=Dst} -> [Dst]; + #ldrsb{dst=Dst} -> [Dst]; + #move{dst=Dst} -> [Dst]; + #pseudo_call{} -> call_clobbered_gpr(); + #pseudo_li{dst=Dst} -> [Dst]; + #pseudo_move{dst=Dst} -> [Dst]; + #pseudo_tailcall_prepare{} -> tailcall_clobbered_gpr(); + #smull{dstlo=DstLo,dsthi=DstHi,src1=Src1} -> + %% ARM requires DstLo, DstHi, and Src1 to be distinct. + %% Add fake DEF of Src1 to prevent regalloc from reusing + %% it as DstLo or DstHi. + [DstLo, DstHi, Src1]; + _ -> [] + end. + +call_clobbered_gpr() -> + [hipe_arm:mk_temp(R, T) + || {R,T} <- hipe_arm_registers:call_clobbered() ++ all_fp_pseudos()]. + +all_fp_pseudos() -> []. % XXX: for now + +tailcall_clobbered_gpr() -> + [hipe_arm:mk_temp(R, T) + || {R,T} <- hipe_arm_registers:tailcall_clobbered() ++ all_fp_pseudos()]. + +insn_use_gpr(I) -> + case I of + #alu{src=Src,am1=Am1} -> am1_use(Am1, [Src]); + #blx{src=Src} -> [Src]; + #cmp{src=Src,am1=Am1} -> am1_use(Am1, [Src]); + #load{am2=Am2} -> am2_use(Am2, []); + #ldrsb{am3=Am3} -> am3_use(Am3, []); + #move{am1=Am1} -> am1_use(Am1, []); + #pseudo_blr{} -> + LR = hipe_arm:mk_temp(hipe_arm_registers:lr(), 'untagged'), + RV = hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged'), + [RV, LR]; + #pseudo_bx{src=Src} -> + io:format("~w: whoa there! insn_use of ~w occurred\n", [?MODULE,I]), + [Src]; + #pseudo_call{funv=FunV,sdesc=#arm_sdesc{arity=Arity}} -> + funv_use(FunV, arity_use_gpr(Arity)); + #pseudo_move{src=Src} -> [Src]; + #pseudo_switch{jtab=JTabR,index=IndexR} -> addtemp(JTabR, [IndexR]); + #pseudo_tailcall{funv=FunV,arity=Arity,stkargs=StkArgs} -> + addargs(StkArgs, addtemps(tailcall_clobbered_gpr(), funv_use(FunV, arity_use_gpr(Arity)))); + #smull{src1=Src1,src2=Src2} -> addtemp(Src1, [Src2]); + #store{src=Src,am2=Am2} -> am2_use(Am2, [Src]); + _ -> [] + end. + +addargs([Arg|Args], Set) -> + addargs(Args, addarg(Arg, Set)); +addargs([], Set) -> + Set. + +addarg(Arg, Set) -> + case Arg of + #arm_temp{} -> addtemp(Arg, Set); + _ -> Set + end. + +arity_use_gpr(Arity) -> + [hipe_arm:mk_temp(R, 'tagged') + || R <- hipe_arm_registers:args(Arity)]. + +funv_use(FunV, Set) -> + case FunV of + #arm_temp{} -> addtemp(FunV, Set); + _ -> Set + end. + +am1_use(Am1, Set) -> + case Am1 of + #arm_temp{} -> addtemp(Am1, Set); + {Src,rrx} -> addtemp(Src, Set); + {Src,_,ShiftArg} -> + Set1 = addtemp(Src, Set), + case ShiftArg of + #arm_temp{} -> addtemp(ShiftArg, Set1); + _ -> Set1 + end; + _ -> Set + end. + +am2_use(#am2{src=Src,offset=Am2Offset}, Set) -> + Set1 = addtemp(Src, Set), + case Am2Offset of + #arm_temp{} -> addtemp(Am2Offset, Set1); + {Src2,_} -> addtemp(Src2, Set1); + {Src2,_,_} -> addtemp(Src2, Set1); + _ -> Set1 + end. + +am3_use(#am3{src=Src,offset=Am3Offset}, Set) -> + Set1 = addtemp(Src, Set), + case Am3Offset of + #arm_temp{} -> addtemp(Am3Offset, Set1); + _ -> Set1 + end. + +%%% +%%% Auxiliary operations on sets of temps +%%% These sets are small. No point using gb_trees, right? +%%% + +addtemps([Arg|Args], Set) -> + addtemps(Args, addtemp(Arg, Set)); +addtemps([], Set) -> + Set. + +addtemp(Temp, Set) -> + case lists:member(Temp, Set) of + false -> [Temp|Set]; + _ -> Set + end. |