aoptobj.pas 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525
  1. {
  2. Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit contains the processor independent assembler optimizer
  5. object, base for the dataflow analyzer, peepholeoptimizer and
  6. common subexpression elimination objects.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************
  19. }
  20. Unit AoptObj;
  21. {$i fpcdefs.inc}
  22. { general, processor independent objects for use by the assembler optimizer }
  23. Interface
  24. uses
  25. globtype,
  26. aasmbase,aasmcpu,aasmtai,aasmdata,
  27. cclasses,
  28. cgbase,cgutils,
  29. cpubase,
  30. aoptbase,aoptcpub,aoptda;
  31. { ************************************************************************* }
  32. { ********************************* Constants ***************************** }
  33. { ************************************************************************* }
  34. Const
  35. {Possible register content types}
  36. con_Unknown = 0;
  37. con_ref = 1;
  38. con_const = 2;
  39. {***************** Types ****************}
  40. Type
  41. { ************************************************************************* }
  42. { ************************* Some general type definitions ***************** }
  43. { ************************************************************************* }
  44. TRefCompare = Function(const r1, r2: TReference): Boolean;
  45. //!!! FIXME
  46. TRegArray = Array[byte] of tsuperregister;
  47. TRegSet = tcpuregisterset;
  48. { possible actions on an operand: read, write or modify (= read & write) }
  49. TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
  50. { ************************************************************************* }
  51. { * Object to hold information on which regiters are in use and which not * }
  52. { ************************************************************************* }
  53. { TUsedRegs }
  54. TUsedRegs = class
  55. Constructor create(aTyp : TRegisterType);
  56. Constructor create_regset(aTyp : TRegisterType;Const _RegSet: TRegSet);
  57. Destructor Destroy;override;
  58. Procedure Clear;
  59. { update the info with the pairegalloc objects coming after
  60. p }
  61. procedure Update(p: Tai; IgnoreNewAllocs: Boolean=false);
  62. { is Reg currently in use }
  63. Function IsUsed(Reg: TRegister): Boolean;
  64. { get all the currently used registers }
  65. Function GetUsedRegs: TRegSet;
  66. Private
  67. Typ : TRegisterType;
  68. UsedRegs: TRegSet;
  69. End;
  70. { ************************************************************************* }
  71. { ******************* Contents of the integer registers ******************* }
  72. { ************************************************************************* }
  73. { size of the integer that holds the state number of a register. Can be any }
  74. { integer type, so it can be changed to reduce the size of the TContent }
  75. { structure or to improve alignment }
  76. TStateInt = Byte;
  77. TContent = Record
  78. { start and end of block instructions that defines the }
  79. { content of this register. If Typ = con_const, then }
  80. { Longint(StartMod) = value of the constant) }
  81. StartMod: Tai;
  82. { starts at 0, gets increased everytime the register is }
  83. { written to }
  84. WState: TStateInt;
  85. { starts at 0, gets increased everytime the register is read }
  86. { from }
  87. RState: TStateInt;
  88. { how many instructions starting with StarMod does the block }
  89. { consist of }
  90. NrOfMods: Byte;
  91. { the type of the content of the register: unknown, memory }
  92. { (variable) or constant }
  93. Typ: Byte;
  94. End;
  95. //!!! FIXME
  96. TRegContent = Array[byte] Of TContent;
  97. { ************************************************************************** }
  98. { information object with the contents of every register. Every Tai object }
  99. { gets one of these assigned: a pointer to it is stored in the OptInfo field }
  100. { ************************************************************************** }
  101. { TPaiProp }
  102. TPaiProp = class(TAoptBaseCpu)
  103. Regs: TRegContent;
  104. { can this instruction be removed? }
  105. CanBeRemoved: Boolean;
  106. Constructor create; reintroduce;
  107. { checks the whole sequence of which (so regs[which].StartMod and and }
  108. { the next NrOfMods Tai objects) to see whether Reg is used somewhere, }
  109. { without it being loaded with something else first }
  110. Function RegInSequence(Reg, which: TRegister): Boolean;
  111. { destroy the contents of a register, as well as those whose contents }
  112. { are based on those of that register }
  113. Procedure DestroyReg(Reg: TRegister; var InstrSinceLastMod:
  114. TInstrSinceLastMod);
  115. { if the contents of WhichReg (can be R_NO in case of a constant) are }
  116. { written to memory at the location Ref, the contents of the registers }
  117. { that depend on Ref have to be destroyed }
  118. Procedure DestroyRefs(Const Ref: TReference; WhichReg: TRegister; var
  119. InstrSinceLastMod: TInstrSinceLastMod);
  120. { an instruction reads from operand o }
  121. Procedure ReadOp(const o:toper);
  122. { an instruction reads from reference Ref }
  123. Procedure ReadRef(Ref: PReference);
  124. { an instruction reads from register Reg }
  125. Procedure ReadReg(Reg: TRegister);
  126. { an instruction writes/modifies operand o and this has special }
  127. { side-effects or modifies the contents in such a way that we can't }
  128. { simply add this instruction to the sequence of instructions that }
  129. { describe the contents of the operand, so destroy it }
  130. Procedure DestroyOp(const o:Toper; var InstrSinceLastMod:
  131. TInstrSinceLastMod);
  132. { destroy the contents of all registers }
  133. Procedure DestroyAllRegs(var InstrSinceLastMod: TInstrSinceLastMod);
  134. { a register's contents are modified, but not destroyed (the new value
  135. depends on the old one) }
  136. Procedure ModifyReg(reg: TRegister; var InstrSinceLastMod:
  137. TInstrSinceLastMod);
  138. { an operand's contents are modified, but not destroyed (the new value
  139. depends on the old one) }
  140. Procedure ModifyOp(const oper: TOper; var InstrSinceLastMod:
  141. TInstrSinceLastMod);
  142. { increase the write state of a register (call every time a register is
  143. written to) }
  144. Procedure IncWState(Reg: TRegister);
  145. { increase the read state of a register (call every time a register is }
  146. { read from) }
  147. Procedure IncRState(Reg: TRegister);
  148. { get the write state of a register }
  149. Function GetWState(Reg: TRegister): TStateInt;
  150. { get the read state of a register }
  151. Function GetRState(Reg: TRegister): TStateInt;
  152. { get the type of contents of a register }
  153. Function GetRegContentType(Reg: TRegister): Byte;
  154. Destructor Done;
  155. Private
  156. Procedure IncState(var s: TStateInt);
  157. { returns whether the reference Ref is used somewhere in the loading }
  158. { sequence Content }
  159. Function RefInSequence(Const Ref: TReference; Content: TContent;
  160. RefsEq: TRefCompare): Boolean;
  161. { returns whether the instruction P reads from and/or writes }
  162. { to Reg }
  163. Function RefInInstruction(Const Ref: TReference; p: Tai;
  164. RefsEq: TRefCompare): Boolean;
  165. { returns whether two references with at least one pointing to an array }
  166. { may point to the same memory location }
  167. End;
  168. { ************************************************************************* }
  169. { ************************ Label information ****************************** }
  170. { ************************************************************************* }
  171. TLabelTableItem = Record
  172. PaiObj: Tai;
  173. End;
  174. TLabelTable = Array[0..2500000] Of TLabelTableItem;
  175. PLabelTable = ^TLabelTable;
  176. PLabelInfo = ^TLabelInfo;
  177. TLabelInfo = Record
  178. { the highest and lowest label number occurring in the current code }
  179. { fragment }
  180. LowLabel, HighLabel: longint;
  181. LabelDif: cardinal;
  182. { table that contains the addresses of the Pai_Label objects associated
  183. with each label number }
  184. LabelTable: PLabelTable;
  185. End;
  186. { ************************************************************************* }
  187. { ********** General optimizer object, used to derive others from ********* }
  188. { ************************************************************************* }
  189. TAllUsedRegs = array[TRegisterType] of TUsedRegs;
  190. { TAOptObj }
  191. TAOptObj = class(TAoptBaseCpu)
  192. { the PAasmOutput list this optimizer instance works on }
  193. AsmL: TAsmList;
  194. { The labelinfo record contains the addresses of the Tai objects }
  195. { that are labels, how many labels there are and the min and max }
  196. { label numbers }
  197. LabelInfo: PLabelInfo;
  198. { Start and end of the block that is currently being optimized }
  199. BlockStart, BlockEnd: Tai;
  200. DFA: TAOptDFA;
  201. UsedRegs: TAllUsedRegs;
  202. { _AsmL is the PAasmOutpout list that has to be optimized, }
  203. { _BlockStart and _BlockEnd the start and the end of the block }
  204. { that has to be optimized and _LabelInfo a pointer to a }
  205. { TLabelInfo record }
  206. Constructor create(_AsmL: TAsmList; _BlockStart, _BlockEnd: Tai;
  207. _LabelInfo: PLabelInfo); virtual; reintroduce;
  208. Destructor Destroy;override;
  209. { processor independent methods }
  210. Procedure CreateUsedRegs(var regs: TAllUsedRegs);
  211. Procedure ClearUsedRegs;
  212. Procedure UpdateUsedRegs(p : Tai);
  213. procedure UpdateUsedRegs(var Regs: TAllUsedRegs; p: Tai);
  214. Function CopyUsedRegs(var dest : TAllUsedRegs) : boolean;
  215. Procedure ReleaseUsedRegs(const regs : TAllUsedRegs);
  216. Function RegInUsedRegs(reg : TRegister;regs : TAllUsedRegs) : boolean;
  217. Procedure IncludeRegInUsedRegs(reg : TRegister;var regs : TAllUsedRegs);
  218. Procedure ExcludeRegFromUsedRegs(reg: TRegister;var regs : TAllUsedRegs);
  219. Function GetAllocationString(const regs : TAllUsedRegs) : string;
  220. { returns true if the label L is found between hp and the next }
  221. { instruction }
  222. Function FindLabel(L: TasmLabel; Var hp: Tai): Boolean;
  223. { inserts new_one between prev and foll in AsmL }
  224. Procedure InsertLLItem(prev, foll, new_one: TLinkedListItem);
  225. { If P is a Tai object releveant to the optimizer, P is returned
  226. If it is not relevant tot he optimizer, the first object after P
  227. that is relevant is returned }
  228. Function SkipHead(P: Tai): Tai;
  229. { returns true if the operands o1 and o2 are completely equal }
  230. Function OpsEqual(const o1,o2:toper): Boolean;
  231. { Returns the next ait_alloc object with ratype ra_alloc for
  232. Reg is found in the block
  233. of Tai's starting with StartPai and ending with the next "real"
  234. instruction. If none is found, it returns
  235. nil
  236. }
  237. Function FindRegAlloc(Reg: TRegister; StartPai: Tai): tai_regalloc;
  238. { Returns the last ait_alloc object with ratype ra_alloc for
  239. Reg is found in the block
  240. of Tai's starting with StartPai and ending with the next "real"
  241. instruction. If none is found, it returns
  242. nil
  243. }
  244. Function FindRegAllocBackward(Reg : TRegister; StartPai : Tai) : tai_regalloc;
  245. { Returns the next ait_alloc object with ratype ra_dealloc
  246. for Reg which is found in the block of Tai's starting with StartPai
  247. and ending with the next "real" instruction. If none is found, it returns
  248. nil }
  249. Function FindRegDeAlloc(Reg: TRegister; StartPai: Tai): tai_regalloc;
  250. { reg used after p? }
  251. function RegUsedAfterInstruction(reg: Tregister; p: tai; var AllUsedRegs: TAllUsedRegs): Boolean;
  252. { traces sucessive jumps to their final destination and sets it, e.g.
  253. je l1 je l3
  254. <code> <code>
  255. l1: becomes l1:
  256. je l2 je l3
  257. <code> <code>
  258. l2: l2:
  259. jmp l3 jmp l3
  260. the level parameter denotes how deeep we have already followed the jump,
  261. to avoid endless loops with constructs such as "l5: ; jmp l5" }
  262. function GetFinalDestination(hp: taicpu; level: longint): boolean;
  263. function getlabelwithsym(sym: tasmlabel): tai;
  264. { Removes an instruction following hp1 (possibly with reg.deallocations in between),
  265. if its opcode is A_NOP. }
  266. procedure RemoveDelaySlot(hp1: tai);
  267. { peephole optimizer }
  268. procedure PrePeepHoleOpts;
  269. procedure PeepHoleOptPass1;
  270. procedure PeepHoleOptPass2; virtual;
  271. procedure PostPeepHoleOpts;
  272. { processor dependent methods }
  273. // if it returns true, perform a "continue"
  274. function PeepHoleOptPass1Cpu(var p: tai): boolean; virtual;
  275. function PostPeepHoleOptsCpu(var p: tai): boolean; virtual;
  276. End;
  277. Function ArrayRefsEq(const r1, r2: TReference): Boolean;
  278. { ***************************** Implementation **************************** }
  279. Implementation
  280. uses
  281. cutils,
  282. globals,
  283. verbose,
  284. procinfo;
  285. function JumpTargetOp(ai: taicpu): poper; inline;
  286. begin
  287. {$if defined(MIPS)}
  288. { MIPS branches can have 1,2 or 3 operands, target label is the last one. }
  289. result:=ai.oper[ai.ops-1];
  290. {$else MIPS}
  291. result:=ai.oper[0];
  292. {$endif MIPS}
  293. end;
  294. { ************************************************************************* }
  295. { ******************************** TUsedRegs ****************************** }
  296. { ************************************************************************* }
  297. Constructor TUsedRegs.create(aTyp : TRegisterType);
  298. Begin
  299. Typ:=aTyp;
  300. UsedRegs := [];
  301. End;
  302. Constructor TUsedRegs.create_regset(aTyp : TRegisterType;Const _RegSet: TRegSet);
  303. Begin
  304. Typ:=aTyp;
  305. UsedRegs := _RegSet;
  306. End;
  307. {
  308. updates UsedRegs with the RegAlloc Information coming after P
  309. }
  310. Procedure TUsedRegs.Update(p: Tai;IgnoreNewAllocs : Boolean = false);
  311. Begin
  312. { this code is normally not used because updating the register allocation information is done in
  313. TAOptObj.UpdateUsedRegs for speed reasons }
  314. repeat
  315. while assigned(p) and
  316. ((p.typ in (SkipInstr - [ait_RegAlloc])) or
  317. ((p.typ = ait_label) and
  318. labelCanBeSkipped(tai_label(p))) or
  319. ((p.typ = ait_marker) and
  320. (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_NoLineInfoStart,mark_NoLineInfoEnd]))) do
  321. p := tai(p.next);
  322. while assigned(p) and
  323. (p.typ=ait_RegAlloc) Do
  324. begin
  325. if (getregtype(tai_regalloc(p).reg) = typ) then
  326. begin
  327. case tai_regalloc(p).ratype of
  328. ra_alloc :
  329. if not(IgnoreNewAllocs) then
  330. Include(UsedRegs, getsupreg(tai_regalloc(p).reg));
  331. ra_dealloc :
  332. Exclude(UsedRegs, getsupreg(tai_regalloc(p).reg));
  333. end;
  334. end;
  335. p := tai(p.next);
  336. end;
  337. until not(assigned(p)) or
  338. (not(p.typ in SkipInstr) and
  339. not((p.typ = ait_label) and
  340. labelCanBeSkipped(tai_label(p))));
  341. End;
  342. Function TUsedRegs.IsUsed(Reg: TRegister): Boolean;
  343. Begin
  344. IsUsed := (getregtype(Reg)=Typ) and (getsupreg(Reg) in UsedRegs);
  345. End;
  346. Function TUsedRegs.GetUsedRegs: TRegSet;
  347. Begin
  348. GetUsedRegs := UsedRegs;
  349. End;
  350. Destructor TUsedRegs.Destroy;
  351. Begin
  352. inherited destroy;
  353. end;
  354. procedure TUsedRegs.Clear;
  355. begin
  356. UsedRegs := [];
  357. end;
  358. { ************************************************************************* }
  359. { **************************** TPaiProp *********************************** }
  360. { ************************************************************************* }
  361. Constructor TPaiProp.Create;
  362. Begin
  363. {!!!!!!
  364. UsedRegs.Init;
  365. CondRegs.init;
  366. }
  367. { DirFlag: TFlagContents; I386 specific}
  368. End;
  369. Function TPaiProp.RegInSequence(Reg, which: TRegister): Boolean;
  370. {
  371. Var p: Tai;
  372. RegsChecked: TRegSet;
  373. content: TContent;
  374. Counter: Byte;
  375. TmpResult: Boolean;
  376. }
  377. begin
  378. Result:=False; { unimplemented }
  379. (*!!!!!!!!!!1
  380. RegsChecked := [];
  381. content := regs[which];
  382. p := content.StartMod;
  383. TmpResult := False;
  384. Counter := 1;
  385. While Not(TmpResult) And
  386. (Counter <= Content.NrOfMods) Do
  387. Begin
  388. If IsLoadMemReg(p) Then
  389. With PInstr(p)^.oper[LoadSrc]^.ref^ Do
  390. If (Base = ProcInfo.FramePointer)
  391. {$ifdef cpurefshaveindexreg}
  392. And (Index = R_NO)
  393. {$endif cpurefshaveindexreg} Then
  394. Begin
  395. RegsChecked := RegsChecked +
  396. [RegMaxSize(PInstr(p)^.oper[LoadDst]^.reg)];
  397. If Reg = RegMaxSize(PInstr(p)^.oper[LoadDst]^.reg) Then
  398. Break;
  399. End
  400. Else
  401. Begin
  402. If (Base = Reg) And
  403. Not(Base In RegsChecked)
  404. Then TmpResult := True;
  405. {$ifdef cpurefshaveindexreg}
  406. If Not(TmpResult) And
  407. (Index = Reg) And
  408. Not(Index In RegsChecked)
  409. Then TmpResult := True;
  410. {$Endif cpurefshaveindexreg}
  411. End
  412. Else TmpResult := RegInInstruction(Reg, p);
  413. Inc(Counter);
  414. GetNextInstruction(p,p)
  415. End;
  416. RegInSequence := TmpResult
  417. *)
  418. End;
  419. Procedure TPaiProp.DestroyReg(Reg: TRegister; var InstrSinceLastMod:
  420. TInstrSinceLastMod);
  421. { Destroys the contents of the register Reg in the PPaiProp p1, as well as }
  422. { the contents of registers are loaded with a memory location based on Reg }
  423. {
  424. Var TmpWState, TmpRState: Byte;
  425. Counter: TRegister;
  426. }
  427. Begin
  428. {!!!!!!!
  429. Reg := RegMaxSize(Reg);
  430. If (Reg in [LoGPReg..HiGPReg]) Then
  431. For Counter := LoGPReg to HiGPReg Do
  432. With Regs[Counter] Do
  433. If (Counter = reg) Or
  434. ((Typ = Con_Ref) And
  435. RegInSequence(Reg, Counter)) Then
  436. Begin
  437. InstrSinceLastMod[Counter] := 0;
  438. IncWState(Counter);
  439. TmpWState := GetWState(Counter);
  440. TmpRState := GetRState(Counter);
  441. FillChar(Regs[Counter], SizeOf(TContent), 0);
  442. WState := TmpWState;
  443. RState := TmpRState
  444. End
  445. }
  446. End;
  447. Function ArrayRefsEq(const r1, r2: TReference): Boolean;
  448. Begin
  449. Result:=False; { unimplemented }
  450. (*!!!!!!!!!!
  451. ArrayRefsEq := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup) And
  452. {$ifdef refsHaveSegmentReg}
  453. (R1.Segment = R2.Segment) And
  454. {$endif}
  455. (R1.Base = R2.Base) And
  456. (R1.Symbol=R2.Symbol);
  457. *)
  458. End;
  459. Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister;
  460. var InstrSinceLastMod: TInstrSinceLastMod);
  461. { destroys all registers which possibly contain a reference to Ref, WhichReg }
  462. { is the register whose contents are being written to memory (if this proc }
  463. { is called because of a "mov?? %reg, (mem)" instruction) }
  464. {
  465. Var RefsEq: TRefCompare;
  466. Counter: TRegister;
  467. }
  468. Begin
  469. (*!!!!!!!!!!!
  470. WhichReg := RegMaxSize(WhichReg);
  471. If (Ref.base = procinfo.FramePointer) or
  472. Assigned(Ref.Symbol) Then
  473. Begin
  474. If
  475. {$ifdef cpurefshaveindexreg}
  476. (Ref.Index = R_NO) And
  477. {$endif cpurefshaveindexreg}
  478. (Not(Assigned(Ref.Symbol)) or
  479. (Ref.base = R_NO)) Then
  480. { local variable which is not an array }
  481. RefsEq := @RefsEqual
  482. Else
  483. { local variable which is an array }
  484. RefsEq := @ArrayRefsEq;
  485. {write something to a parameter, a local or global variable, so
  486. * with uncertain optimizations on:
  487. - destroy the contents of registers whose contents have somewhere a
  488. "mov?? (Ref), %reg". WhichReg (this is the register whose contents
  489. are being written to memory) is not destroyed if it's StartMod is
  490. of that form and NrOfMods = 1 (so if it holds ref, but is not a
  491. pointer or value based on Ref)
  492. * with uncertain optimizations off:
  493. - also destroy registers that contain any pointer}
  494. For Counter := LoGPReg to HiGPReg Do
  495. With Regs[Counter] Do
  496. Begin
  497. If (typ = Con_Ref) And
  498. ((Not(cs_opt_size in current_settings.optimizerswitches) And
  499. (NrOfMods <> 1)
  500. ) Or
  501. (RefInSequence(Ref,Regs[Counter], RefsEq) And
  502. ((Counter <> WhichReg) Or
  503. ((NrOfMods <> 1) And
  504. {StarMod is always of the type ait_instruction}
  505. (PInstr(StartMod)^.oper[0].typ = top_ref) And
  506. RefsEq(PInstr(StartMod)^.oper[0].ref^, Ref)
  507. )
  508. )
  509. )
  510. )
  511. Then
  512. DestroyReg(Counter, InstrSinceLastMod)
  513. End
  514. End
  515. Else
  516. {write something to a pointer location, so
  517. * with uncertain optimzations on:
  518. - do not destroy registers which contain a local/global variable or a
  519. parameter, except if DestroyRefs is called because of a "movsl"
  520. * with uncertain optimzations off:
  521. - destroy every register which contains a memory location
  522. }
  523. For Counter := LoGPReg to HiGPReg Do
  524. With Regs[Counter] Do
  525. If (typ = Con_Ref) And
  526. (Not(cs_opt_size in current_settings.optimizerswitches) Or
  527. {$ifdef x86}
  528. {for movsl}
  529. (Ref.Base = R_EDI) Or
  530. {$endif}
  531. {don't destroy if reg contains a parameter, local or global variable}
  532. Not((NrOfMods = 1) And
  533. (PInstr(StartMod)^.oper[0].typ = top_ref) And
  534. ((PInstr(StartMod)^.oper[0].ref^.base = ProcInfo.FramePointer) Or
  535. Assigned(PInstr(StartMod)^.oper[0].ref^.Symbol)
  536. )
  537. )
  538. )
  539. Then DestroyReg(Counter, InstrSinceLastMod)
  540. *)
  541. End;
  542. Procedure TPaiProp.DestroyAllRegs(var InstrSinceLastMod: TInstrSinceLastMod);
  543. {Var Counter: TRegister;}
  544. Begin {initializes/desrtoys all registers}
  545. (*!!!!!!!!!
  546. For Counter := LoGPReg To HiGPReg Do
  547. Begin
  548. ReadReg(Counter);
  549. DestroyReg(Counter, InstrSinceLastMod);
  550. End;
  551. CondRegs.Init;
  552. { FPURegs.Init; }
  553. *)
  554. End;
  555. Procedure TPaiProp.DestroyOp(const o:Toper; var InstrSinceLastMod:
  556. TInstrSinceLastMod);
  557. Begin
  558. {!!!!!!!
  559. Case o.typ Of
  560. top_reg: DestroyReg(o.reg, InstrSinceLastMod);
  561. top_ref:
  562. Begin
  563. ReadRef(o.ref);
  564. DestroyRefs(o.ref^, R_NO, InstrSinceLastMod);
  565. End;
  566. top_symbol:;
  567. End;
  568. }
  569. End;
  570. Procedure TPaiProp.ReadReg(Reg: TRegister);
  571. Begin
  572. {!!!!!!!
  573. Reg := RegMaxSize(Reg);
  574. If Reg in General_Registers Then
  575. IncRState(RegMaxSize(Reg))
  576. }
  577. End;
  578. Procedure TPaiProp.ReadRef(Ref: PReference);
  579. Begin
  580. (*!!!!!!
  581. If Ref^.Base <> R_NO Then
  582. ReadReg(Ref^.Base);
  583. {$ifdef cpurefshaveindexreg}
  584. If Ref^.Index <> R_NO Then
  585. ReadReg(Ref^.Index);
  586. {$endif cpurefshaveindexreg}
  587. *)
  588. End;
  589. Procedure TPaiProp.ReadOp(const o:toper);
  590. Begin
  591. Case o.typ Of
  592. top_reg: ReadReg(o.reg);
  593. top_ref: ReadRef(o.ref);
  594. else
  595. internalerror(200410241);
  596. End;
  597. End;
  598. Procedure TPaiProp.ModifyReg(reg: TRegister; Var InstrSinceLastMod:
  599. TInstrSinceLastMod);
  600. Begin
  601. (*!!!!!!!
  602. With Regs[reg] Do
  603. If (Typ = Con_Ref)
  604. Then
  605. Begin
  606. IncState(WState);
  607. {also store how many instructions are part of the sequence in the first
  608. instructions PPaiProp, so it can be easily accessed from within
  609. CheckSequence}
  610. Inc(NrOfMods, InstrSinceLastMod[Reg]);
  611. PPaiProp(StartMod.OptInfo)^.Regs[Reg].NrOfMods := NrOfMods;
  612. InstrSinceLastMod[Reg] := 0;
  613. End
  614. Else
  615. DestroyReg(Reg, InstrSinceLastMod);
  616. *)
  617. End;
  618. Procedure TPaiProp.ModifyOp(const oper: TOper; var InstrSinceLastMod:
  619. TInstrSinceLastMod);
  620. Begin
  621. If oper.typ = top_reg Then
  622. ModifyReg(RegMaxSize(oper.reg),InstrSinceLastMod)
  623. Else
  624. Begin
  625. ReadOp(oper);
  626. DestroyOp(oper, InstrSinceLastMod);
  627. End
  628. End;
  629. Procedure TPaiProp.IncWState(Reg: TRegister);{$ifdef inl} inline;{$endif inl}
  630. Begin
  631. //!!!! IncState(Regs[Reg].WState);
  632. End;
  633. Procedure TPaiProp.IncRState(Reg: TRegister);{$ifdef inl} inline;{$endif inl}
  634. Begin
  635. //!!!! IncState(Regs[Reg].RState);
  636. End;
  637. Function TPaiProp.GetWState(Reg: TRegister): TStateInt; {$ifdef inl} inline;{$endif inl}
  638. Begin
  639. Result:=0; { unimplemented }
  640. //!!!! GetWState := Regs[Reg].WState
  641. End;
  642. Function TPaiProp.GetRState(Reg: TRegister): TStateInt; {$ifdef inl} inline;{$endif inl}
  643. Begin
  644. Result:=0; { unimplemented }
  645. //!!!! GetRState := Regs[Reg].RState
  646. End;
  647. Function TPaiProp.GetRegContentType(Reg: TRegister): Byte; {$ifdef inl} inline;{$endif inl}
  648. Begin
  649. Result:=0; { unimplemented }
  650. //!!!! GetRegContentType := Regs[Reg].typ
  651. End;
  652. Destructor TPaiProp.Done;
  653. Begin
  654. //!!!! UsedRegs.Done;
  655. //!!!! CondRegs.Done;
  656. { DirFlag: TFlagContents; I386 specific}
  657. End;
  658. { ************************ private TPaiProp stuff ************************* }
  659. Procedure TPaiProp.IncState(Var s: TStateInt); {$ifdef inl} inline;{$endif inl}
  660. Begin
  661. If s <> High(TStateInt) Then Inc(s)
  662. Else s := 0
  663. End;
  664. Function TPaiProp.RefInInstruction(Const Ref: TReference; p: Tai;
  665. RefsEq: TRefCompare): Boolean;
  666. Var Count: AWord;
  667. TmpResult: Boolean;
  668. Begin
  669. TmpResult := False;
  670. If (p.typ = ait_instruction) Then
  671. Begin
  672. Count := 0;
  673. Repeat
  674. If (TInstr(p).oper[Count]^.typ = Top_Ref) Then
  675. TmpResult := RefsEq(Ref, PInstr(p)^.oper[Count]^.ref^);
  676. Inc(Count);
  677. Until (Count = MaxOps) or TmpResult;
  678. End;
  679. RefInInstruction := TmpResult;
  680. End;
  681. Function TPaiProp.RefInSequence(Const Ref: TReference; Content: TContent;
  682. RefsEq: TRefCompare): Boolean;
  683. Var p: Tai;
  684. Counter: Byte;
  685. TmpResult: Boolean;
  686. Begin
  687. p := Content.StartMod;
  688. TmpResult := False;
  689. Counter := 1;
  690. While Not(TmpResult) And
  691. (Counter <= Content.NrOfMods) Do
  692. Begin
  693. If (p.typ = ait_instruction) And
  694. RefInInstruction(Ref, p, @references_equal)
  695. Then TmpResult := True;
  696. Inc(Counter);
  697. GetNextInstruction(p,p)
  698. End;
  699. RefInSequence := TmpResult
  700. End;
  701. { ************************************************************************* }
  702. { ***************************** TAoptObj ********************************** }
  703. { ************************************************************************* }
  704. Constructor TAoptObj.create(_AsmL: TAsmList; _BlockStart, _BlockEnd: Tai;
  705. _LabelInfo: PLabelInfo);
  706. Begin
  707. AsmL := _AsmL;
  708. BlockStart := _BlockStart;
  709. BlockEnd := _BlockEnd;
  710. LabelInfo := _LabelInfo;
  711. CreateUsedRegs(UsedRegs);
  712. End;
  713. destructor TAOptObj.Destroy;
  714. var
  715. i : TRegisterType;
  716. begin
  717. for i:=low(TRegisterType) to high(TRegisterType) do
  718. UsedRegs[i].Destroy;
  719. inherited Destroy;
  720. end;
  721. procedure TAOptObj.CreateUsedRegs(var regs: TAllUsedRegs);
  722. var
  723. i : TRegisterType;
  724. begin
  725. for i:=low(TRegisterType) to high(TRegisterType) do
  726. Regs[i]:=TUsedRegs.Create(i);
  727. end;
  728. procedure TAOptObj.ClearUsedRegs;
  729. var
  730. i : TRegisterType;
  731. begin
  732. for i:=low(TRegisterType) to high(TRegisterType) do
  733. UsedRegs[i].Clear;
  734. end;
  735. procedure TAOptObj.UpdateUsedRegs(p : Tai);
  736. begin
  737. { this code is based on TUsedRegs.Update to avoid multiple passes through the asmlist,
  738. the code is duplicated here }
  739. repeat
  740. while assigned(p) and
  741. ((p.typ in (SkipInstr - [ait_RegAlloc])) or
  742. ((p.typ = ait_label) and
  743. labelCanBeSkipped(tai_label(p))) or
  744. ((p.typ = ait_marker) and
  745. (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_NoLineInfoStart,mark_NoLineInfoEnd]))) do
  746. p := tai(p.next);
  747. while assigned(p) and
  748. (p.typ=ait_RegAlloc) Do
  749. begin
  750. case tai_regalloc(p).ratype of
  751. ra_alloc :
  752. Include(UsedRegs[getregtype(tai_regalloc(p).reg)].UsedRegs, getsupreg(tai_regalloc(p).reg));
  753. ra_dealloc :
  754. Exclude(UsedRegs[getregtype(tai_regalloc(p).reg)].UsedRegs, getsupreg(tai_regalloc(p).reg));
  755. end;
  756. p := tai(p.next);
  757. end;
  758. until not(assigned(p)) or
  759. (not(p.typ in SkipInstr) and
  760. not((p.typ = ait_label) and
  761. labelCanBeSkipped(tai_label(p))));
  762. end;
  763. procedure TAOptObj.UpdateUsedRegs(var Regs : TAllUsedRegs;p : Tai);
  764. var
  765. i : TRegisterType;
  766. begin
  767. for i:=low(TRegisterType) to high(TRegisterType) do
  768. Regs[i].Update(p);
  769. end;
  770. function TAOptObj.CopyUsedRegs(var dest: TAllUsedRegs): boolean;
  771. var
  772. i : TRegisterType;
  773. begin
  774. Result:=true;
  775. for i:=low(TRegisterType) to high(TRegisterType) do
  776. dest[i]:=TUsedRegs.Create_Regset(i,UsedRegs[i].GetUsedRegs);
  777. end;
  778. procedure TAOptObj.ReleaseUsedRegs(const regs: TAllUsedRegs);
  779. var
  780. i : TRegisterType;
  781. begin
  782. for i:=low(TRegisterType) to high(TRegisterType) do
  783. regs[i].Free;
  784. end;
  785. Function TAOptObj.RegInUsedRegs(reg : TRegister;regs : TAllUsedRegs) : boolean;
  786. begin
  787. result:=regs[getregtype(reg)].IsUsed(reg);
  788. end;
  789. procedure TAOptObj.IncludeRegInUsedRegs(reg: TRegister;
  790. var regs: TAllUsedRegs);
  791. begin
  792. include(regs[getregtype(reg)].UsedRegs,getsupreg(Reg));
  793. end;
  794. procedure TAOptObj.ExcludeRegFromUsedRegs(reg: TRegister;
  795. var regs: TAllUsedRegs);
  796. begin
  797. exclude(regs[getregtype(reg)].UsedRegs,getsupreg(Reg));
  798. end;
  799. function TAOptObj.GetAllocationString(const regs: TAllUsedRegs): string;
  800. var
  801. i : TRegisterType;
  802. j : TSuperRegister;
  803. begin
  804. Result:='';
  805. for i:=low(TRegisterType) to high(TRegisterType) do
  806. for j in regs[i].UsedRegs do
  807. Result:=Result+std_regname(newreg(i,j,R_SUBWHOLE))+' ';
  808. end;
  809. Function TAOptObj.FindLabel(L: TasmLabel; Var hp: Tai): Boolean;
  810. Var TempP: Tai;
  811. Begin
  812. TempP := hp;
  813. While Assigned(TempP) and
  814. (TempP.typ In SkipInstr + [ait_label,ait_align]) Do
  815. If (TempP.typ <> ait_Label) Or
  816. (Tai_label(TempP).labsym <> L)
  817. Then GetNextInstruction(TempP, TempP)
  818. Else
  819. Begin
  820. hp := TempP;
  821. FindLabel := True;
  822. exit
  823. End;
  824. FindLabel := False;
  825. End;
  826. Procedure TAOptObj.InsertLLItem(prev, foll, new_one : TLinkedListItem);
  827. Begin
  828. If Assigned(prev) Then
  829. If Assigned(foll) Then
  830. Begin
  831. If Assigned(new_one) Then
  832. Begin
  833. new_one.previous := prev;
  834. new_one.next := foll;
  835. prev.next := new_one;
  836. foll.previous := new_one;
  837. { should we update line information? }
  838. if (not (tai(new_one).typ in SkipLineInfo)) and
  839. (not (tai(foll).typ in SkipLineInfo)) then
  840. Tailineinfo(new_one).fileinfo := Tailineinfo(foll).fileinfo
  841. End
  842. End
  843. Else AsmL.Concat(new_one)
  844. Else If Assigned(Foll) Then AsmL.Insert(new_one)
  845. End;
  846. Function TAOptObj.SkipHead(P: Tai): Tai;
  847. Var OldP: Tai;
  848. Begin
  849. Repeat
  850. OldP := P;
  851. If (P.typ in SkipInstr) Or
  852. ((P.typ = ait_marker) And
  853. (Tai_Marker(P).Kind = mark_AsmBlockEnd)) Then
  854. GetNextInstruction(P, P)
  855. Else If ((P.Typ = Ait_Marker) And
  856. (Tai_Marker(P).Kind = mark_NoPropInfoStart)) Then
  857. { a marker of the type mark_NoPropInfoStart can't be the first instruction of a }
  858. { paasmoutput list }
  859. GetNextInstruction(Tai(P.Previous),P);
  860. If (P.Typ = Ait_Marker) And
  861. (Tai_Marker(P).Kind = mark_AsmBlockStart) Then
  862. Begin
  863. P := Tai(P.Next);
  864. While (P.typ <> Ait_Marker) Or
  865. (Tai_Marker(P).Kind <> mark_AsmBlockEnd) Do
  866. P := Tai(P.Next)
  867. End;
  868. Until P = OldP;
  869. SkipHead := P;
  870. End;
  871. Function TAOptObj.OpsEqual(const o1,o2:toper): Boolean;
  872. Begin
  873. if o1.typ=o2.typ then
  874. Case o1.typ Of
  875. Top_Reg :
  876. OpsEqual:=o1.reg=o2.reg;
  877. Top_Ref :
  878. OpsEqual := references_equal(o1.ref^, o2.ref^);
  879. Top_Const :
  880. OpsEqual:=o1.val=o2.val;
  881. Top_None :
  882. OpsEqual := True
  883. else OpsEqual := False
  884. End
  885. else
  886. OpsEqual := False;
  887. End;
  888. Function TAOptObj.FindRegAlloc(Reg: TRegister; StartPai: Tai): tai_regalloc;
  889. Begin
  890. Result:=nil;
  891. Repeat
  892. While Assigned(StartPai) And
  893. ((StartPai.typ in (SkipInstr - [ait_regAlloc])) Or
  894. {$if defined(MIPS) or defined(SPARC)}
  895. ((startpai.typ=ait_instruction) and (taicpu(startpai).opcode=A_NOP)) or
  896. {$endif MIPS or SPARC}
  897. ((StartPai.typ = ait_label) and
  898. Not(Tai_Label(StartPai).labsym.Is_Used))) Do
  899. StartPai := Tai(StartPai.Next);
  900. If Assigned(StartPai) And
  901. (StartPai.typ = ait_regAlloc) Then
  902. Begin
  903. if (tai_regalloc(StartPai).ratype=ra_alloc) and
  904. (getregtype(tai_regalloc(StartPai).Reg) = getregtype(Reg)) and
  905. (getsupreg(tai_regalloc(StartPai).Reg) = getsupreg(Reg)) then
  906. begin
  907. Result:=tai_regalloc(StartPai);
  908. exit;
  909. end;
  910. StartPai := Tai(StartPai.Next);
  911. End
  912. else
  913. exit;
  914. Until false;
  915. End;
  916. Function TAOptObj.FindRegAllocBackward(Reg: TRegister; StartPai: Tai): tai_regalloc;
  917. Begin
  918. Result:=nil;
  919. Repeat
  920. While Assigned(StartPai) And
  921. ((StartPai.typ in (SkipInstr - [ait_regAlloc])) Or
  922. ((StartPai.typ = ait_label) and
  923. Not(Tai_Label(StartPai).labsym.Is_Used))) Do
  924. StartPai := Tai(StartPai.Previous);
  925. If Assigned(StartPai) And
  926. (StartPai.typ = ait_regAlloc) Then
  927. Begin
  928. if (tai_regalloc(StartPai).ratype=ra_alloc) and
  929. (getregtype(tai_regalloc(StartPai).Reg) = getregtype(Reg)) and
  930. (getsupreg(tai_regalloc(StartPai).Reg) = getsupreg(Reg)) then
  931. begin
  932. Result:=tai_regalloc(StartPai);
  933. exit;
  934. end;
  935. StartPai := Tai(StartPai.Previous);
  936. End
  937. else
  938. exit;
  939. Until false;
  940. End;
  941. function TAOptObj.FindRegDeAlloc(Reg: TRegister; StartPai: Tai): tai_regalloc;
  942. Begin
  943. Result:=nil;
  944. Repeat
  945. While Assigned(StartPai) And
  946. ((StartPai.typ in (SkipInstr - [ait_regAlloc])) Or
  947. ((StartPai.typ = ait_label) and
  948. Not(Tai_Label(StartPai).labsym.Is_Used))) Do
  949. StartPai := Tai(StartPai.Next);
  950. If Assigned(StartPai) And
  951. (StartPai.typ = ait_regAlloc) Then
  952. Begin
  953. if (tai_regalloc(StartPai).ratype=ra_dealloc) and
  954. (getregtype(tai_regalloc(StartPai).Reg) = getregtype(Reg)) and
  955. (getsupreg(tai_regalloc(StartPai).Reg) = getsupreg(Reg)) then
  956. begin
  957. Result:=tai_regalloc(StartPai);
  958. exit;
  959. end;
  960. StartPai := Tai(StartPai.Next);
  961. End
  962. else
  963. exit;
  964. Until false;
  965. End;
  966. function TAOptObj.RegUsedAfterInstruction(reg: Tregister; p: tai;
  967. var AllUsedRegs: TAllUsedRegs): Boolean;
  968. begin
  969. AllUsedRegs[getregtype(reg)].Update(tai(p.Next),true);
  970. RegUsedAfterInstruction :=
  971. (AllUsedRegs[getregtype(reg)].IsUsed(reg)); { optimization and
  972. (not(getNextInstruction(p,p)) or
  973. not(regLoadedWithNewValue(supreg,false,p))); }
  974. end;
  975. function SkipLabels(hp: tai; var hp2: tai): boolean;
  976. {skips all labels and returns the next "real" instruction}
  977. begin
  978. while assigned(hp.next) and
  979. (tai(hp.next).typ in SkipInstr + [ait_label,ait_align]) Do
  980. hp := tai(hp.next);
  981. if assigned(hp.next) then
  982. begin
  983. SkipLabels := True;
  984. hp2 := tai(hp.next)
  985. end
  986. else
  987. begin
  988. hp2 := hp;
  989. SkipLabels := False
  990. end;
  991. end;
  992. function FindAnyLabel(hp: tai; var l: tasmlabel): Boolean;
  993. begin
  994. FindAnyLabel := false;
  995. while assigned(hp.next) and
  996. (tai(hp.next).typ in (SkipInstr+[ait_align])) Do
  997. hp := tai(hp.next);
  998. if assigned(hp.next) and
  999. (tai(hp.next).typ = ait_label) then
  1000. begin
  1001. FindAnyLabel := true;
  1002. l := tai_label(hp.next).labsym;
  1003. end
  1004. end;
  1005. {$push}
  1006. {$r-}
  1007. function tAOptObj.getlabelwithsym(sym: tasmlabel): tai;
  1008. begin
  1009. if (int64(sym.labelnr) >= int64(labelinfo^.lowlabel)) and
  1010. (int64(sym.labelnr) <= int64(labelinfo^.highlabel)) then { range check, a jump can go past an assembler block! }
  1011. getlabelwithsym := labelinfo^.labeltable^[sym.labelnr-labelinfo^.lowlabel].paiobj
  1012. else
  1013. getlabelwithsym := nil;
  1014. end;
  1015. {$pop}
  1016. { Returns True if hp is an unconditional jump to a label }
  1017. function IsJumpToLabelUncond(hp: taicpu): boolean;
  1018. begin
  1019. {$if defined(avr)}
  1020. result:=(hp.opcode in aopt_uncondjmp) and
  1021. {$else avr}
  1022. result:=(hp.opcode=aopt_uncondjmp) and
  1023. {$endif avr}
  1024. {$if defined(arm) or defined(aarch64)}
  1025. (hp.condition=c_None) and
  1026. {$endif arm or aarch64}
  1027. (hp.ops>0) and
  1028. (JumpTargetOp(hp)^.typ = top_ref) and
  1029. (JumpTargetOp(hp)^.ref^.symbol is TAsmLabel);
  1030. end;
  1031. { Returns True if hp is any jump to a label }
  1032. function IsJumpToLabel(hp: taicpu): boolean;
  1033. begin
  1034. result:=hp.is_jmp and
  1035. (hp.ops>0) and
  1036. (JumpTargetOp(hp)^.typ = top_ref) and
  1037. (JumpTargetOp(hp)^.ref^.symbol is TAsmLabel);
  1038. end;
  1039. procedure TAOptObj.RemoveDelaySlot(hp1:tai);
  1040. var
  1041. hp2: tai;
  1042. begin
  1043. hp2:=tai(hp1.next);
  1044. while assigned(hp2) and (hp2.typ in SkipInstr) do
  1045. hp2:=tai(hp2.next);
  1046. if assigned(hp2) and (hp2.typ=ait_instruction) and
  1047. (taicpu(hp2).opcode=A_NOP) then
  1048. begin
  1049. asml.remove(hp2);
  1050. hp2.free;
  1051. end;
  1052. { Anything except A_NOP must be left in place: these instructions
  1053. execute before branch, so code stays correct if branch is removed. }
  1054. end;
  1055. function TAOptObj.GetFinalDestination(hp: taicpu; level: longint): boolean;
  1056. {traces sucessive jumps to their final destination and sets it, e.g.
  1057. je l1 je l3
  1058. <code> <code>
  1059. l1: becomes l1:
  1060. je l2 je l3
  1061. <code> <code>
  1062. l2: l2:
  1063. jmp l3 jmp l3
  1064. the level parameter denotes how deeep we have already followed the jump,
  1065. to avoid endless loops with constructs such as "l5: ; jmp l5" }
  1066. var p1: tai;
  1067. {$if not defined(MIPS) and not defined(JVM)}
  1068. p2: tai;
  1069. l: tasmlabel;
  1070. {$endif}
  1071. begin
  1072. GetfinalDestination := false;
  1073. if level > 20 then
  1074. exit;
  1075. p1 := getlabelwithsym(tasmlabel(JumpTargetOp(hp)^.ref^.symbol));
  1076. if assigned(p1) then
  1077. begin
  1078. SkipLabels(p1,p1);
  1079. if (tai(p1).typ = ait_instruction) and
  1080. (taicpu(p1).is_jmp) then
  1081. if { the next instruction after the label where the jump hp arrives}
  1082. { is unconditional or of the same type as hp, so continue }
  1083. IsJumpToLabelUncond(taicpu(p1))
  1084. {$if not defined(MIPS) and not defined(JVM)}
  1085. { for MIPS, it isn't enough to check the condition; first operands must be same, too. }
  1086. or
  1087. conditions_equal(taicpu(p1).condition,hp.condition) or
  1088. { the next instruction after the label where the jump hp arrives
  1089. is the opposite of hp (so this one is never taken), but after
  1090. that one there is a branch that will be taken, so perform a
  1091. little hack: set p1 equal to this instruction (that's what the
  1092. last SkipLabels is for, only works with short bool evaluation)}
  1093. (conditions_equal(taicpu(p1).condition,inverse_cond(hp.condition)) and
  1094. SkipLabels(p1,p2) and
  1095. (p2.typ = ait_instruction) and
  1096. (taicpu(p2).is_jmp) and
  1097. (IsJumpToLabelUncond(taicpu(p2)) or
  1098. (conditions_equal(taicpu(p2).condition,hp.condition))) and
  1099. SkipLabels(p1,p1))
  1100. {$endif not MIPS and not JVM}
  1101. then
  1102. begin
  1103. { quick check for loops of the form "l5: ; jmp l5 }
  1104. if (tasmlabel(JumpTargetOp(taicpu(p1))^.ref^.symbol).labelnr =
  1105. tasmlabel(JumpTargetOp(hp)^.ref^.symbol).labelnr) then
  1106. exit;
  1107. if not GetFinalDestination(taicpu(p1),succ(level)) then
  1108. exit;
  1109. {$if defined(aarch64)}
  1110. { can't have conditional branches to
  1111. global labels on AArch64, because the
  1112. offset may become too big }
  1113. if not(taicpu(hp).condition in [C_None,C_AL,C_NV]) and
  1114. (tasmlabel(JumpTargetOp(taicpu(p1))^.ref^.symbol).bind<>AB_LOCAL) then
  1115. exit;
  1116. {$endif aarch64}
  1117. tasmlabel(JumpTargetOp(hp)^.ref^.symbol).decrefs;
  1118. JumpTargetOp(hp)^.ref^.symbol:=JumpTargetOp(taicpu(p1))^.ref^.symbol;
  1119. tasmlabel(JumpTargetOp(hp)^.ref^.symbol).increfs;
  1120. end
  1121. {$if not defined(MIPS) and not defined(JVM)}
  1122. else
  1123. if conditions_equal(taicpu(p1).condition,inverse_cond(hp.condition)) then
  1124. if not FindAnyLabel(p1,l) then
  1125. begin
  1126. {$ifdef finaldestdebug}
  1127. insertllitem(asml,p1,p1.next,tai_comment.Create(
  1128. strpnew('previous label inserted'))));
  1129. {$endif finaldestdebug}
  1130. current_asmdata.getjumplabel(l);
  1131. insertllitem(p1,p1.next,tai_label.Create(l));
  1132. tasmlabel(JumpTargetOp(hp)^.ref^.symbol).decrefs;
  1133. JumpTargetOp(hp)^.ref^.symbol := l;
  1134. l.increfs;
  1135. { this won't work, since the new label isn't in the labeltable }
  1136. { so it will fail the rangecheck. Labeltable should become a }
  1137. { hashtable to support this: }
  1138. { GetFinalDestination(asml, hp); }
  1139. end
  1140. else
  1141. begin
  1142. {$ifdef finaldestdebug}
  1143. insertllitem(asml,p1,p1.next,tai_comment.Create(
  1144. strpnew('next label reused'))));
  1145. {$endif finaldestdebug}
  1146. l.increfs;
  1147. tasmlabel(JumpTargetOp(hp)^.ref^.symbol).decrefs;
  1148. JumpTargetOp(hp)^.ref^.symbol := l;
  1149. if not GetFinalDestination(hp,succ(level)) then
  1150. exit;
  1151. end;
  1152. {$endif not MIPS and not JVM}
  1153. end;
  1154. GetFinalDestination := true;
  1155. end;
  1156. procedure TAOptObj.PrePeepHoleOpts;
  1157. begin
  1158. end;
  1159. procedure TAOptObj.PeepHoleOptPass1;
  1160. var
  1161. p,hp1,hp2 : tai;
  1162. stoploop:boolean;
  1163. begin
  1164. repeat
  1165. stoploop:=true;
  1166. p := BlockStart;
  1167. ClearUsedRegs;
  1168. while (p <> BlockEnd) Do
  1169. begin
  1170. { I'am not sure why this is done, UsedRegs should reflect the register usage before the instruction
  1171. If an instruction needs the information of this, it can easily create a TempUsedRegs (FK)
  1172. UpdateUsedRegs(tai(p.next));
  1173. }
  1174. {$ifdef DEBUG_OPTALLOC}
  1175. if p.Typ=ait_instruction then
  1176. InsertLLItem(tai(p.Previous),p,tai_comment.create(strpnew(GetAllocationString(UsedRegs))));
  1177. {$endif DEBUG_OPTALLOC}
  1178. if PeepHoleOptPass1Cpu(p) then
  1179. begin
  1180. stoploop:=false;
  1181. UpdateUsedRegs(p);
  1182. continue;
  1183. end;
  1184. case p.Typ Of
  1185. ait_instruction:
  1186. begin
  1187. { Handle Jmp Optimizations }
  1188. if taicpu(p).is_jmp then
  1189. begin
  1190. { the following if-block removes all code between a jmp and the next label,
  1191. because it can never be executed
  1192. }
  1193. if IsJumpToLabelUncond(taicpu(p)) then
  1194. begin
  1195. hp2:=p;
  1196. while GetNextInstruction(hp2, hp1) and
  1197. (hp1.typ <> ait_label)
  1198. {$ifdef JVM}
  1199. and (hp1.typ <> ait_jcatch)
  1200. {$endif}
  1201. do
  1202. if not(hp1.typ in ([ait_label,ait_align]+skipinstr)) then
  1203. begin
  1204. if (hp1.typ = ait_instruction) and
  1205. taicpu(hp1).is_jmp and
  1206. (JumpTargetOp(taicpu(hp1))^.typ = top_ref) and
  1207. (JumpTargetOp(taicpu(hp1))^.ref^.symbol is TAsmLabel) then
  1208. TAsmLabel(JumpTargetOp(taicpu(hp1))^.ref^.symbol).decrefs;
  1209. { don't kill start/end of assembler block,
  1210. no-line-info-start/end etc }
  1211. if hp1.typ<>ait_marker then
  1212. begin
  1213. {$if defined(SPARC) or defined(MIPS) }
  1214. if (hp1.typ=ait_instruction) and (taicpu(hp1).is_jmp) then
  1215. RemoveDelaySlot(hp1);
  1216. {$endif SPARC or MIPS }
  1217. asml.remove(hp1);
  1218. hp1.free;
  1219. stoploop:=false;
  1220. end
  1221. else
  1222. hp2:=hp1;
  1223. end
  1224. else break;
  1225. end;
  1226. if GetNextInstruction(p, hp1) then
  1227. begin
  1228. SkipEntryExitMarker(hp1,hp1);
  1229. { remove unconditional jumps to a label coming right after them }
  1230. if IsJumpToLabelUncond(taicpu(p)) and
  1231. FindLabel(tasmlabel(JumpTargetOp(taicpu(p))^.ref^.symbol), hp1) and
  1232. { TODO: FIXME removing the first instruction fails}
  1233. (p<>blockstart) then
  1234. begin
  1235. tasmlabel(JumpTargetOp(taicpu(p))^.ref^.symbol).decrefs;
  1236. {$if defined(SPARC) or defined(MIPS)}
  1237. RemoveDelaySlot(p);
  1238. {$endif SPARC or MIPS}
  1239. hp2:=tai(hp1.next);
  1240. asml.remove(p);
  1241. p.free;
  1242. p:=hp2;
  1243. stoploop:=false;
  1244. continue;
  1245. end
  1246. else if assigned(hp1) then
  1247. begin
  1248. { change the following jumps:
  1249. jmp<cond> lab_1 jmp<cond_inverted> lab_2
  1250. jmp lab_2 >>> <code>
  1251. lab_1: lab_2:
  1252. <code>
  1253. lab_2:
  1254. }
  1255. if hp1.typ = ait_label then
  1256. SkipLabels(hp1,hp1);
  1257. if (tai(hp1).typ=ait_instruction) and
  1258. IsJumpToLabelUncond(taicpu(hp1)) and
  1259. GetNextInstruction(hp1, hp2) and
  1260. IsJumpToLabel(taicpu(p)) and
  1261. FindLabel(tasmlabel(JumpTargetOp(taicpu(p))^.ref^.symbol), hp2) then
  1262. begin
  1263. if (taicpu(p).opcode=aopt_condjmp)
  1264. {$if defined(arm) or defined(aarch64)}
  1265. and (taicpu(p).condition<>C_None)
  1266. {$endif arm or aarch64}
  1267. {$if defined(aarch64)}
  1268. { can't have conditional branches to
  1269. global labels on AArch64, because the
  1270. offset may become too big }
  1271. and (tasmlabel(JumpTargetOp(taicpu(hp1))^.ref^.symbol).bind=AB_LOCAL)
  1272. {$endif aarch64}
  1273. then
  1274. begin
  1275. taicpu(p).condition:=inverse_cond(taicpu(p).condition);
  1276. tai_label(hp2).labsym.decrefs;
  1277. JumpTargetOp(taicpu(p))^.ref^.symbol:=JumpTargetOp(taicpu(hp1))^.ref^.symbol;
  1278. { when freeing hp1, the reference count
  1279. isn't decreased, so don't increase
  1280. taicpu(p).oper[0]^.ref^.symbol.increfs;
  1281. }
  1282. {$if defined(SPARC) or defined(MIPS)}
  1283. RemoveDelaySlot(hp1);
  1284. {$endif SPARC or MIPS}
  1285. asml.remove(hp1);
  1286. hp1.free;
  1287. stoploop:=false;
  1288. GetFinalDestination(taicpu(p),0);
  1289. end
  1290. else
  1291. begin
  1292. GetFinalDestination(taicpu(p),0);
  1293. p:=tai(p.next);
  1294. continue;
  1295. end;
  1296. end
  1297. else if IsJumpToLabel(taicpu(p)) then
  1298. GetFinalDestination(taicpu(p),0);
  1299. end;
  1300. end;
  1301. end
  1302. else
  1303. { All other optimizes }
  1304. begin
  1305. end; { if is_jmp }
  1306. end;
  1307. end;
  1308. UpdateUsedRegs(p);
  1309. p:=tai(p.next);
  1310. end;
  1311. until stoploop or not(cs_opt_level3 in current_settings.optimizerswitches);
  1312. end;
  1313. procedure TAOptObj.PeepHoleOptPass2;
  1314. begin
  1315. end;
  1316. procedure TAOptObj.PostPeepHoleOpts;
  1317. var
  1318. p: tai;
  1319. begin
  1320. p := BlockStart;
  1321. ClearUsedRegs;
  1322. while (p <> BlockEnd) Do
  1323. begin
  1324. UpdateUsedRegs(tai(p.next));
  1325. if PostPeepHoleOptsCpu(p) then
  1326. continue;
  1327. UpdateUsedRegs(p);
  1328. p:=tai(p.next);
  1329. end;
  1330. end;
  1331. function TAOptObj.PeepHoleOptPass1Cpu(var p: tai): boolean;
  1332. begin
  1333. result := false;
  1334. end;
  1335. function TAOptObj.PostPeepHoleOptsCpu(var p: tai): boolean;
  1336. begin
  1337. result := false;
  1338. end;
  1339. End.