2
0

aopt.pas 15 KB

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