1
%%% -*- erlang-indent-level: 4 -*-
3
%%% simple local x86 regalloc
6
-define(HIPE_X86_RA_NAIVE, hipe_amd64_ra_naive).
7
-define(HIPE_X86_REGISTERS, hipe_amd64_registers).
8
-define(HIPE_X86_SPECIFIC_FP, hipe_amd64_specific_sse2).
11
-define(HIPE_X86_RA_NAIVE, hipe_x86_ra_naive).
12
-define(HIPE_X86_REGISTERS, hipe_x86_registers).
13
-define(HIPE_X86_SPECIFIC_FP, hipe_x86_specific_x87).
17
-module(?HIPE_X86_RA_NAIVE).
20
-include("../x86/hipe_x86.hrl").
21
-define(HIPE_INSTRUMENT_COMPILER, true). % enable instrumentation
22
-include("../main/hipe.hrl").
24
ra(X86Defun, Coloring_fp, Options) ->
25
#defun{code=Code0} = X86Defun,
26
Code1 = do_insns(Code0),
27
NofSpilledFloats = count_non_float_spills(Coloring_fp),
28
NofFloats = length(Coloring_fp),
29
?add_spills(Options, hipe_gensym:get_var(x86) -
30
?HIPE_X86_REGISTERS:first_virtual()-
34
{X86Defun#defun{code=Code1,
35
var_range={0, hipe_gensym:get_var(x86)}},
38
count_non_float_spills(Coloring_fp)->
39
count_non_float_spills(Coloring_fp,0).
40
count_non_float_spills([{_,To}|Tail], Num)->
41
case ?HIPE_X86_SPECIFIC_FP:is_precoloured(To) of
43
count_non_float_spills(Tail, Num);
45
count_non_float_spills(Tail, Num+1)
47
count_non_float_spills([],Num) ->
50
do_insns([I|Insns]) ->
51
do_insn(I) ++ do_insns(Insns);
55
do_insn(I) -> % Insn -> Insn list
89
#pseudo_tailcall_prepare{} ->
100
io:format("Unknown Instruction = ~w\n", [I]),
101
exit({?MODULE, unknown_instruction, I})
107
#alu{src=Src0,dst=Dst0} = I,
108
{FixSrc,Src,FixDst,Dst} = do_binary(Src0, Dst0),
109
FixSrc ++ FixDst ++ [I#alu{src=Src,dst=Dst}].
114
#cmp{src=Src0,dst=Dst0} = I,
115
{FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
116
FixSrc ++ FixDst ++ [I#cmp{src=Src,dst=Dst}].
118
%%% Fix a jmp_switch op.
122
#jmp_switch{temp=Temp, jtab=Tab} = I,
123
case temp_is_pseudo(Temp) of
125
case temp_is_pseudo(Tab) of
129
Reg = hipe_x86:mk_temp(hipe_amd64_registers:temp0(),
131
[hipe_x86:mk_move(Temp, Reg), I#jmp_switch{jtab=Reg}]
134
Reg = hipe_x86:mk_temp(hipe_amd64_registers:temp1(),
136
case temp_is_pseudo(Tab) of
138
[hipe_x86:mk_move(Temp, Reg), I#jmp_switch{temp=Reg}];
140
Reg2 = hipe_x86:mk_temp(hipe_amd64_registers:temp0(),
142
[hipe_x86:mk_move(Temp, Reg),
143
hipe_x86:mk_move(Tab, Reg2),
144
I#jmp_switch{temp=Reg, jtab=Reg2}]
149
#jmp_switch{temp=Temp} = I,
150
case temp_is_pseudo(Temp) of
154
Reg = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp0(), 'untagged'),
155
[hipe_x86:mk_move(Temp, Reg), I#jmp_switch{temp=Reg}]
163
case temp_is_pseudo(Temp) of
167
Reg = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp0(), 'untagged'),
168
[I#lea{temp=Reg}, hipe_x86:mk_move(Reg, Temp)]
174
#move{src=Src0,dst=Dst0} = I,
175
{FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
176
FixSrc ++ FixDst ++ [I#move{src=Src,dst=Dst}].
180
#move64{dst=Dst} = I,
181
case is_mem_opnd(Dst) of
185
Reg = hipe_amd64_registers:temp1(),
186
NewDst = clone(Dst, Reg),
187
[I#move64{dst=NewDst}, hipe_x86:mk_move(NewDst, Dst)]
190
do_move64(I) -> exit({?MODULE, I}).
196
#movsx{src=Src0,dst=Dst0} ->
197
fix_src_operand(Src0);
198
#movzx{src=Src0,dst=Dst0} ->
199
fix_src_operand(Src0)
201
{FixDst, Dst} = fix_dst_operand(Dst0),
202
Reg = ?HIPE_X86_REGISTERS:temp0(),
203
Dst2 = clone(Dst, Reg),
205
case is_mem_opnd(Dst) of
207
Reg = ?HIPE_X86_REGISTERS:temp0(),
208
Dst2 = clone(Dst, Reg),
211
[hipe_x86:mk_movsx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)];
213
[hipe_x86:mk_movzx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)]
218
[hipe_x86:mk_movsx(Src, Dst)];
220
[hipe_x86:mk_movzx(Src, Dst)]
224
FixSrc ++ FixDst ++ I2.
230
do_fmove(I=#fmove{src=#x86_temp{type=untagged},
231
dst=#x86_temp{type=double}}) ->
232
#fmove{src=Src0,dst=Dst0} = I,
233
Src = clone(Src0, ?HIPE_X86_REGISTERS:temp0()),
234
Dst = clone(Dst0, ?HIPE_X86_REGISTERS:temp1()),
235
[hipe_x86:mk_move(Src0, Src),
236
I#fmove{src=Src, dst=Dst},
237
hipe_x86:mk_fmove(Dst, Dst0)];
240
#fmove{src=Src0,dst=Dst0} = I,
241
{FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
242
FixSrc ++ FixDst ++ [I#fmove{src=Src,dst=Dst}].
245
#fp_unop{arg=Arg} = I,
246
case is_mem_opnd(Arg) of
250
Reg = ?HIPE_X86_REGISTERS:temp1(),
251
NewArg = clone(Arg, Reg),
252
[hipe_x86:mk_fmove(Arg, NewArg),
253
I#fp_unop{arg=NewArg},
254
hipe_x86:mk_fmove(NewArg, Arg)]
258
#fp_binop{src=Src0, dst=Dst0} = I,
259
{FixSrc, Src} = fix_src_operand(Src0),
260
{FixDst, Dst} = fix_dst_operand(Dst0),
261
Reg = ?HIPE_X86_REGISTERS:temp1(),
262
Dst2 = clone(Dst, Reg),
263
FixSrc ++ FixDst ++ [hipe_x86:mk_fmove(Dst, Dst2),
264
I#fp_binop{src=Src, dst=Dst2},
265
hipe_x86:mk_fmove(Dst2, Dst)].
268
#shift{src=Src0,dst=Dst0} = I,
269
{FixDst, Dst} = fix_dst_operand(Dst0),
270
Reg = ?HIPE_X86_REGISTERS:?ECX(),
273
FixDst ++ [I#shift{dst=Dst}];
274
#x86_temp{reg=Reg} ->
275
FixDst ++ [I#shift{dst=Dst}]
278
%%% Fix the operands of a binary op.
279
%%% 1. remove pseudos from any explicit memory operands
280
%%% 2. if both operands are (implicit or explicit) memory operands,
281
%%% move src to a reg and use reg as src in the original insn
283
do_binary(Src0, Dst0) ->
284
{FixSrc, Src} = fix_src_operand(Src0),
285
{FixDst, Dst} = fix_dst_operand(Dst0),
287
case is_mem_opnd(Src) of
291
case is_mem_opnd(Dst) of
295
Reg = ?HIPE_X86_REGISTERS:temp0(),
296
Src2 = clone(Src, Reg),
297
FixSrc2 = FixSrc ++ [mk_move(Src, Src2)],
301
{FixSrc3, Src3, FixDst, Dst}.
303
%%% Fix any x86_mem operand to not refer to any pseudos.
304
%%% The fixup may use additional instructions and registers.
305
%%% 'src' operands may clobber '%temp0'.
306
%%% 'dst' operands may clobber '%temp1'.
308
fix_src_operand(Opnd) ->
309
fix_mem_operand(Opnd, ?HIPE_X86_REGISTERS:temp0()).
311
fix_dst_operand(Opnd) ->
312
fix_mem_operand(Opnd, ?HIPE_X86_REGISTERS:temp1()).
314
fix_mem_operand(Opnd, Reg) -> % -> {[fixupcode], newop}
316
#x86_mem{base=Base,off=Off} ->
317
case is_mem_opnd(Base) of
319
case src_is_pseudo(Off) of
322
true -> % pseudo(reg)
323
Temp = clone(Off, Reg),
324
{[hipe_x86:mk_move(Off, Temp)],
325
Opnd#x86_mem{off=Temp}}
328
Temp = clone(Base, Reg),
329
case src_is_pseudo(Off) of
330
false -> % imm/reg(pseudo)
331
{[hipe_x86:mk_move(Base, Temp)],
332
Opnd#x86_mem{base=Temp}};
333
true -> % pseudo1(pseudo0)
334
{[hipe_x86:mk_move(Base, Temp),
335
hipe_x86:mk_alu('add', Off, Temp)],
336
Opnd#x86_mem{base=Temp, off=hipe_x86:mk_imm(0)}}
343
%%% Check if an operand denotes a memory cell (mem or pseudo).
348
#x86_temp{} -> temp_is_pseudo(Opnd);
352
%%% Check if an operand is a pseudo-Temp.
354
src_is_pseudo(Src) ->
355
case hipe_x86:is_temp(Src) of
356
true -> temp_is_pseudo(Src);
360
temp_is_pseudo(Temp) ->
361
not(?HIPE_X86_REGISTERS:is_precoloured(hipe_x86:temp_reg(Temp))).
363
%%% Make Reg a clone of Dst (attach Dst's type to Reg).
368
#x86_mem{} -> hipe_x86:mem_type(Dst);
369
#x86_temp{} -> hipe_x86:temp_type(Dst)
371
hipe_x86:mk_temp(Reg, Type).
373
mk_move(Src, Dst=#x86_temp{type=double}) ->
374
hipe_x86:mk_fmove(Src, Dst);
376
hipe_x86:mk_move(Src, Dst).