aopt.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. globtype, globals,
  47. verbose,
  48. cgbase,
  49. aoptda,aoptcpu,aoptcpud;
  50. Constructor TAsmOptimizer.create(_AsmL: TAsmList);
  51. Begin
  52. inherited create(_asml,nil,nil,nil);
  53. {setup labeltable, always necessary}
  54. New(LabelInfo);
  55. End;
  56. procedure TAsmOptimizer.FindLoHiLabels;
  57. { Walks through the paasmlist to find the lowest and highest label number. }
  58. { Returns the last Pai object of the current block }
  59. Var LabelFound: Boolean;
  60. p: tai;
  61. Begin
  62. LabelInfo^.LowLabel := High(longint);
  63. LabelInfo^.HighLabel := 0;
  64. LabelInfo^.LabelDif := 0;
  65. LabelInfo^.LabelTable:=nil;
  66. LabelFound := False;
  67. P := BlockStart;
  68. With LabelInfo^ Do
  69. Begin
  70. While Assigned(P) And
  71. ((P.typ <> Ait_Marker) Or
  72. (tai_Marker(P).Kind <> mark_AsmBlockStart)) Do
  73. Begin
  74. If (p.typ = ait_label) and
  75. (tai_Label(p).labsym.labeltype=alt_jump) and
  76. (tai_Label(p).labsym.is_used) Then
  77. Begin
  78. LabelFound := True;
  79. If (tai_Label(p).labsym.labelnr < LowLabel) Then
  80. LowLabel := tai_Label(p).labsym.labelnr;
  81. If (tai_Label(p).labsym.labelnr > HighLabel) Then
  82. HighLabel := tai_Label(p).labsym.labelnr
  83. End;
  84. GetNextInstruction(p, p)
  85. End;
  86. blockend:=p;
  87. If LabelFound
  88. Then LabelDif := HighLabel-LowLabel+1
  89. Else LabelDif := 0
  90. End
  91. End;
  92. Procedure TAsmOptimizer.BuildLabelTableAndFixRegAlloc;
  93. { Builds a table with the locations of the labels in the TAsmList. }
  94. { Also fixes some RegDeallocs like "# %eax released; push (%eax)" }
  95. Var p,hp1, hp2: tai;
  96. Regs: TAllUsedRegs;
  97. LabelIdx : longint;
  98. Begin
  99. CreateUsedRegs(Regs);
  100. With LabelInfo^ Do
  101. If (LabelDif <> 0) Then
  102. Begin
  103. GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
  104. FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
  105. p := BlockStart;
  106. While (P <> BlockEnd) Do
  107. Begin
  108. Case p.typ Of
  109. ait_Label:
  110. begin
  111. If tai_label(p).labsym.is_used and
  112. (tai_Label(p).labsym.labeltype=alt_jump) then
  113. begin
  114. LabelIdx:=tai_label(p).labsym.labelnr-LowLabel;
  115. if LabelIdx>int64(LabelDif) then
  116. internalerror(200604202);
  117. LabelTable^[LabelIdx].PaiObj := p;
  118. end;
  119. end;
  120. ait_regAlloc:
  121. begin
  122. if tai_regalloc(p).ratype=ra_alloc then
  123. Begin
  124. If Not(RegInUsedRegs(tai_regalloc(p).Reg,Regs)) Then
  125. IncludeRegInUsedRegs(tai_regalloc(p).Reg,Regs)
  126. Else
  127. Begin
  128. hp1 := tai(p.previous);
  129. AsmL.remove(p);
  130. p.free;
  131. p := hp1;
  132. { not sure if this is useful, it even skips previous deallocs of the register (FK)
  133. hp1 := p;
  134. hp2 := nil;
  135. While GetLastInstruction(hp1, hp1) And
  136. Not(RegInInstruction(tai_regalloc(p).Reg, hp1)) Do
  137. hp2:=hp1;
  138. If hp2<>nil Then
  139. Begin
  140. hp1:=tai_regalloc.DeAlloc(tai_regalloc(p).Reg,hp2);
  141. InsertLLItem(tai(hp2.previous), hp2, hp1);
  142. End;
  143. }
  144. End;
  145. End
  146. else
  147. Begin
  148. ExcludeRegFromUsedRegs(tai_regalloc(p).Reg,Regs);
  149. hp1 := p;
  150. hp2 := nil;
  151. While Not(FindRegAlloc(tai_regalloc(p).Reg, tai(hp1.Next))) And
  152. GetNextInstruction(hp1, hp1) And
  153. RegInInstruction(tai_regalloc(p).Reg, hp1) Do
  154. hp2 := hp1;
  155. If hp2 <> nil Then
  156. Begin
  157. hp1 := tai(p.previous);
  158. AsmL.Remove(p);
  159. InsertLLItem(hp2, tai(hp2.Next), p);
  160. p := hp1;
  161. End
  162. else if findregalloc(tai_regalloc(p).reg, tai(p.next))
  163. and getnextinstruction(p,hp1) then
  164. begin
  165. hp1 := tai(p.previous);
  166. AsmL.remove(p);
  167. p.free;
  168. p := hp1;
  169. // don't include here, since then the allocation will be removed when it's processed
  170. // include(usedregs,supreg);
  171. end;
  172. End
  173. End
  174. End;
  175. P := tai(p.Next);
  176. While Assigned(p) and
  177. (p <> blockend) and
  178. (p.typ in (SkipInstr - [ait_regalloc])) Do
  179. P := tai(P.Next)
  180. End;
  181. End;
  182. ReleaseUsedRegs(Regs);
  183. End;
  184. procedure tasmoptimizer.clear;
  185. begin
  186. if assigned(LabelInfo^.labeltable) then
  187. begin
  188. freemem(LabelInfo^.labeltable);
  189. LabelInfo^.labeltable := nil;
  190. end;
  191. LabelInfo^.labeldif:=0;
  192. LabelInfo^.lowlabel:=high(longint);
  193. LabelInfo^.highlabel:=0;
  194. end;
  195. procedure tasmoptimizer.pass_1;
  196. begin
  197. findlohilabels;
  198. BuildLabelTableAndFixRegAlloc;
  199. end;
  200. Procedure TAsmOptimizer.Optimize;
  201. Var
  202. HP: tai;
  203. pass: longint;
  204. Begin
  205. pass:=0;
  206. BlockStart := tai(AsmL.First);
  207. pass_1;
  208. While Assigned(BlockStart) Do
  209. Begin
  210. if pass = 0 then
  211. PrePeepHoleOpts;
  212. { Peephole optimizations }
  213. PeepHoleOptPass1;
  214. { Only perform them twice in the first pass }
  215. if pass = 0 then
  216. PeepHoleOptPass1;
  217. If (cs_opt_asmcse in current_settings.optimizerswitches) Then
  218. Begin
  219. // DFA:=TAOptDFACpu.Create(AsmL,BlockStart,BlockEnd,LabelInfo);
  220. { data flow analyzer }
  221. // DFA.DoDFA;
  222. { common subexpression elimination }
  223. { CSE;}
  224. End;
  225. { more peephole optimizations }
  226. PeepHoleOptPass2;
  227. { if pass = last_pass then }
  228. PostPeepHoleOpts;
  229. { free memory }
  230. clear;
  231. { continue where we left off, BlockEnd is either the start of an }
  232. { assembler block or nil}
  233. BlockStart := BlockEnd;
  234. While Assigned(BlockStart) And
  235. (BlockStart.typ = ait_Marker) And
  236. (tai_Marker(BlockStart).Kind = mark_AsmBlockStart) Do
  237. Begin
  238. { we stopped at an assembler block, so skip it }
  239. While GetNextInstruction(BlockStart, BlockStart) And
  240. ((BlockStart.Typ <> Ait_Marker) Or
  241. (tai_Marker(Blockstart).Kind <> mark_AsmBlockEnd)) Do;
  242. { blockstart now contains a tai_marker(mark_AsmBlockEnd) }
  243. If GetNextInstruction(BlockStart, HP) And
  244. ((HP.typ <> ait_Marker) Or
  245. (Tai_Marker(HP).Kind <> mark_AsmBlockStart)) Then
  246. { There is no assembler block anymore after the current one, so }
  247. { optimize the next block of "normal" instructions }
  248. pass_1
  249. { Otherwise, skip the next assembler block }
  250. else
  251. blockStart := hp;
  252. End
  253. End;
  254. End;
  255. Destructor TAsmOptimizer.Destroy;
  256. Begin
  257. Dispose(LabelInfo)
  258. End;
  259. procedure Optimize(AsmL:TAsmList);
  260. var
  261. p : TAsmOptimizer;
  262. begin
  263. p:=casmoptimizer.Create(AsmL);
  264. p.Optimize;
  265. p.free
  266. end;
  267. procedure PreRegallocSchedule(AsmL:TAsmList);
  268. var
  269. p : TAsmOptimizer;
  270. begin
  271. p:=cpreregallocscheduler.Create(AsmL);
  272. p.Optimize;
  273. p.free
  274. end;
  275. end.