aopt.pas 14 KB

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