1%% -*- erlang-indent-level: 2 -*-
2%%
3%% Licensed under the Apache License, Version 2.0 (the "License");
4%% you may not use this file except in compliance with the License.
5%% You may obtain a copy of the License at
6%%
7%%     http://www.apache.org/licenses/LICENSE-2.0
8%%
9%% Unless required by applicable law or agreed to in writing, software
10%% distributed under the License is distributed on an "AS IS" BASIS,
11%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12%% See the License for the specific language governing permissions and
13%% limitations under the License.
14
15-module(hipe_sparc_finalise).
16-export([finalise/1]).
17-include("hipe_sparc.hrl").
18
19finalise(Defun) ->
20  #defun{code=Code0} = Defun,
21  Code1 = peep(expand(Code0)),
22  Defun#defun{code=Code1}.
23
24expand(Insns) ->
25  expand_list(Insns, []).
26
27expand_list([I|Insns], Accum) ->
28  expand_list(Insns, expand_insn(I, Accum));
29expand_list([], Accum) ->
30  lists:reverse(Accum).
31
32expand_insn(I, Accum) ->
33  case I of
34    #bp{'cond'='a'} ->
35      [hipe_sparc:mk_nop(),
36       I |
37       Accum];
38    #call_rec{} ->
39      [hipe_sparc:mk_nop(),
40       I |
41       Accum];
42    #call_tail{} ->
43      RA = hipe_sparc:mk_ra(),
44      TempRA = hipe_sparc:mk_temp1(),
45      [hipe_sparc:mk_mov(TempRA, RA),
46       I,	% becomes a call, which clobbers RA
47       hipe_sparc:mk_mov(RA, TempRA) |
48       Accum];
49    #jmp{} ->
50      [hipe_sparc:mk_nop(),
51       I |
52       Accum];
53    #pseudo_bp{'cond'=Cond,true_label=TrueLab,false_label=FalseLab, pred=Pred} ->
54      [hipe_sparc:mk_nop(),
55       hipe_sparc:mk_b_label(FalseLab),
56       hipe_sparc:mk_nop(),
57       hipe_sparc:mk_bp(Cond, TrueLab, Pred) |
58       Accum];
59    %% #pseudo_br{} -> expand_pseudo_br(I, Accum);
60    #pseudo_call{funv=FunV,sdesc=SDesc,contlab=ContLab,linkage=Linkage} ->
61      [hipe_sparc:mk_nop(),
62       hipe_sparc:mk_b_label(ContLab),
63       hipe_sparc:mk_nop(),
64       case FunV of
65	 #sparc_temp{} ->
66	   hipe_sparc:mk_jmpl(FunV, SDesc);
67	 _ ->
68	   hipe_sparc:mk_call_rec(FunV, SDesc, Linkage)
69       end |
70       Accum];
71    #pseudo_ret{} ->
72      RA = hipe_sparc:mk_ra(),
73      [hipe_sparc:mk_nop(),
74       hipe_sparc:mk_jmp(RA, hipe_sparc:mk_simm13(8), []) |
75       Accum];
76    #pseudo_tailcall_prepare{} ->
77      Accum;
78    _ ->
79      XXX =
80	case I of
81	  #alu{} -> true;
82	  #comment{} -> true;
83	  #label{} -> true;
84	  #pseudo_set{} -> true;
85	  #rdy{} -> true;
86	  #sethi{} -> true;
87	  #store{} -> true;
88	  #bp{} -> false;
89	  %% #br{} -> false;
90	  #call_rec{} -> false;
91	  #call_tail{} -> false;
92	  #jmp{} -> false;
93	  #jmpl{} -> false;
94	  #pseudo_bp{} -> false;
95	  %% #pseudo_br{} -> false;
96	  #pseudo_call{} -> false;
97	  #pseudo_call_prepare{} -> false;
98	  #pseudo_move{} -> false;
99	  #pseudo_ret{} -> false;
100	  #pseudo_tailcall{} -> false;
101	  #pseudo_tailcall_prepare{} -> false;
102	  #fp_binary{} -> true;
103	  #fp_unary{} -> true;
104	  #pseudo_fload{} -> true;
105	  #pseudo_fstore{} -> true
106	end,
107      case XXX of
108	true -> [];
109	false -> exit({?MODULE,expand_insn,I})
110      end,
111      [I|Accum]
112  end.
113
114-ifdef(notdef).	% XXX: only for sparc64, alas
115expand_pseudo_br(I, Accum) ->
116  #pseudo_br{rcond=RCond,src=Src,true_label=TrueLab,false_label=FalseLab, pred=Pred} = I,
117  [hipe_sparc:mk_nop(),
118   hipe_sparc:mk_b_label(FalseLab),
119   hipe_sparc:mk_nop(),
120   hipe_sparc:mk_br(RCond, Src, TrueLab, Pred) |
121   Accum].
122-endif.
123
124peep(Insns) ->
125  peep_list(Insns, []).
126
127peep_list([#bp{'cond'='a',label=Label}, #sethi{uimm22=#sparc_uimm22{value=0},dst=#sparc_temp{reg=0}} | (Insns = [#label{label=Label}|_])], Accum) ->
128  peep_list(Insns, Accum);
129peep_list([I|Insns], Accum) ->
130  peep_list(Insns, [I|Accum]);
131peep_list([], Accum) ->
132  lists:reverse(Accum).
133