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_ppc_ra_postconditions).
16
17-export([check_and_rewrite/3, check_and_rewrite2/3]).
18
19-include("hipe_ppc.hrl").
20
21check_and_rewrite(CFG, Coloring, Allocator) ->
22  TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_ppc_specific, no_context),
23  check_and_rewrite2(CFG, TempMap, Allocator).
24
25check_and_rewrite2(CFG, TempMap, Allocator) ->
26  Strategy = strategy(Allocator),
27  do_bbs(hipe_ppc_cfg:labels(CFG), TempMap, Strategy, CFG, false).
28
29strategy(Allocator) ->
30  case Allocator of
31    'normal' -> 'new';
32    'linearscan' -> 'fixed';
33    'naive' -> 'fixed'
34  end.
35
36do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill};
37do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) ->
38  Code0 = hipe_bb:code(BB = hipe_ppc_cfg:bb(CFG0, Lbl)),
39  {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0),
40  CFG = hipe_ppc_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
41  do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill).
42
43do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
44  {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
45  do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
46do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
47  {lists:reverse(Accum), DidSpill}.
48
49do_insn(I, TempMap, Strategy) ->
50  case I of
51    #alu{} -> do_alu(I, TempMap, Strategy);
52    #cmp{} -> do_cmp(I, TempMap, Strategy);
53    #load{} -> do_load(I, TempMap, Strategy);
54    #loadx{} -> do_loadx(I, TempMap, Strategy);
55    #mfspr{} -> do_mfspr(I, TempMap, Strategy);
56    #mtcr{} -> do_mtcr(I, TempMap, Strategy);
57    #mtspr{} -> do_mtspr(I, TempMap, Strategy);
58    #pseudo_li{} -> do_pseudo_li(I, TempMap, Strategy);
59    #pseudo_move{} -> do_pseudo_move(I, TempMap, Strategy);
60    #pseudo_spill_move{} -> do_pseudo_spill_move(I, TempMap, Strategy);
61    #store{} -> do_store(I, TempMap, Strategy);
62    #storex{} -> do_storex(I, TempMap, Strategy);
63    #unary{} -> do_unary(I, TempMap, Strategy);
64    #lfd{} -> do_lfd(I, TempMap, Strategy);
65    #lfdx{} -> do_lfdx(I, TempMap, Strategy);
66    #stfd{} -> do_stfd(I, TempMap, Strategy);
67    #stfdx{} -> do_stfdx(I, TempMap, Strategy);
68    _ -> {[I], false}
69  end.
70
71%%% Fix relevant instruction types.
72
73do_alu(I=#alu{dst=Dst,src1=Src1,src2=Src2}, TempMap, Strategy) ->
74  {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
75  {FixSrc1,NewSrc1,DidSpill2} = fix_src1(Src1, TempMap, Strategy),
76  {FixSrc2,NewSrc2,DidSpill3} = fix_src2_or_imm(Src2, TempMap, Strategy),
77  NewI = I#alu{dst=NewDst,src1=NewSrc1,src2=NewSrc2},
78  {FixSrc1 ++ FixSrc2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
79
80do_cmp(I=#cmp{src1=Src1,src2=Src2}, TempMap, Strategy) ->
81  {FixSrc1,NewSrc1,DidSpill1} = fix_src1(Src1, TempMap, Strategy),
82  {FixSrc2,NewSrc2,DidSpill2} = fix_src2_or_imm(Src2, TempMap, Strategy),
83  NewI = I#cmp{src1=NewSrc1,src2=NewSrc2},
84  {FixSrc1 ++ FixSrc2 ++ [NewI], DidSpill1 or DidSpill2}.
85
86do_load(I=#load{dst=Dst,base=Base}, TempMap, Strategy) ->
87  {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
88  {FixBase,NewBase,DidSpill2} = fix_src1(Base, TempMap, Strategy),
89  NewI = I#load{dst=NewDst,base=NewBase},
90  {FixBase ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
91
92do_loadx(I=#loadx{dst=Dst,base1=Base1,base2=Base2}, TempMap, Strategy) ->
93  {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
94  {FixBase1,NewBase1,DidSpill2} = fix_src1(Base1, TempMap, Strategy),
95  {FixBase2,NewBase2,DidSpill3} = fix_src2(Base2, TempMap, Strategy),
96  NewI = I#loadx{dst=NewDst,base1=NewBase1,base2=NewBase2},
97  {FixBase1 ++ FixBase2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
98
99do_mfspr(I=#mfspr{dst=Dst}, TempMap, Strategy) ->
100  {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
101  NewI = I#mfspr{dst=NewDst},
102  {[NewI | FixDst], DidSpill}.
103
104do_mtcr(I=#mtcr{src=Src}, TempMap, Strategy) ->
105  {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy),
106  NewI = I#mtcr{src=NewSrc},
107  {FixSrc ++ [NewI], DidSpill}.
108
109do_mtspr(I=#mtspr{src=Src}, TempMap, Strategy) ->
110  {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy),
111  NewI = I#mtspr{src=NewSrc},
112  {FixSrc ++ [NewI], DidSpill}.
113
114do_pseudo_li(I=#pseudo_li{dst=Dst}, TempMap, Strategy) ->
115  {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
116  NewI = I#pseudo_li{dst=NewDst},
117  {[NewI | FixDst], DidSpill}.
118
119do_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, TempMap, Strategy) ->
120  %% Either Dst or Src (but not both) may be a pseudo temp.
121  %% pseudo_move, pseudo_spill_move, and pseudo_tailcall are
122  %% special cases: in all other instructions, all temps
123  %% must be non-pseudos after register allocation.
124  case temp_is_spilled(Src, TempMap)
125    andalso temp_is_spilled(Dst, TempMap)
126  of
127    true -> % Turn into pseudo_spill_move
128      Temp = clone(Src, temp1(Strategy)),
129      NewI = #pseudo_spill_move{dst=Dst,temp=Temp,src=Src},
130      {[NewI], true};
131    _ ->
132      {[I], false}
133  end.
134
135do_pseudo_spill_move(I=#pseudo_spill_move{temp=Temp}, TempMap, _Strategy) ->
136  %% Temp is above the low water mark and must not have been spilled
137  false = temp_is_spilled(Temp, TempMap),
138  {[I], false}.
139
140do_store(I=#store{src=Src,base=Base}, TempMap, Strategy) ->
141  {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
142  {FixBase,NewBase,DidSpill2} = fix_src2(Base, TempMap, Strategy),
143  NewI = I#store{src=NewSrc,base=NewBase},
144  {FixSrc ++ FixBase ++ [NewI], DidSpill1 or DidSpill2}.
145
146do_storex(I=#storex{src=Src,base1=Base1,base2=Base2}, TempMap, Strategy) ->
147  {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
148  {FixBase1,NewBase1,DidSpill2} = fix_src2(Base1, TempMap, Strategy),
149  {FixBase2,NewBase2,DidSpill3} = fix_src3(Base2, TempMap, Strategy),
150  NewI = I#storex{src=NewSrc,base1=NewBase1,base2=NewBase2},
151  {FixSrc ++ FixBase1 ++ FixBase2 ++ [NewI], DidSpill1 or DidSpill2 or DidSpill3}.
152
153do_unary(I=#unary{dst=Dst,src=Src}, TempMap, Strategy) ->
154  {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
155  {FixSrc,NewSrc,DidSpill2} = fix_src1(Src, TempMap, Strategy),
156  NewI = I#unary{dst=NewDst,src=NewSrc},
157  {FixSrc ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
158
159do_lfd(I=#lfd{base=Base}, TempMap, Strategy) ->
160  {FixBase,NewBase,DidSpill} = fix_src1(Base, TempMap, Strategy),
161  NewI = I#lfd{base=NewBase},
162  {FixBase ++ [NewI], DidSpill}.
163
164do_lfdx(I=#lfdx{base1=Base1,base2=Base2}, TempMap, Strategy) ->
165  {FixBase1,NewBase1,DidSpill1} = fix_src1(Base1, TempMap, Strategy),
166  {FixBase2,NewBase2,DidSpill2} = fix_src2(Base2, TempMap, Strategy),
167  NewI = I#lfdx{base1=NewBase1,base2=NewBase2},
168  {FixBase1 ++ FixBase2 ++ [NewI], DidSpill1 or DidSpill2}.
169
170do_stfd(I=#stfd{base=Base}, TempMap, Strategy) ->
171  {FixBase,NewBase,DidSpill} = fix_src1(Base, TempMap, Strategy),
172  NewI = I#stfd{base=NewBase},
173  {FixBase ++ [NewI], DidSpill}.
174
175do_stfdx(I=#stfdx{base1=Base1,base2=Base2}, TempMap, Strategy) ->
176  {FixBase1,NewBase1,DidSpill1} = fix_src1(Base1, TempMap, Strategy),
177  {FixBase2,NewBase2,DidSpill2} = fix_src2(Base2, TempMap, Strategy),
178  NewI = I#stfdx{base1=NewBase1,base2=NewBase2},
179  {FixBase1 ++ FixBase2 ++ [NewI], DidSpill1 or DidSpill2}.
180
181%%% Fix Dst and Src operands.
182
183fix_src2_or_imm(Src2, TempMap, Strategy) ->
184  case Src2 of
185    #ppc_temp{} -> fix_src2(Src2, TempMap, Strategy);
186    _ -> {[], Src2, false}
187  end.
188
189fix_src1(Src, TempMap, Strategy) ->
190  fix_src(Src, TempMap, temp1(Strategy)).
191
192temp1('new') -> [];
193temp1('fixed') -> hipe_ppc_registers:temp1().
194
195fix_src2(Src, TempMap, Strategy) ->
196  fix_src(Src, TempMap, temp2(Strategy)).
197
198temp2('new') -> [];
199temp2('fixed') -> hipe_ppc_registers:temp2().
200
201fix_src3(Src, TempMap, Strategy) -> % storex :-(
202  fix_src(Src, TempMap, temp3(Strategy)).
203
204temp3('new') -> [];
205temp3('fixed') -> hipe_ppc_registers:temp3().
206
207fix_src(Src, TempMap, RegOpt) ->
208  case temp_is_spilled(Src, TempMap) of
209    true ->
210      NewSrc = clone(Src, RegOpt),
211      {[hipe_ppc:mk_pseudo_move(NewSrc, Src)],
212       NewSrc,
213       true};
214    _ ->
215      {[], Src, false}
216  end.
217
218fix_dst(Dst, TempMap, Strategy) ->
219  case temp_is_spilled(Dst, TempMap) of
220    true ->
221      NewDst = clone(Dst, temp3(Strategy)),
222      {[hipe_ppc:mk_pseudo_move(Dst, NewDst)],
223       NewDst,
224       true};
225    _ ->
226      {[], Dst, false}
227  end.
228
229%%% Check if an operand is a pseudo-temp.
230
231temp_is_spilled(Temp, []) -> % special case for naive regalloc
232  not(hipe_ppc:temp_is_precoloured(Temp));
233temp_is_spilled(Temp, TempMap) ->
234  case hipe_ppc:temp_is_allocatable(Temp) of
235    true ->
236      Reg = hipe_ppc:temp_reg(Temp),
237      tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
238    false -> true
239  end.
240
241%%% Make a certain reg into a clone of Temp.
242
243clone(Temp, RegOpt) ->
244  Type = hipe_ppc:temp_type(Temp),
245  case RegOpt of
246    [] -> hipe_ppc:mk_new_temp(Type);
247    Reg -> hipe_ppc:mk_temp(Reg, Type)
248  end.
249