1
%% ====================================================================
2
%% Filename : hipe_x86_ra_ls_postconditions.erl
3
%% Module : hipe_x86_ra_ls_postconditions
6
%% History : * 2001-07-24 Erik Johansson (happi@csd.uu.se):
10
%% $Date: 2003/04/10 15:40:39 $
12
%% ====================================================================
15
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17
-module(hipe_x86_ra_ls_postconditions).
18
-export([check_and_rewrite/4]).
19
-include("hipe_x86.hrl").
20
-define(HIPE_INSTRUMENT_COMPILER, true).
21
-include("../main/hipe.hrl").
22
-define(count_temp(T), ?cons_counter(counter_mfa_mem_temps, T)).
25
check_and_rewrite(X86Defun, Coloring, DontSpill, _Options) ->
26
%% io:format("Converting\n"),
27
TempMap = hipe_temp_map:cols2tuple(Coloring,hipe_x86_specific),
28
%% io:format("Rewriting\n"),
29
#defun{code=Code0} = X86Defun,
30
{Code1, NewDontSpill} = do_insns(Code0, TempMap, [], DontSpill),
31
{X86Defun#defun{code=Code1,
32
var_range={0, hipe_gensym:get_var()}},
33
Coloring, NewDontSpill}.
35
do_insns([I|Insns], TempMap, Is, DontSpill) ->
36
{NewIs, NewDontSpill} = do_insns(Insns, TempMap, Is, DontSpill),
37
{NewI, FinalDontSpill} = do_insn(I, TempMap, NewDontSpill),
38
{NewI ++ NewIs, FinalDontSpill};
39
do_insns([],_, Is, DontSpill) ->
42
do_insn(I, TempMap, DontSpill) -> % Insn -> Insn list
45
do_alu(I, TempMap, DontSpill);
47
do_cmp(I, TempMap, DontSpill);
49
do_jmp_switch(I, TempMap, DontSpill);
51
do_lea(I, TempMap, DontSpill);
53
do_move(I, TempMap, DontSpill);
55
do_movx(I, TempMap, DontSpill);
57
do_movx(I, TempMap, DontSpill);
59
do_fmov(I, TempMap, DontSpill);
61
do_shift(I, TempMap, DontSpill);
63
%% comment, jmp*, label, pseudo_call, pseudo_jcc, pseudo_tailcall,
64
%% pseudo_tailcall_prepare, push, ret
70
do_alu(I, TempMap, DontSpill) ->
71
#alu{src=Src0,dst=Dst0} = I,
72
{FixSrc,Src,FixDst,Dst, NewDontSpill} =
73
do_binary(Src0, Dst0, TempMap, DontSpill),
74
{FixSrc ++ FixDst ++ [I#alu{src=Src,dst=Dst}], NewDontSpill}.
79
do_cmp(I, TempMap, DontSpill) ->
80
#cmp{src=Src0,dst=Dst0} = I,
81
{FixSrc, Src, FixDst, Dst, NewDontSpill} =
82
do_binary(Src0, Dst0, TempMap, DontSpill),
83
{FixSrc ++ FixDst ++ [I#cmp{src=Src,dst=Dst}], NewDontSpill}.
85
%%% Fix a jmp_switch op.
87
do_jmp_switch(I, TempMap, DontSpill) ->
88
#jmp_switch{temp=Temp} = I,
89
case is_spilled(Temp, TempMap) of
94
NewTmp = spill_temp('untagged'),
96
{[hipe_x86:mk_move(Temp, NewTmp), I#jmp_switch{temp=NewTmp}],
102
do_lea(I, TempMap, DontSpill) ->
104
case is_spilled(Temp, TempMap) of
108
NewTmp = spill_temp('untagged'),
109
{[I#lea{temp=NewTmp}, hipe_x86:mk_move(NewTmp, Temp)],
115
do_move(I, TempMap, DontSpill) ->
116
#move{src=Src0,dst=Dst0} = I,
117
{FixSrc, Src, FixDst, Dst, NewDontSpill} =
119
#x86_mem{type=byte} ->
120
do_byte_move(Src0, Dst0,
123
do_binary(Src0, Dst0,
126
{FixSrc ++ FixDst ++ [I#move{src=Src,dst=Dst}],
130
do_movx(I, TempMap, DontSpill) ->
131
{FixSrc, Src, DontSpill1} =
133
#movsx{src=Src0,dst=Dst0} ->
134
fix_src_operand(Src0, TempMap);
135
#movzx{src=Src0,dst=Dst0} ->
136
fix_src_operand(Src0, TempMap)
138
{FixDst, Dst, DontSpill2} = fix_dst_operand(Dst0, TempMap),
140
case is_spilled(Dst, TempMap) of
144
[hipe_x86:mk_movsx(Src, Dst)];
146
[hipe_x86:mk_movzx(Src, Dst)]
154
[hipe_x86:mk_movsx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)];
156
[hipe_x86:mk_movzx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)]
161
DontSpill3 ++ DontSpill2 ++
162
DontSpill1 ++ DontSpill}.
165
do_fmov(I, TempMap, DontSpill) ->
166
#fmov{src=Src0,dst=Dst0} = I,
167
{FixSrc, Src, FixDst, Dst, NewDontSpill} =
168
do_binary(Src0, Dst0,
170
{FixSrc ++ FixDst ++ [I#fmov{src=Src,dst=Dst}],
173
%%% Fix a shift operation
174
%%% 1. remove pseudos from any explicit memory operands
175
%%% 2. if the source is a register or memory position
176
%%% make sure to move it to %ecx
178
do_shift(I, TempMap, DontSpill) ->
179
#shift{src=Src0,dst=Dst0} = I,
180
{FixDst, Dst, DontSpill2} = fix_dst_operand(Dst0, TempMap),
181
DontSpill3 = DontSpill ++ DontSpill2,
182
Reg = hipe_x86_registers:ecx(),
185
{FixDst ++ [I#shift{dst=Dst}], DontSpill3};
186
#x86_temp{reg=Reg} ->
187
{FixDst ++ [I#shift{dst=Dst}], DontSpill3}
190
do_byte_move(Src0, Dst0,TempMap, DontSpill) ->
191
{FixSrc, Src, DontSpill1} = fix_src_operand(Src0, TempMap),
192
{FixDst, Dst, DontSpill2} = fix_dst_operand(Dst0, TempMap),
193
{FixSrc3, Src3, DontSpill3} =
197
#x86_temp{reg=Reg} ->
201
false -> %hardcode a move to eax for all temps not in the four low regs
202
Src2 = hipe_x86:mk_temp(hipe_x86_registers:eax(), untagged),
203
FixSrc2 = FixSrc ++ [hipe_x86:mk_move(Src, Src2)],
204
{FixSrc2, Src2, [Src2]}
207
{FixSrc3, Src3, FixDst, Dst,
208
DontSpill3 ++ DontSpill2 ++
209
DontSpill1 ++ DontSpill}.
211
%%% Fix the operands of a binary op.
212
%%% 1. remove pseudos from any explicit memory operands
213
%%% 2. if both operands are (implicit or explicit) memory operands,
214
%%% move src to a reg and use reg as src in the original insn
216
do_binary(Src0, Dst0, TempMap, DontSpill) ->
217
{FixSrc, Src, DontSpill1} = fix_src_operand(Src0, TempMap),
218
{FixDst, Dst, DontSpill2} = fix_dst_operand(Dst0, TempMap),
219
{FixSrc3, Src3, DontSpill3} =
220
case is_mem_opnd(Src, TempMap) of
224
case is_mem_opnd(Dst, TempMap) of
229
FixSrc2 = FixSrc ++ [hipe_x86:mk_move(Src, Src2)],
230
{FixSrc2, Src2, [Src2]}
233
{FixSrc3, Src3, FixDst, Dst,
234
DontSpill3 ++ DontSpill2 ++
235
DontSpill1 ++ DontSpill}.
237
%%% Fix any x86_mem operand to not refer to any spilled temps.
239
fix_src_operand(Opnd,TmpMap) ->
240
fix_mem_operand(Opnd, TmpMap, hipe_x86_registers:temp1()).
242
fix_dst_operand(Opnd, TempMap) ->
243
fix_mem_operand(Opnd,TempMap, hipe_x86_registers:temp0()).
245
fix_mem_operand(Opnd, TempMap, Reg) -> % -> {[fixupcode], newop, DontSpill}
247
#x86_mem{base=Base,off=Off} ->
248
case is_mem_opnd(Base, TempMap) of
250
%% XXX: (Mikael) this test looks wrong to me, since it will
251
%% falsely trigger for temps that are actual registers.
252
%% ra_dummy uses src_is_pseudo() here.
254
%% The assembler can't handle reg offsets, so at the moment
255
%% it is handled here. (Happi)
256
case hipe_x86:is_imm(Off) of
259
false -> % pseudo(pseudo)
260
Temp = clone(Off, Reg),
261
{[hipe_x86:mk_move(Base, Temp),
262
hipe_x86:mk_alu('add', Off, Temp)],
263
Opnd#x86_mem{base=Temp, off=hipe_x86:mk_imm(0)},
268
Temp = clone(Base, Reg),
269
case hipe_x86:is_imm(Off) of
270
true -> % imm/reg(pseudo)
271
{[hipe_x86:mk_move(Base, Temp)],
272
Opnd#x86_mem{base=Temp},
274
false -> % pseudo(pseudo)
275
{[hipe_x86:mk_move(Base, Temp),
276
hipe_x86:mk_alu('add', Off, Temp)],
277
Opnd#x86_mem{base=Temp, off=hipe_x86:mk_imm(0)},
285
%%% Check if an operand denotes a memory cell (mem or pseudo).
287
is_mem_opnd(Opnd, TempMap) ->
292
Reg = hipe_x86:temp_reg(Opnd),
293
case hipe_x86:temp_is_allocatable(Opnd) of
295
case size(TempMap) > Reg of
298
hipe_temp_map:is_spilled(Reg,
311
%% io:format("Op ~w mem: ~w\n",[Opnd,R]),
314
%%% Check if an operand is a spilled Temp.
316
%src_is_spilled(Src, TempMap) ->
317
% case hipe_x86:is_temp(Src) of
319
% Reg = hipe_x86:temp_reg(Src),
320
% case hipe_x86:temp_is_allocatable(Src) of
322
% case size(TempMap) > Reg of
324
% case hipe_temp_map:is_spilled(Reg, TempMap) of
339
is_spilled(Temp, TempMap) ->
340
case hipe_x86:temp_is_allocatable(Temp) of
342
Reg = hipe_x86:temp_reg(Temp),
343
case size(TempMap) > Reg of
345
case hipe_temp_map:is_spilled(Reg, TempMap) of
359
%%% Make Reg a clone of Dst (attach Dst's type to Reg).
364
#x86_mem{} -> hipe_x86:mem_type(Dst);
365
#x86_temp{} -> hipe_x86:temp_type(Dst)
370
hipe_x86:mk_temp(hipe_x86_registers:temp1(),Type).
375
#x86_mem{} -> hipe_x86:mem_type(Dst);
376
#x86_temp{} -> hipe_x86:temp_type(Dst)
378
hipe_x86:mk_temp(Reg,Type).