aopt.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. {
  2. Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit contains the interface routines between the code generator
  5. and the optimizer.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. Unit aopt;
  20. {$i fpcdefs.inc}
  21. Interface
  22. Uses
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. aoptobj;
  25. Type
  26. TAsmOptimizer = class(TAoptObj)
  27. { _AsmL is the PAasmOutpout list that has to be optimized }
  28. Constructor create(_AsmL: TAsmList); virtual; reintroduce;
  29. { call the necessary optimizer procedures }
  30. Procedure Optimize;
  31. Destructor destroy;override;
  32. private
  33. procedure FindLoHiLabels;
  34. Procedure BuildLabelTableAndFixRegAlloc;
  35. procedure clear;
  36. procedure pass_1;
  37. End;
  38. TAsmOptimizerClass = class of TAsmOptimizer;
  39. var
  40. casmoptimizer : TAsmOptimizerClass;
  41. cpreregallocscheduler : TAsmOptimizerClass;
  42. procedure Optimize(AsmL:TAsmList);
  43. procedure PreRegallocSchedule(AsmL:TAsmList);
  44. Implementation
  45. uses
  46. cutils,
  47. globtype, globals,
  48. verbose,
  49. cpubase,
  50. cgbase,
  51. aoptda,aoptcpu,aoptcpud;
  52. Constructor TAsmOptimizer.create(_AsmL: TAsmList);
  53. Begin
  54. inherited create(_asml,nil,nil,nil);
  55. {setup labeltable, always necessary}
  56. New(LabelInfo);
  57. End;
  58. procedure TAsmOptimizer.FindLoHiLabels;
  59. { Walks through the paasmlist to find the lowest and highest label number. }
  60. { Returns the last Pai object of the current block }
  61. Var LabelFound: Boolean;
  62. p: tai;
  63. Begin
  64. LabelInfo^.LowLabel := High(longint);
  65. LabelInfo^.HighLabel := 0;
  66. LabelInfo^.LabelDif := 0;
  67. LabelInfo^.LabelTable:=nil;
  68. LabelFound := False;
  69. P := BlockStart;
  70. With LabelInfo^ Do
  71. Begin
  72. While Assigned(P) And
  73. ((P.typ <> Ait_Marker) Or
  74. (tai_Marker(P).Kind <> mark_AsmBlockStart)) Do
  75. Begin
  76. If (p.typ = ait_label) and
  77. (tai_Label(p).labsym.labeltype=alt_jump) and
  78. (tai_Label(p).labsym.is_used) Then
  79. Begin
  80. LabelFound := True;
  81. If (tai_Label(p).labsym.labelnr < LowLabel) Then
  82. LowLabel := tai_Label(p).labsym.labelnr;
  83. If (tai_Label(p).labsym.labelnr > HighLabel) Then
  84. HighLabel := tai_Label(p).labsym.labelnr
  85. End;
  86. GetNextInstruction(p, p)
  87. End;
  88. blockend:=p;
  89. If LabelFound
  90. Then LabelDif := HighLabel-LowLabel+1
  91. Else LabelDif := 0
  92. End
  93. End;
  94. Procedure TAsmOptimizer.BuildLabelTableAndFixRegAlloc;
  95. { Builds a table with the locations of the labels in the TAsmList. }
  96. { Also fixes some RegDeallocs like "# %eax released; push (%eax)" }
  97. Var p,hp1, hp2: tai;
  98. Regs: TAllUsedRegs;
  99. LabelIdx : longint;
  100. Begin
  101. CreateUsedRegs(Regs);
  102. With LabelInfo^ Do
  103. begin
  104. If (LabelDif <> 0) Then
  105. Begin
  106. GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
  107. FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
  108. end;
  109. p := BlockStart;
  110. While (P <> BlockEnd) Do
  111. Begin
  112. Case p.typ Of
  113. ait_Label:
  114. begin
  115. If tai_label(p).labsym.is_used and
  116. (tai_Label(p).labsym.labeltype=alt_jump) then
  117. begin
  118. LabelIdx:=tai_label(p).labsym.labelnr-LowLabel;
  119. if LabelIdx>int64(LabelDif) then
  120. internalerror(200604202);
  121. LabelTable^[LabelIdx].PaiObj := p;
  122. end;
  123. end;
  124. ait_regAlloc:
  125. begin
  126. if tai_regalloc(p).ratype=ra_alloc then
  127. Begin
  128. If Not(RegInUsedRegs(tai_regalloc(p).Reg,Regs)) Then
  129. IncludeRegInUsedRegs(tai_regalloc(p).Reg,Regs)
  130. Else
  131. Begin
  132. hp1 := tai(p.previous);
  133. {$ifdef DEBUG_OPTALLOC}
  134. AsmL.InsertAfter(tai_comment.Create(strpnew('Removed allocation of '+std_regname(tai_regalloc(p).Reg))),p);
  135. {$endif DEBUG_OPTALLOC}
  136. AsmL.remove(p);
  137. p.free;
  138. p := hp1;
  139. { not sure if this is useful, it even skips previous deallocs of the register (FK)
  140. hp1 := p;
  141. hp2 := nil;
  142. While GetLastInstruction(hp1, hp1) And
  143. Not(RegInInstruction(tai_regalloc(p).Reg, hp1)) Do
  144. hp2:=hp1;
  145. If hp2<>nil Then
  146. Begin
  147. hp1:=tai_regalloc.DeAlloc(tai_regalloc(p).Reg,hp2);
  148. InsertLLItem(tai(hp2.previous), hp2, hp1);
  149. End;
  150. }
  151. End;
  152. End
  153. else if tai_regalloc(p).ratype=ra_dealloc then
  154. Begin
  155. ExcludeRegFromUsedRegs(tai_regalloc(p).Reg,Regs);
  156. hp1 := p;
  157. hp2 := nil;
  158. While Not(FindRegAlloc(tai_regalloc(p).Reg, tai(hp1.Next))) And
  159. GetNextInstruction(hp1, hp1) And
  160. RegInInstruction(tai_regalloc(p).Reg, hp1) Do
  161. hp2 := hp1;
  162. If hp2 <> nil Then
  163. Begin
  164. hp1 := tai(p.previous);
  165. {$ifdef DEBUG_OPTALLOC}
  166. AsmL.InsertAfter(tai_comment.Create(strpnew('Moved deallocation of '+std_regname(tai_regalloc(p).Reg))),p);
  167. {$endif DEBUG_OPTALLOC}
  168. AsmL.Remove(p);
  169. InsertLLItem(hp2, tai(hp2.Next), p);
  170. {$ifdef DEBUG_OPTALLOC}
  171. AsmL.InsertAfter(tai_comment.Create(strpnew('Moved deallocation of '+std_regname(tai_regalloc(p).Reg)+' here')),hp2);
  172. {$endif DEBUG_OPTALLOC}
  173. p := hp1;
  174. End
  175. else if findregalloc(tai_regalloc(p).reg, tai(p.next))
  176. and getnextinstruction(p,hp1) then
  177. begin
  178. hp1 := tai(p.previous);
  179. {$ifdef DEBUG_OPTALLOC}
  180. AsmL.InsertAfter(tai_comment.Create(strpnew('Removed deallocation of '+std_regname(tai_regalloc(p).Reg))),p);
  181. {$endif DEBUG_OPTALLOC}
  182. AsmL.remove(p);
  183. p.free;
  184. p := hp1;
  185. // don't include here, since then the allocation will be removed when it's processed
  186. // include(usedregs,supreg);
  187. end;
  188. End
  189. End
  190. End;
  191. P := tai(p.Next);
  192. While Assigned(p) and
  193. (p <> blockend) and
  194. (p.typ in (SkipInstr - [ait_regalloc])) Do
  195. P := tai(P.Next)
  196. End;
  197. end;
  198. ReleaseUsedRegs(Regs);
  199. End;
  200. procedure tasmoptimizer.clear;
  201. begin
  202. if assigned(LabelInfo^.labeltable) then
  203. begin
  204. freemem(LabelInfo^.labeltable);
  205. LabelInfo^.labeltable := nil;
  206. end;
  207. LabelInfo^.labeldif:=0;
  208. LabelInfo^.lowlabel:=high(longint);
  209. LabelInfo^.highlabel:=0;
  210. end;
  211. procedure tasmoptimizer.pass_1;
  212. begin
  213. findlohilabels;
  214. BuildLabelTableAndFixRegAlloc;
  215. end;
  216. Procedure TAsmOptimizer.Optimize;
  217. Var
  218. HP: tai;
  219. pass: longint;
  220. Begin
  221. pass:=0;
  222. BlockStart := tai(AsmL.First);
  223. pass_1;
  224. While Assigned(BlockStart) Do
  225. Begin
  226. if pass = 0 then
  227. PrePeepHoleOpts;
  228. { Peephole optimizations }
  229. PeepHoleOptPass1;
  230. { Only perform them twice in the first pass }
  231. if pass = 0 then
  232. PeepHoleOptPass1;
  233. If (cs_opt_asmcse in current_settings.optimizerswitches) Then
  234. Begin
  235. // DFA:=TAOptDFACpu.Create(AsmL,BlockStart,BlockEnd,LabelInfo);
  236. { data flow analyzer }
  237. // DFA.DoDFA;
  238. { common subexpression elimination }
  239. { CSE;}
  240. End;
  241. { more peephole optimizations }
  242. PeepHoleOptPass2;
  243. { if pass = last_pass then }
  244. PostPeepHoleOpts;
  245. { free memory }
  246. clear;
  247. { continue where we left off, BlockEnd is either the start of an }
  248. { assembler block or nil}
  249. BlockStart := BlockEnd;
  250. While Assigned(BlockStart) And
  251. (BlockStart.typ = ait_Marker) And
  252. (tai_Marker(BlockStart).Kind = mark_AsmBlockStart) Do
  253. Begin
  254. { we stopped at an assembler block, so skip it }
  255. While GetNextInstruction(BlockStart, BlockStart) And
  256. ((BlockStart.Typ <> Ait_Marker) Or
  257. (tai_Marker(Blockstart).Kind <> mark_AsmBlockEnd)) Do;
  258. { blockstart now contains a tai_marker(mark_AsmBlockEnd) }
  259. If GetNextInstruction(BlockStart, HP) And
  260. ((HP.typ <> ait_Marker) Or
  261. (Tai_Marker(HP).Kind <> mark_AsmBlockStart)) Then
  262. { There is no assembler block anymore after the current one, so }
  263. { optimize the next block of "normal" instructions }
  264. pass_1
  265. { Otherwise, skip the next assembler block }
  266. else
  267. blockStart := hp;
  268. End
  269. End;
  270. End;
  271. Destructor TAsmOptimizer.Destroy;
  272. Begin
  273. if assigned(LabelInfo^.LabelTable) then
  274. Freemem(LabelInfo^.LabelTable);
  275. Dispose(LabelInfo);
  276. inherited Destroy;
  277. End;
  278. procedure Optimize(AsmL:TAsmList);
  279. var
  280. p : TAsmOptimizer;
  281. begin
  282. p:=casmoptimizer.Create(AsmL);
  283. p.Optimize;
  284. p.free
  285. end;
  286. procedure PreRegallocSchedule(AsmL:TAsmList);
  287. var
  288. p : TAsmOptimizer;
  289. begin
  290. p:=cpreregallocscheduler.Create(AsmL);
  291. p.Optimize;
  292. p.free
  293. end;
  294. end.