2
0

aopt.pas 14 KB

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