PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/hipe/arm/hipe_arm_ra_postconditions.erl

https://github.com/dustin/otp
Erlang | 278 lines | 204 code | 42 blank | 32 comment | 0 complexity | 23274996cb9758e848e6151c85eb572b MD5 | raw file
  1. %% -*- erlang-indent-level: 2 -*-
  2. %%
  3. %% %CopyrightBegin%
  4. %%
  5. %% Copyright Ericsson AB 2005-2009. All Rights Reserved.
  6. %%
  7. %% The contents of this file are subject to the Erlang Public License,
  8. %% Version 1.1, (the "License"); you may not use this file except in
  9. %% compliance with the License. You should have received a copy of the
  10. %% Erlang Public License along with this software. If not, it can be
  11. %% retrieved online at http://www.erlang.org/.
  12. %%
  13. %% Software distributed under the License is distributed on an "AS IS"
  14. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  15. %% the License for the specific language governing rights and limitations
  16. %% under the License.
  17. %%
  18. %% %CopyrightEnd%
  19. %%
  20. -module(hipe_arm_ra_postconditions).
  21. -export([check_and_rewrite/3, check_and_rewrite2/3]).
  22. -include("hipe_arm.hrl").
  23. check_and_rewrite(Defun, Coloring, Allocator) ->
  24. TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific),
  25. check_and_rewrite2(Defun, TempMap, Allocator).
  26. check_and_rewrite2(Defun, TempMap, Allocator) ->
  27. Strategy = strategy(Allocator),
  28. #defun{code=Code0} = Defun,
  29. {Code1,DidSpill} = do_insns(Code0, TempMap, Strategy, [], false),
  30. VarRange = {0, hipe_gensym:get_var(arm)},
  31. {Defun#defun{code=Code1, var_range=VarRange},
  32. DidSpill}.
  33. strategy(Allocator) ->
  34. case Allocator of
  35. 'normal' -> 'new';
  36. 'linearscan' -> 'fixed';
  37. 'naive' -> 'fixed'
  38. end.
  39. do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
  40. {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
  41. do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
  42. do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
  43. {lists:reverse(Accum), DidSpill}.
  44. do_insn(I, TempMap, Strategy) ->
  45. case I of
  46. #alu{} -> do_alu(I, TempMap, Strategy);
  47. #cmp{} -> do_cmp(I, TempMap, Strategy);
  48. #load{} -> do_load(I, TempMap, Strategy);
  49. #ldrsb{} -> do_ldrsb(I, TempMap, Strategy);
  50. #move{} -> do_move(I, TempMap, Strategy);
  51. #pseudo_call{} -> do_pseudo_call(I, TempMap, Strategy);
  52. #pseudo_li{} -> do_pseudo_li(I, TempMap, Strategy);
  53. #pseudo_move{} -> do_pseudo_move(I, TempMap, Strategy);
  54. #pseudo_switch{} -> do_pseudo_switch(I, TempMap, Strategy);
  55. #pseudo_tailcall{} -> do_pseudo_tailcall(I, TempMap, Strategy);
  56. #smull{} -> do_smull(I, TempMap, Strategy);
  57. #store{} -> do_store(I, TempMap, Strategy);
  58. _ -> {[I], false}
  59. end.
  60. %%% Fix relevant instruction types.
  61. do_alu(I=#alu{dst=Dst,src=Src,am1=Am1}, TempMap, Strategy) ->
  62. {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
  63. {FixSrc,NewSrc,DidSpill2} = fix_src1(Src, TempMap, Strategy),
  64. {FixAm1,NewAm1,DidSpill3} = fix_am1(Am1, TempMap, Strategy),
  65. NewI = I#alu{dst=NewDst,src=NewSrc,am1=NewAm1},
  66. {FixSrc ++ FixAm1 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
  67. do_cmp(I=#cmp{src=Src,am1=Am1}, TempMap, Strategy) ->
  68. {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
  69. {FixAm1,NewAm1,DidSpill2} = fix_am1(Am1, TempMap, Strategy),
  70. NewI = I#cmp{src=NewSrc,am1=NewAm1},
  71. {FixSrc ++ FixAm1 ++ [NewI], DidSpill1 or DidSpill2}.
  72. do_load(I=#load{dst=Dst,am2=Am2}, TempMap, Strategy) ->
  73. {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
  74. {FixAm2,NewAm2,DidSpill2} = fix_am2(Am2, TempMap, Strategy),
  75. NewI = I#load{dst=NewDst,am2=NewAm2},
  76. {FixAm2 ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
  77. do_ldrsb(I=#ldrsb{dst=Dst,am3=Am3}, TempMap, Strategy) ->
  78. {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
  79. {FixAm3,NewAm3,DidSpill2} = fix_am3(Am3, TempMap, Strategy),
  80. NewI = I#ldrsb{dst=NewDst,am3=NewAm3},
  81. {FixAm3 ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
  82. do_move(I=#move{dst=Dst,am1=Am1}, TempMap, Strategy) ->
  83. {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
  84. {FixAm1,NewAm1,DidSpill2} = fix_am1(Am1, TempMap, Strategy),
  85. NewI = I#move{dst=NewDst,am1=NewAm1},
  86. {FixAm1 ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
  87. do_pseudo_call(I=#pseudo_call{funv=FunV}, TempMap, Strategy) ->
  88. {FixFunV,NewFunV,DidSpill} = fix_funv(FunV, TempMap, Strategy),
  89. NewI = I#pseudo_call{funv=NewFunV},
  90. {FixFunV ++ [NewI], DidSpill}.
  91. do_pseudo_li(I=#pseudo_li{dst=Dst}, TempMap, Strategy) ->
  92. {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
  93. NewI = I#pseudo_li{dst=NewDst},
  94. {[NewI | FixDst], DidSpill}.
  95. do_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, TempMap, Strategy) ->
  96. %% Either Dst or Src (but not both) may be a pseudo temp.
  97. %% pseudo_move and pseudo_tailcall are special cases: in
  98. %% all other instructions, all temps must be non-pseudos
  99. %% after register allocation.
  100. case temp_is_spilled(Dst, TempMap) of
  101. true -> % Src must not be a pseudo
  102. {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy),
  103. NewI = I#pseudo_move{src=NewSrc},
  104. {FixSrc ++ [NewI], DidSpill};
  105. _ ->
  106. {[I], false}
  107. end.
  108. do_pseudo_switch(I=#pseudo_switch{jtab=JTab,index=Index}, TempMap, Strategy) ->
  109. {FixJTab,NewJTab,DidSpill1} = fix_src1(JTab, TempMap, Strategy),
  110. {FixIndex,NewIndex,DidSpill2} = fix_src2(Index, TempMap, Strategy),
  111. NewI = I#pseudo_switch{jtab=NewJTab,index=NewIndex},
  112. {FixJTab ++ FixIndex ++ [NewI], DidSpill1 or DidSpill2}.
  113. do_pseudo_tailcall(I=#pseudo_tailcall{funv=FunV}, TempMap, Strategy) ->
  114. {FixFunV,NewFunV,DidSpill} = fix_funv(FunV, TempMap, Strategy),
  115. NewI = I#pseudo_tailcall{funv=NewFunV},
  116. {FixFunV ++ [NewI], DidSpill}.
  117. do_smull(I=#smull{dstlo=DstLo,dsthi=DstHi,src1=Src1,src2=Src2}, TempMap, Strategy) ->
  118. %% ARM requires that DstLo, DstHi, and Src1 are distinct.
  119. %% We furthermore require Src1 and Src2 to be different in the fixed strategy.
  120. {FixDstLo,NewDstLo,DidSpill1} = fix_dst(DstLo, TempMap, Strategy), % temp1
  121. {FixDstHi,NewDstHi,DidSpill2} = fix_dst2(DstHi, TempMap, Strategy), % temp3
  122. {FixSrc1,NewSrc1,DidSpill3} = fix_src2(Src1, TempMap, Strategy), % temp2
  123. {FixSrc2,NewSrc2,DidSpill4} = fix_src1(Src2, TempMap, Strategy), % temp1; temp3 would be OK
  124. NewI = I#smull{dstlo=NewDstLo,dsthi=NewDstHi,src1=NewSrc1,src2=NewSrc2},
  125. {FixSrc1 ++ FixSrc2 ++ [NewI | FixDstLo ++ FixDstHi],
  126. DidSpill1 or DidSpill2 or DidSpill3 or DidSpill4}.
  127. do_store(I=#store{src=Src,am2=Am2}, TempMap, Strategy) ->
  128. {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
  129. {FixAm2,NewAm2,DidSpill2} = fix_am2(Am2, TempMap, Strategy),
  130. NewI = I#store{src=NewSrc,am2=NewAm2},
  131. {FixSrc ++ FixAm2 ++ [NewI], DidSpill1 or DidSpill2}.
  132. %%% Fix Dst and Src operands.
  133. fix_funv(FunV, TempMap, Strategy) ->
  134. case FunV of
  135. #arm_temp{} -> fix_src3(FunV, TempMap, Strategy);
  136. _ -> {[], FunV, false}
  137. end.
  138. fix_am1(Am1, TempMap, Strategy) ->
  139. case Am1 of
  140. #arm_temp{} ->
  141. fix_src2(Am1, TempMap, Strategy);
  142. {Src2,rrx} ->
  143. {Fix,New,DidSpill} = fix_src2(Src2, TempMap, Strategy),
  144. {Fix, {New,rrx}, DidSpill};
  145. {Src2,ShiftOp,ShiftArg} ->
  146. {FixSrc2,NewSrc2,DidSpill1} = fix_src2(Src2, TempMap, Strategy),
  147. {FixArg,NewArg,DidSpill2} =
  148. case ShiftArg of
  149. #arm_temp{} -> fix_src3(ShiftArg, TempMap, Strategy);
  150. _ -> {[], ShiftArg, false}
  151. end,
  152. %% order matters: FixArg may clobber temp2/Src2
  153. {FixArg ++ FixSrc2, {NewSrc2,ShiftOp,NewArg}, DidSpill1 or DidSpill2};
  154. _ -> {[], Am1, false}
  155. end.
  156. fix_am2(Am2=#am2{src=Src2,offset=Offset}, TempMap, Strategy) ->
  157. {FixSrc2,NewSrc2,DidSpill1} = fix_src2(Src2, TempMap, Strategy),
  158. {FixOffset,NewOffset,DidSpill2} = fix_am2offset(Offset, TempMap, Strategy),
  159. NewAm2 = Am2#am2{src=NewSrc2,offset=NewOffset},
  160. %% order matters: FixOffset may clobber temp2/Src2
  161. {FixOffset ++ FixSrc2, NewAm2, DidSpill1 or DidSpill2}.
  162. fix_am2offset(Offset, TempMap, Strategy) ->
  163. case Offset of
  164. #arm_temp{} ->
  165. fix_src3(Offset, TempMap, Strategy);
  166. {Src3,rrx} ->
  167. {Fix,New,DidSpill} = fix_src3(Src3, TempMap, Strategy),
  168. {Fix, {New,rrx}, DidSpill};
  169. {Src3,ShiftOp,Imm5} ->
  170. {Fix,New,DidSpill} = fix_src3(Src3, TempMap, Strategy),
  171. {Fix, {New,ShiftOp,Imm5}, DidSpill};
  172. _ ->
  173. {[], Offset, false}
  174. end.
  175. fix_am3(Am3=#am3{src=Src2,offset=Offset}, TempMap, Strategy) ->
  176. {FixSrc2,NewSrc2,DidSpill1} = fix_src2(Src2, TempMap, Strategy),
  177. {FixOffset,NewOffset,DidSpill2} = fix_am3offset(Offset, TempMap, Strategy),
  178. NewAm3 = Am3#am3{src=NewSrc2,offset=NewOffset},
  179. %% order matters: FixOffset may clobber temp2/Src2
  180. {FixOffset ++ FixSrc2, NewAm3, DidSpill1 or DidSpill2}.
  181. fix_am3offset(Offset, TempMap, Strategy) ->
  182. case Offset of
  183. #arm_temp{} -> fix_src3(Offset, TempMap, Strategy);
  184. _ -> {[], Offset, false}
  185. end.
  186. fix_src1(Src, TempMap, Strategy) ->
  187. fix_src(Src, TempMap, temp1(Strategy)).
  188. temp1('new') -> [];
  189. temp1('fixed') -> hipe_arm_registers:temp1().
  190. fix_src2(Src, TempMap, Strategy) ->
  191. fix_src(Src, TempMap, temp2(Strategy)).
  192. temp2('new') -> [];
  193. temp2('fixed') -> hipe_arm_registers:temp2().
  194. fix_src3(Src, TempMap, Strategy) ->
  195. fix_src(Src, TempMap, temp3(Strategy)).
  196. temp3('new') -> [];
  197. temp3('fixed') -> hipe_arm_registers:temp3().
  198. fix_src(Src, TempMap, RegOpt) ->
  199. case temp_is_spilled(Src, TempMap) of
  200. true ->
  201. NewSrc = clone(Src, RegOpt),
  202. {[hipe_arm:mk_pseudo_move(NewSrc, Src)],
  203. NewSrc,
  204. true};
  205. _ ->
  206. {[], Src, false}
  207. end.
  208. fix_dst(Dst, TempMap, Strategy) ->
  209. fix_dst_common(Dst, TempMap, temp1(Strategy)).
  210. fix_dst2(Dst, TempMap, Strategy) -> % only used for smull's DstHi
  211. fix_dst_common(Dst, TempMap, temp3(Strategy)).
  212. fix_dst_common(Dst, TempMap, RegOpt) ->
  213. case temp_is_spilled(Dst, TempMap) of
  214. true ->
  215. NewDst = clone(Dst, RegOpt),
  216. {[hipe_arm:mk_pseudo_move(Dst, NewDst)], NewDst, true};
  217. _ ->
  218. {[], Dst, false}
  219. end.
  220. %%% Check if an operand is a pseudo-temp.
  221. temp_is_spilled(Temp, []) -> % special case for naive regalloc
  222. not(hipe_arm:temp_is_precoloured(Temp));
  223. temp_is_spilled(Temp, TempMap) ->
  224. case hipe_arm:temp_is_allocatable(Temp) of
  225. true ->
  226. Reg = hipe_arm:temp_reg(Temp),
  227. tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
  228. false -> true
  229. end.
  230. %%% Make a certain reg into a clone of Temp.
  231. clone(Temp, RegOpt) ->
  232. Type = hipe_arm:temp_type(Temp),
  233. case RegOpt of
  234. [] -> hipe_arm:mk_new_temp(Type);
  235. Reg -> hipe_arm:mk_temp(Reg, Type)
  236. end.