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-ifdef(HIPE_AMD64).
16-define(HIPE_X86_SPECIFIC, hipe_amd64_specific).
17-define(HIPE_X86_RA_POSTCONDITIONS, hipe_amd64_ra_postconditions).
18-define(HIPE_X86_REGISTERS, hipe_amd64_registers).
19-define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
20-define(HIPE_X86_DEFUSE, hipe_amd64_defuse).
21-define(HIPE_X86_SUBST, hipe_amd64_subst).
22-else.
23-define(HIPE_X86_SPECIFIC, hipe_x86_specific).
24-define(HIPE_X86_RA_POSTCONDITIONS, hipe_x86_ra_postconditions).
25-define(HIPE_X86_REGISTERS, hipe_x86_registers).
26-define(HIPE_X86_LIVENESS, hipe_x86_liveness).
27-define(HIPE_X86_DEFUSE, hipe_x86_defuse).
28-define(HIPE_X86_SUBST, hipe_x86_subst).
29-endif.
30
31-module(?HIPE_X86_SPECIFIC).
32
33-export([number_of_temporaries/2]).
34
35%% The following exports are used as M:F(...) calls from other modules;
36%% e.g. hipe_x86_ra_ls.
37-export([analyze/2,
38	 bb/3,
39	 args/2,
40	 labels/2,
41	 livein/3,
42	 liveout/3,
43	 uses/2,
44	 defines/2,
45	 defines_all_alloc/2,
46	 def_use/2,
47	 is_arg/2,	% used by hipe_ls_regalloc
48	 is_move/2,
49	 is_spill_move/2,
50	 is_fixed/2,	% used by hipe_graph_coloring_regalloc
51	 is_global/2,
52	 is_precoloured/2,
53	 reg_nr/2,
54	 non_alloc/2,
55	 allocatable/1,
56	 physical_name/2,
57	 all_precoloured/1,
58	 new_spill_index/2,	% used by hipe_ls_regalloc
59	 var_range/2,
60	 breadthorder/2,
61	 postorder/2,
62	 reverse_postorder/2]).
63
64%% callbacks for hipe_regalloc_loop
65-export([check_and_rewrite/3]).
66
67%% callbacks for hipe_regalloc_prepass, hipe_range_split
68-export([mk_move/3,
69	 mk_goto/2,
70	 redirect_jmp/4,
71	 new_label/1,
72	 new_reg_nr/1,
73	 update_reg_nr/3,
74	 update_bb/4,
75	 subst_temps/3]).
76
77%% callbacks for hipe_bb_weights
78-export([branch_preds/2]).
79
80check_and_rewrite(CFG, Coloring, _) ->
81  ?HIPE_X86_RA_POSTCONDITIONS:check_and_rewrite(CFG, Coloring, 'normal').
82
83reverse_postorder(CFG, _) ->
84  hipe_x86_cfg:reverse_postorder(CFG).
85
86breadthorder(CFG, _) ->
87  hipe_x86_cfg:breadthorder(CFG).
88
89postorder(CFG, _) ->
90  hipe_x86_cfg:postorder(CFG).
91
92%% Globally defined registers for linear scan
93is_global(R, _) ->
94  ?HIPE_X86_REGISTERS:temp1() =:= R orelse
95  ?HIPE_X86_REGISTERS:temp0() =:= R orelse
96  ?HIPE_X86_REGISTERS:is_fixed(R).
97
98is_fixed(R, _) ->
99  ?HIPE_X86_REGISTERS:is_fixed(R).
100
101is_arg(R, _) ->
102  ?HIPE_X86_REGISTERS:is_arg(R).
103
104args(CFG, _) ->
105  ?HIPE_X86_REGISTERS:args(hipe_x86_cfg:arity(CFG)).
106
107non_alloc(CFG, _) ->
108  non_alloc_1(?HIPE_X86_REGISTERS:nr_args(), hipe_x86_cfg:params(CFG)).
109
110%% same as hipe_x86_frame:fix_formals/2
111non_alloc_1(0, Rest) -> Rest;
112non_alloc_1(N, [_|Rest]) -> non_alloc_1(N-1, Rest);
113non_alloc_1(_, []) -> [].
114
115%% Liveness stuff
116
117analyze(CFG, _) ->
118  ?HIPE_X86_LIVENESS:analyze(CFG).
119
120livein(Liveness,L,_) ->
121  [X || X <- ?HIPE_X86_LIVENESS:livein(Liveness,L),
122	hipe_x86:temp_is_allocatable(X),
123	hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:fcalls(),
124	hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:heap_limit(),
125	hipe_x86:temp_type(X) =/= 'double'].
126
127liveout(BB_in_out_liveness,Label,_) ->
128  [X || X <- ?HIPE_X86_LIVENESS:liveout(BB_in_out_liveness,Label),
129	hipe_x86:temp_is_allocatable(X),
130	hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:fcalls(),
131	hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:heap_limit(),
132	hipe_x86:temp_type(X) =/= 'double'].
133
134%% Registers stuff
135
136allocatable(_) ->
137  ?HIPE_X86_REGISTERS:allocatable().
138
139all_precoloured(_) ->
140  ?HIPE_X86_REGISTERS:all_precoloured().
141
142is_precoloured(Reg,_) ->
143  ?HIPE_X86_REGISTERS:is_precoloured(Reg).
144
145physical_name(Reg,_) ->
146  Reg.
147
148%% CFG stuff
149
150labels(CFG,_) ->
151  hipe_x86_cfg:labels(CFG).
152
153var_range(_CFG,_) ->
154  hipe_gensym:var_range(x86).
155
156number_of_temporaries(_CFG,_) ->
157  Highest_temporary = hipe_gensym:get_var(x86),
158  %% Since we can have temps from 0 to Max adjust by +1.
159  Highest_temporary + 1.
160
161bb(CFG,L,_) ->
162  hipe_x86_cfg:bb(CFG,L).
163
164update_bb(CFG,L,BB,_) ->
165  hipe_x86_cfg:bb_add(CFG,L,BB).
166
167branch_preds(Instr,_) ->
168  hipe_x86_cfg:branch_preds(Instr).
169
170%% X86 stuff
171
172def_use(Instruction,_) ->
173  {[X || X <- ?HIPE_X86_DEFUSE:insn_def(Instruction),
174	 hipe_x86:temp_is_allocatable(X),
175	 hipe_x86:temp_type(X) =/= 'double'],
176   [X || X <- ?HIPE_X86_DEFUSE:insn_use(Instruction),
177	 hipe_x86:temp_is_allocatable(X),
178	 hipe_x86:temp_type(X) =/= 'double']
179  }.
180
181uses(I,_) ->
182  [X || X <- ?HIPE_X86_DEFUSE:insn_use(I),
183	hipe_x86:temp_is_allocatable(X),
184	hipe_x86:temp_type(X) =/= 'double'].
185
186defines(I,_) ->
187  [X || X <- ?HIPE_X86_DEFUSE:insn_def(I),
188	hipe_x86:temp_is_allocatable(X),
189	hipe_x86:temp_type(X) =/= 'double'].
190
191defines_all_alloc(I,_) -> ?HIPE_X86_DEFUSE:insn_defs_all(I).
192
193is_move(Instruction,_) ->
194  case hipe_x86:is_move(Instruction) of
195    true ->
196      Src = hipe_x86:move_src(Instruction),
197      Dst = hipe_x86:move_dst(Instruction),
198      case hipe_x86:is_temp(Src) of
199	true ->
200	  case hipe_x86:temp_is_allocatable(Src) of
201	    true ->
202	      case hipe_x86:is_temp(Dst) of
203		true ->
204		  hipe_x86:temp_is_allocatable(Dst);
205		false -> false
206	      end;
207	    false -> false
208	  end;
209	false -> false
210      end;
211    false -> false
212  end.
213
214is_spill_move(Instruction,_) ->
215  hipe_x86:is_pseudo_spill_move(Instruction).
216
217reg_nr(Reg,_) ->
218  hipe_x86:temp_reg(Reg).
219
220mk_move(Src, Dst, _) ->
221  hipe_x86:mk_move(Src, Dst).
222
223mk_goto(Label, _) ->
224  hipe_x86:mk_jmp_label(Label).
225
226redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
227  Ref = make_ref(),
228  put(Ref, false),
229  I = hipe_x86_subst:insn_lbls(
230	fun(Tgt) ->
231	    if Tgt =:= ToOld -> put(Ref, true), ToNew;
232	       is_integer(Tgt) -> Tgt
233	    end
234	end, Jmp),
235  true = erase(Ref), % Assert that something was rewritten
236  I.
237
238new_label(_) ->
239  hipe_gensym:get_next_label(x86).
240
241new_reg_nr(_) ->
242  hipe_gensym:get_next_var(x86).
243
244update_reg_nr(Nr, Temp, _) ->
245  hipe_x86:mk_temp(Nr, hipe_x86:temp_type(Temp)).
246
247subst_temps(SubstFun, Instr, _) ->
248  ?HIPE_X86_SUBST:insn_temps(
249    fun(Op) ->
250	case hipe_x86:temp_is_allocatable(Op)
251	  andalso hipe_x86:temp_type(Op) =/= 'double'
252	of
253	  true -> SubstFun(Op);
254	  false -> Op
255	end
256    end, Instr).
257
258new_spill_index(SpillIndex, _) when is_integer(SpillIndex) ->
259  SpillIndex+1.
260