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_fp). 16-export([check_and_rewrite/2]). 17-include("hipe_ppc.hrl"). 18 19check_and_rewrite(CFG, Coloring) -> 20 TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_ppc_specific_fp, no_context), 21 do_bbs(hipe_ppc_cfg:labels(CFG), TempMap, CFG, false). 22 23do_bbs([], _TempMap, CFG, DidSpill) -> {CFG, DidSpill}; 24do_bbs([Lbl|Lbls], TempMap, CFG0, DidSpill0) -> 25 Code0 = hipe_bb:code(BB = hipe_ppc_cfg:bb(CFG0, Lbl)), 26 {Code, DidSpill} = do_insns(Code0, TempMap, [], DidSpill0), 27 CFG = hipe_ppc_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)), 28 do_bbs(Lbls, TempMap, CFG, DidSpill). 29 30do_insns([I|Insns], TempMap, Accum, DidSpill0) -> 31 {NewIs, DidSpill1} = do_insn(I, TempMap), 32 do_insns(Insns, TempMap, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1); 33do_insns([], _TempMap, Accum, DidSpill) -> 34 {lists:reverse(Accum), DidSpill}. 35 36do_insn(I, TempMap) -> 37 case I of 38 #lfd{} -> do_lfd(I, TempMap); 39 #lfdx{} -> do_lfdx(I, TempMap); 40 #stfd{} -> do_stfd(I, TempMap); 41 #stfdx{} -> do_stfdx(I, TempMap); 42 #fp_binary{} -> do_fp_binary(I, TempMap); 43 #fp_unary{} -> do_fp_unary(I, TempMap); 44 #pseudo_fmove{} -> do_pseudo_fmove(I, TempMap); 45 #pseudo_spill_fmove{} -> do_pseudo_spill_fmove(I, TempMap); 46 _ -> {[I], false} 47 end. 48 49%%% Fix relevant instruction types. 50 51do_lfd(I=#lfd{dst=Dst}, TempMap) -> 52 {FixDst, NewDst, DidSpill} = fix_dst(Dst, TempMap), 53 NewI = I#lfd{dst=NewDst}, 54 {[NewI | FixDst], DidSpill}. 55 56do_lfdx(I=#lfdx{dst=Dst}, TempMap) -> 57 {FixDst, NewDst, DidSpill} = fix_dst(Dst, TempMap), 58 NewI = I#lfdx{dst=NewDst}, 59 {[NewI | FixDst], DidSpill}. 60 61do_stfd(I=#stfd{src=Src}, TempMap) -> 62 {FixSrc, NewSrc, DidSpill} = fix_src(Src, TempMap), 63 NewI = I#stfd{src=NewSrc}, 64 {FixSrc ++ [NewI], DidSpill}. 65 66do_stfdx(I=#stfdx{src=Src}, TempMap) -> 67 {FixSrc, NewSrc, DidSpill} = fix_src(Src, TempMap), 68 NewI = I#stfdx{src=NewSrc}, 69 {FixSrc ++ [NewI], DidSpill}. 70 71do_fp_binary(I=#fp_binary{dst=Dst,src1=Src1,src2=Src2}, TempMap) -> 72 {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap), 73 {FixSrc1,NewSrc1,DidSpill2} = fix_src(Src1, TempMap), 74 {FixSrc2,NewSrc2,DidSpill3} = fix_src(Src2, TempMap), 75 NewI = I#fp_binary{dst=NewDst,src1=NewSrc1,src2=NewSrc2}, 76 {FixSrc1 ++ FixSrc2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}. 77 78do_fp_unary(I=#fp_unary{dst=Dst,src=Src}, TempMap) -> 79 {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap), 80 {FixSrc,NewSrc,DidSpill2} = fix_src(Src, TempMap), 81 NewI = I#fp_unary{dst=NewDst,src=NewSrc}, 82 {FixSrc ++ [NewI | FixDst], DidSpill1 or DidSpill2}. 83 84do_pseudo_fmove(I=#pseudo_fmove{dst=Dst,src=Src}, TempMap) -> 85 case temp_is_spilled(Src, TempMap) 86 andalso temp_is_spilled(Dst, TempMap) 87 of 88 true -> % Turn into pseudo_spill_fmove 89 Temp = clone(Src), 90 NewI = #pseudo_spill_fmove{dst=Dst,temp=Temp,src=Src}, 91 {[NewI], true}; 92 _ -> 93 {[I], false} 94 end. 95 96do_pseudo_spill_fmove(I=#pseudo_spill_fmove{temp=Temp}, TempMap) -> 97 %% Temp is above the low water mark and must not have been spilled 98 false = temp_is_spilled(Temp, TempMap), 99 {[I], false}. 100 101%%% Fix Dst and Src operands. 102 103fix_src(Src, TempMap) -> 104 case temp_is_spilled(Src, TempMap) of 105 true -> 106 NewSrc = clone(Src), 107 {[hipe_ppc:mk_pseudo_fmove(NewSrc, Src)], NewSrc, true}; 108 _ -> 109 {[], Src, false} 110 end. 111 112fix_dst(Dst, TempMap) -> 113 case temp_is_spilled(Dst, TempMap) of 114 true -> 115 NewDst = clone(Dst), 116 {[hipe_ppc:mk_pseudo_fmove(Dst, NewDst)], NewDst, true}; 117 _ -> 118 {[], Dst, false} 119 end. 120 121%%% Check if an operand is a pseudo-temp. 122 123temp_is_spilled(Temp, TempMap) -> 124 case hipe_ppc:temp_is_allocatable(Temp) of 125 true -> 126 Reg = hipe_ppc:temp_reg(Temp), 127 tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap); 128 false -> true 129 end. 130 131%%% Create a new temp with the same type as an old one. 132 133clone(Temp) -> 134 Type = hipe_ppc:temp_type(Temp), % XXX: always double? 135 hipe_ppc:mk_new_temp(Type). 136