aopt.pas 13 KB

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