aopt.pas 14 KB

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