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