daopt386.pas 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Jonas Maebe, member of the Freepascal
  4. development team
  5. This unit contains the data flow analyzer and several helper procedures
  6. and functions.
  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 DAOpt386;
  21. {$i defines.inc}
  22. Interface
  23. Uses
  24. GlobType,
  25. CObjects,Aasm,
  26. cpubase,cpuasm;
  27. {******************************* Constants *******************************}
  28. Const
  29. {Possible register content types}
  30. con_Unknown = 0;
  31. con_ref = 1;
  32. con_const = 2;
  33. { The contents aren't usable anymore for CSE, but they may still be }
  34. { usefull for detecting whether the result of a load is actually used }
  35. con_invalid = 3;
  36. { the reverse of the above (in case a (conditional) jump is encountered): }
  37. { CSE is still possible, but the original instruction can't be removed }
  38. con_noRemoveRef = 4;
  39. { same, but for constants }
  40. con_noRemoveConst = 5;
  41. {********************************* Types *********************************}
  42. type
  43. TRegArray = Array[R_EAX..R_BL] of TRegister;
  44. TRegSet = Set of R_EAX..R_BL;
  45. TRegInfo = Record
  46. NewRegsEncountered, OldRegsEncountered: TRegSet;
  47. RegsLoadedForRef: TRegSet;
  48. regsStillUsedAfterSeq: TRegSet;
  49. lastReload: array[R_EAX..R_EDI] of pai;
  50. New2OldReg: TRegArray;
  51. End;
  52. {possible actions on an operand: read, write or modify (= read & write)}
  53. TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
  54. {the possible states of a flag}
  55. TFlagContents = (F_Unknown, F_NotSet, F_Set);
  56. TContent = Packed Record
  57. {start and end of block instructions that defines the
  58. content of this register.}
  59. StartMod: pai;
  60. {how many instructions starting with StarMod does the block consist of}
  61. NrOfMods: Byte;
  62. {the type of the content of the register: unknown, memory, constant}
  63. Typ: Byte;
  64. case byte of
  65. {starts at 0, gets increased everytime the register is written to}
  66. 1: (WState: Byte;
  67. {starts at 0, gets increased everytime the register is read from}
  68. RState: Byte);
  69. { to compare both states in one operation }
  70. 2: (state: word);
  71. End;
  72. {Contents of the integer registers}
  73. TRegContent = Array[R_EAX..R_EDI] Of TContent;
  74. {contents of the FPU registers}
  75. TRegFPUContent = Array[R_ST..R_ST7] Of TContent;
  76. {$ifdef tempOpts}
  77. { linked list which allows searching/deleting based on value, no extra frills}
  78. PSearchLinkedListItem = ^TSearchLinkedListItem;
  79. TSearchLinkedListItem = object(TLinkedList_Item)
  80. constructor init;
  81. function equals(p: PSearchLinkedListItem): boolean; virtual;
  82. end;
  83. PSearchDoubleIntItem = ^TSearchDoubleInttem;
  84. TSearchDoubleIntItem = object(TLinkedList_Item)
  85. constructor init(_int1,_int2: longint);
  86. function equals(p: PSearchLinkedListItem): boolean; virtual;
  87. private
  88. int1, int2: longint;
  89. end;
  90. PSearchLinkedList = ^TSearchLinkedList;
  91. TSearchLinkedList = object(TLinkedList)
  92. function searchByValue(p: PSearchLinkedListItem): boolean;
  93. procedure removeByValue(p: PSearchLinkedListItem);
  94. end;
  95. {$endif tempOpts}
  96. {information record with the contents of every register. Every Pai object
  97. gets one of these assigned: a pointer to it is stored in the OptInfo field}
  98. TPaiProp = Record
  99. Regs: TRegContent;
  100. { FPURegs: TRegFPUContent;} {currently not yet used}
  101. { allocated Registers }
  102. UsedRegs: TRegSet;
  103. { status of the direction flag }
  104. DirFlag: TFlagContents;
  105. {$ifdef tempOpts}
  106. { currently used temps }
  107. tempAllocs: PSearchLinkedList;
  108. {$endif tempOpts}
  109. { can this instruction be removed? }
  110. CanBeRemoved: Boolean;
  111. End;
  112. PPaiProp = ^TPaiProp;
  113. TPaiPropBlock = Array[1..250000] Of TPaiProp;
  114. PPaiPropBlock = ^TPaiPropBlock;
  115. TInstrSinceLastMod = Array[R_EAX..R_EDI] Of Byte;
  116. TLabelTableItem = Record
  117. PaiObj: Pai;
  118. {$IfDef JumpAnal}
  119. InstrNr: Longint;
  120. RefsFound: Word;
  121. JmpsProcessed: Word
  122. {$EndIf JumpAnal}
  123. End;
  124. TLabelTable = Array[0..2500000] Of TLabelTableItem;
  125. PLabelTable = ^TLabelTable;
  126. {*********************** Procedures and Functions ************************}
  127. Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one: PLinkedList_Item);
  128. Function Reg32(Reg: TRegister): TRegister;
  129. Function RefsEquivalent(Const R1, R2: TReference; Var RegInfo: TRegInfo; OpAct: TOpAction): Boolean;
  130. Function RefsEqual(Const R1, R2: TReference): Boolean;
  131. Function IsGP32Reg(Reg: TRegister): Boolean;
  132. Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
  133. function RegReadByInstruction(reg: TRegister; hp: pai): boolean;
  134. function RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
  135. function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
  136. function RegInOp(Reg: TRegister; const o:toper): Boolean;
  137. function writeToMemDestroysContents(regWritten: tregister; const ref: treference;
  138. reg: tregister; const c: tcontent): boolean;
  139. function writeToRegDestroysContents(destReg: tregister; reg: tregister;
  140. const c: tcontent): boolean;
  141. function writeDestroysContents(const op: toper; reg: tregister;
  142. const c: tcontent): boolean;
  143. Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
  144. Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
  145. Procedure SkipHead(var P: Pai);
  146. function labelCanBeSkipped(p: pai_label): boolean;
  147. Procedure RemoveLastDeallocForFuncRes(asmL: PAasmOutput; p: pai);
  148. Function regLoadedWithNewValue(reg: tregister; canDependOnPrevValue: boolean;
  149. hp: pai): boolean;
  150. Procedure UpdateUsedRegs(Var UsedRegs: TRegSet; p: Pai);
  151. Procedure AllocRegBetween(AsmL: PAasmOutput; Reg: TRegister; p1, p2: Pai);
  152. function FindRegDealloc(reg: tregister; p: pai): boolean;
  153. Function RegsEquivalent(OldReg, NewReg: TRegister; Var RegInfo: TRegInfo; OpAct: TopAction): Boolean;
  154. Function InstructionsEquivalent(p1, p2: Pai; Var RegInfo: TRegInfo): Boolean;
  155. Function OpsEqual(const o1,o2:toper): Boolean;
  156. Function DFAPass1(AsmL: PAasmOutput; BlockStart: Pai): Pai;
  157. Function DFAPass2(
  158. {$ifdef statedebug}
  159. AsmL: PAasmOutPut;
  160. {$endif statedebug}
  161. BlockStart, BlockEnd: Pai): Boolean;
  162. Procedure ShutDownDFA;
  163. Function FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
  164. Procedure IncState(Var S: Byte; amount: longint);
  165. {******************************* Variables *******************************}
  166. Var
  167. {the amount of PaiObjects in the current assembler list}
  168. NrOfPaiObjs: Longint;
  169. {Array which holds all TPaiProps}
  170. PaiPropBlock: PPaiPropBlock;
  171. LoLab, HiLab, LabDif: Longint;
  172. LTable: PLabelTable;
  173. {*********************** End of Interface section ************************}
  174. Implementation
  175. Uses
  176. globals, systems, verbose, hcodegen, symconst, tgeni386;
  177. Type
  178. TRefCompare = function(const r1, r2: TReference): Boolean;
  179. Var
  180. {How many instructions are between the current instruction and the last one
  181. that modified the register}
  182. NrOfInstrSinceLastMod: TInstrSinceLastMod;
  183. {$ifdef tempOpts}
  184. constructor TSearchLinkedListItem.init;
  185. begin
  186. end;
  187. function TSearchLinkedListItem.equals(p: PSearchLinkedListItem): boolean;
  188. begin
  189. equals := false;
  190. end;
  191. constructor TSearchDoubleIntItem.init(_int1,_int2: longint);
  192. begin
  193. int1 := _int1;
  194. int2 := _int2;
  195. end;
  196. function TSearchDoubleIntItem.equals(p: PSearchLinkedListItem): boolean;
  197. begin
  198. equals := (TSearchDoubleIntItem(p).int1 = int1) and
  199. (TSearchDoubleIntItem(p).int2 = int2);
  200. end;
  201. function TSearchLinkedList.searchByValue(p: PSearchLinkedListItem): boolean;
  202. var temp: PSearchLinkedListItem;
  203. begin
  204. temp := first;
  205. while (temp <> last^.next) and
  206. not(temp^.equals(p)) do
  207. temp := temp^.next;
  208. searchByValue := temp <> last^.next;
  209. end;
  210. procedure TSearchLinkedList.removeByValue(p: PSearchLinkedListItem);
  211. begin
  212. temp := first;
  213. while (temp <> last^.next) and
  214. not(temp^.equals(p)) do
  215. temp := temp^.next;
  216. if temp <> last^.next then
  217. begin
  218. remove(temp);
  219. dispose(temp,done);
  220. end;
  221. end;
  222. Procedure updateTempAllocs(Var UsedRegs: TRegSet; p: Pai);
  223. {updates UsedRegs with the RegAlloc Information coming after P}
  224. Begin
  225. Repeat
  226. While Assigned(p) And
  227. ((p^.typ in (SkipInstr - [ait_RegAlloc])) or
  228. ((p^.typ = ait_label) And
  229. labelCanBeSkipped(pai_label(current)))) Do
  230. p := Pai(p^.next);
  231. While Assigned(p) And
  232. (p^.typ=ait_RegAlloc) Do
  233. Begin
  234. if pairegalloc(p)^.allocation then
  235. UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
  236. else
  237. UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
  238. p := pai(p^.next);
  239. End;
  240. Until Not(Assigned(p)) Or
  241. (Not(p^.typ in SkipInstr) And
  242. Not((p^.typ = ait_label) And
  243. labelCanBeSkipped(pai_label(current))));
  244. End;
  245. {$endif tempOpts}
  246. {************************ Create the Label table ************************}
  247. Function FindLoHiLabels(Var LowLabel, HighLabel, LabelDif: Longint; BlockStart: Pai): Pai;
  248. {Walks through the paasmlist to find the lowest and highest label number}
  249. Var LabelFound: Boolean;
  250. P, lastP: Pai;
  251. Begin
  252. LabelFound := False;
  253. LowLabel := MaxLongint;
  254. HighLabel := 0;
  255. P := BlockStart;
  256. lastP := p;
  257. While Assigned(P) Do
  258. Begin
  259. If (Pai(p)^.typ = ait_label) Then
  260. If not labelCanBeSkipped(pai_label(p))
  261. Then
  262. Begin
  263. LabelFound := True;
  264. If (Pai_Label(p)^.l^.labelnr < LowLabel) Then
  265. LowLabel := Pai_Label(p)^.l^.labelnr;
  266. If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
  267. HighLabel := Pai_Label(p)^.l^.labelnr;
  268. End;
  269. lastP := p;
  270. GetNextInstruction(p, p);
  271. End;
  272. if (lastP^.typ = ait_marker) and
  273. (pai_marker(lastP)^.kind = asmBlockStart) then
  274. FindLoHiLabels := lastP
  275. else FindLoHiLabels := nil;
  276. If LabelFound
  277. Then LabelDif := HighLabel+1-LowLabel
  278. Else LabelDif := 0;
  279. End;
  280. Function FindRegAlloc(Reg: TRegister; StartPai: Pai; alloc: boolean): Boolean;
  281. { Returns true if a ait_alloc object for Reg is found in the block of Pai's }
  282. { starting with StartPai and ending with the next "real" instruction }
  283. Begin
  284. FindRegAlloc := false;
  285. Repeat
  286. While Assigned(StartPai) And
  287. ((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
  288. ((StartPai^.typ = ait_label) and
  289. labelCanBeSkipped(pai_label(startPai)))) Do
  290. StartPai := Pai(StartPai^.Next);
  291. If Assigned(StartPai) and
  292. (StartPai^.typ = ait_regAlloc) then
  293. begin
  294. if (PairegAlloc(StartPai)^.allocation = alloc) and
  295. (PairegAlloc(StartPai)^.Reg = Reg) then
  296. begin
  297. FindRegAlloc:=true;
  298. break;
  299. end;
  300. StartPai := Pai(StartPai^.Next);
  301. end
  302. else
  303. break;
  304. Until false;
  305. End;
  306. Procedure RemoveLastDeallocForFuncRes(asmL: PAasmOutput; p: pai);
  307. Procedure DoRemoveLastDeallocForFuncRes(asmL: PAasmOutput; reg: TRegister);
  308. var
  309. hp2: pai;
  310. begin
  311. hp2 := p;
  312. repeat
  313. hp2 := pai(hp2^.previous);
  314. if assigned(hp2) and
  315. (hp2^.typ = ait_regalloc) and
  316. not(pairegalloc(hp2)^.allocation) and
  317. (pairegalloc(hp2)^.reg = reg) then
  318. begin
  319. asml^.remove(hp2);
  320. dispose(hp2,done);
  321. break;
  322. end;
  323. until not(assigned(hp2)) or
  324. regInInstruction(reg,hp2);
  325. end;
  326. begin
  327. if assigned(procinfo^.returntype.def) then
  328. case procinfo^.returntype.def^.deftype of
  329. arraydef,recorddef,pointerdef,
  330. stringdef,enumdef,procdef,objectdef,errordef,
  331. filedef,setdef,procvardef,
  332. classrefdef,forwarddef:
  333. DoRemoveLastDeallocForFuncRes(asmL,R_EAX);
  334. orddef:
  335. if procinfo^.returntype.def^.size <> 0 then
  336. begin
  337. DoRemoveLastDeallocForFuncRes(asmL,R_EAX);
  338. { for int64/qword }
  339. if procinfo^.returntype.def^.size = 8 then
  340. DoRemoveLastDeallocForFuncRes(asmL,R_EDX);
  341. end;
  342. end;
  343. end;
  344. procedure getNoDeallocRegs(var regs: TRegSet);
  345. var regCounter: TRegister;
  346. begin
  347. regs := [];
  348. if assigned(procinfo^.returntype.def) then
  349. case procinfo^.returntype.def^.deftype of
  350. arraydef,recorddef,pointerdef,
  351. stringdef,enumdef,procdef,objectdef,errordef,
  352. filedef,setdef,procvardef,
  353. classrefdef,forwarddef:
  354. regs := [R_EAX];
  355. orddef:
  356. if procinfo^.returntype.def^.size <> 0 then
  357. begin
  358. regs := [R_EAX];
  359. { for int64/qword }
  360. if procinfo^.returntype.def^.size = 8 then
  361. regs := regs + [R_EDX];
  362. end;
  363. end;
  364. for regCounter := R_EAX to R_EBX do
  365. if not(regCounter in usableregs) then
  366. regs := regs + [regCounter];
  367. end;
  368. Procedure AddRegDeallocFor(asmL: paasmOutput; reg: TRegister; p: pai);
  369. var hp1: pai;
  370. funcResRegs: TRegset;
  371. funcResReg: boolean;
  372. begin
  373. if not(reg in usableregs) then
  374. exit;
  375. getNoDeallocRegs(funcResRegs);
  376. funcResRegs := funcResRegs - usableregs;
  377. funcResReg := reg in funcResRegs;
  378. hp1 := p;
  379. while not(funcResReg and
  380. (p^.typ = ait_instruction) and
  381. (paicpu(p)^.opcode = A_JMP) and
  382. (pasmlabel(paicpu(p)^.oper[0].sym) = aktexit2label)) and
  383. getLastInstruction(p, p) And
  384. not(regInInstruction(reg, p)) Do
  385. hp1 := p;
  386. { don't insert a dealloc for registers which contain the function result }
  387. { if they are followed by a jump to the exit label (for exit(...)) }
  388. if not(funcResReg) or
  389. not((hp1^.typ = ait_instruction) and
  390. (paicpu(hp1)^.opcode = A_JMP) and
  391. (pasmlabel(paicpu(hp1)^.oper[0].sym) = aktexit2label)) then
  392. begin
  393. p := new(paiRegAlloc, deAlloc(reg));
  394. insertLLItem(AsmL, hp1^.previous, hp1, p);
  395. end;
  396. end;
  397. Procedure BuildLabelTableAndFixRegAlloc(asmL: PAasmOutput; Var LabelTable: PLabelTable; LowLabel: Longint;
  398. Var LabelDif: Longint; BlockStart, BlockEnd: Pai);
  399. {Builds a table with the locations of the labels in the paasmoutput.
  400. Also fixes some RegDeallocs like "# %eax released; push (%eax)"}
  401. Var p, hp1, hp2, lastP: Pai;
  402. regCounter: TRegister;
  403. UsedRegs, noDeallocRegs: TRegSet;
  404. Begin
  405. UsedRegs := [];
  406. If (LabelDif <> 0) Then
  407. Begin
  408. GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
  409. FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
  410. End;
  411. p := BlockStart;
  412. lastP := p;
  413. While (P <> BlockEnd) Do
  414. Begin
  415. Case p^.typ Of
  416. ait_Label:
  417. If not labelCanBeSkipped(pai_label(p)) Then
  418. LabelTable^[Pai_Label(p)^.l^.labelnr-LowLabel].PaiObj := p;
  419. ait_regAlloc:
  420. { ESI and EDI are (de)allocated manually, don't mess with them }
  421. if not(paiRegAlloc(p)^.Reg in [R_EDI,R_ESI]) then
  422. begin
  423. if PairegAlloc(p)^.Allocation then
  424. Begin
  425. If Not(paiRegAlloc(p)^.Reg in UsedRegs) Then
  426. UsedRegs := UsedRegs + [paiRegAlloc(p)^.Reg]
  427. Else
  428. addRegDeallocFor(asmL, paiRegAlloc(p)^.reg, p);
  429. End
  430. else
  431. begin
  432. UsedRegs := UsedRegs - [paiRegAlloc(p)^.Reg];
  433. hp1 := p;
  434. hp2 := nil;
  435. While Not(FindRegAlloc(paiRegAlloc(p)^.Reg, Pai(hp1^.Next),true)) And
  436. GetNextInstruction(hp1, hp1) And
  437. RegInInstruction(paiRegAlloc(p)^.Reg, hp1) Do
  438. hp2 := hp1;
  439. If hp2 <> nil Then
  440. Begin
  441. hp1 := Pai(p^.previous);
  442. AsmL^.Remove(p);
  443. InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
  444. p := hp1;
  445. end;
  446. end;
  447. end;
  448. end;
  449. repeat
  450. lastP := p;
  451. P := Pai(P^.Next);
  452. until not(Assigned(p)) or
  453. not(p^.typ in (SkipInstr - [ait_regalloc]));
  454. End;
  455. { don't add deallocation for function result variable or for regvars}
  456. getNoDeallocRegs(noDeallocRegs);
  457. usedRegs := usedRegs - noDeallocRegs;
  458. for regCounter := R_EAX to R_EDI do
  459. if regCounter in usedRegs then
  460. addRegDeallocFor(asmL,regCounter,lastP);
  461. End;
  462. {************************ Search the Label table ************************}
  463. Function FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
  464. {searches for the specified label starting from hp as long as the
  465. encountered instructions are labels, to be able to optimize constructs like
  466. jne l2 jmp l2
  467. jmp l3 and l1:
  468. l1: l2:
  469. l2:}
  470. Var TempP: Pai;
  471. Begin
  472. TempP := hp;
  473. While Assigned(TempP) and
  474. (TempP^.typ In SkipInstr + [ait_label,ait_align]) Do
  475. If (TempP^.typ <> ait_Label) Or
  476. (pai_label(TempP)^.l <> L)
  477. Then GetNextInstruction(TempP, TempP)
  478. Else
  479. Begin
  480. hp := TempP;
  481. FindLabel := True;
  482. exit
  483. End;
  484. FindLabel := False;
  485. End;
  486. {************************ Some general functions ************************}
  487. Function TCh2Reg(Ch: TInsChange): TRegister;
  488. {converts a TChange variable to a TRegister}
  489. Begin
  490. If (Ch <= Ch_REDI) Then
  491. TCh2Reg := TRegister(Byte(Ch))
  492. Else
  493. If (Ch <= Ch_WEDI) Then
  494. TCh2Reg := TRegister(Byte(Ch) - Byte(Ch_REDI))
  495. Else
  496. If (Ch <= Ch_RWEDI) Then
  497. TCh2Reg := TRegister(Byte(Ch) - Byte(Ch_WEDI))
  498. Else
  499. If (Ch <= Ch_MEDI) Then
  500. TCh2Reg := TRegister(Byte(Ch) - Byte(Ch_RWEDI))
  501. Else InternalError($db)
  502. End;
  503. Function Reg32(Reg: TRegister): TRegister;
  504. {Returns the 32 bit component of Reg if it exists, otherwise Reg is returned}
  505. Begin
  506. Reg32 := Reg;
  507. If (Reg >= R_AX)
  508. Then
  509. If (Reg <= R_DI)
  510. Then Reg32 := Reg16ToReg32(Reg)
  511. Else
  512. If (Reg <= R_BL)
  513. Then Reg32 := Reg8toReg32(Reg);
  514. End;
  515. { inserts new_one between prev and foll }
  516. Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one: PLinkedList_Item);
  517. Begin
  518. If Assigned(prev) Then
  519. If Assigned(foll) Then
  520. Begin
  521. If Assigned(new_one) Then
  522. Begin
  523. new_one^.previous := prev;
  524. new_one^.next := foll;
  525. prev^.next := new_one;
  526. foll^.previous := new_one;
  527. Pai(new_one)^.fileinfo := Pai(foll)^.fileinfo;
  528. End;
  529. End
  530. Else AsmL^.Concat(new_one)
  531. Else If Assigned(Foll) Then AsmL^.Insert(new_one)
  532. End;
  533. {********************* Compare parts of Pai objects *********************}
  534. Function RegsSameSize(Reg1, Reg2: TRegister): Boolean;
  535. {returns true if Reg1 and Reg2 are of the same size (so if they're both
  536. 8bit, 16bit or 32bit)}
  537. Begin
  538. If (Reg1 <= R_EDI)
  539. Then RegsSameSize := (Reg2 <= R_EDI)
  540. Else
  541. If (Reg1 <= R_DI)
  542. Then RegsSameSize := (Reg2 in [R_AX..R_DI])
  543. Else
  544. If (Reg1 <= R_BL)
  545. Then RegsSameSize := (Reg2 in [R_AL..R_BL])
  546. Else RegsSameSize := False
  547. End;
  548. Procedure AddReg2RegInfo(OldReg, NewReg: TRegister; Var RegInfo: TRegInfo);
  549. {updates the ???RegsEncountered and ???2???Reg fields of RegInfo. Assumes that
  550. OldReg and NewReg have the same size (has to be chcked in advance with
  551. RegsSameSize) and that neither equals R_NO}
  552. Begin
  553. With RegInfo Do
  554. Begin
  555. NewRegsEncountered := NewRegsEncountered + [NewReg];
  556. OldRegsEncountered := OldRegsEncountered + [OldReg];
  557. New2OldReg[NewReg] := OldReg;
  558. Case OldReg Of
  559. R_EAX..R_EDI:
  560. Begin
  561. NewRegsEncountered := NewRegsEncountered + [Reg32toReg16(NewReg)];
  562. OldRegsEncountered := OldRegsEncountered + [Reg32toReg16(OldReg)];
  563. New2OldReg[Reg32toReg16(NewReg)] := Reg32toReg16(OldReg);
  564. If (NewReg in [R_EAX..R_EBX]) And
  565. (OldReg in [R_EAX..R_EBX]) Then
  566. Begin
  567. NewRegsEncountered := NewRegsEncountered + [Reg32toReg8(NewReg)];
  568. OldRegsEncountered := OldRegsEncountered + [Reg32toReg8(OldReg)];
  569. New2OldReg[Reg32toReg8(NewReg)] := Reg32toReg8(OldReg);
  570. End;
  571. End;
  572. R_AX..R_DI:
  573. Begin
  574. NewRegsEncountered := NewRegsEncountered + [Reg16toReg32(NewReg)];
  575. OldRegsEncountered := OldRegsEncountered + [Reg16toReg32(OldReg)];
  576. New2OldReg[Reg16toReg32(NewReg)] := Reg16toReg32(OldReg);
  577. If (NewReg in [R_AX..R_BX]) And
  578. (OldReg in [R_AX..R_BX]) Then
  579. Begin
  580. NewRegsEncountered := NewRegsEncountered + [Reg16toReg8(NewReg)];
  581. OldRegsEncountered := OldRegsEncountered + [Reg16toReg8(OldReg)];
  582. New2OldReg[Reg16toReg8(NewReg)] := Reg16toReg8(OldReg);
  583. End;
  584. End;
  585. R_AL..R_BL:
  586. Begin
  587. NewRegsEncountered := NewRegsEncountered + [Reg8toReg32(NewReg)]
  588. + [Reg8toReg16(NewReg)];
  589. OldRegsEncountered := OldRegsEncountered + [Reg8toReg32(OldReg)]
  590. + [Reg8toReg16(OldReg)];
  591. New2OldReg[Reg8toReg32(NewReg)] := Reg8toReg32(OldReg);
  592. End;
  593. End;
  594. End;
  595. End;
  596. Procedure AddOp2RegInfo(const o:Toper; Var RegInfo: TRegInfo);
  597. Begin
  598. Case o.typ Of
  599. Top_Reg:
  600. If (o.reg <> R_NO) Then
  601. AddReg2RegInfo(o.reg, o.reg, RegInfo);
  602. Top_Ref:
  603. Begin
  604. If o.ref^.base <> R_NO Then
  605. AddReg2RegInfo(o.ref^.base, o.ref^.base, RegInfo);
  606. If o.ref^.index <> R_NO Then
  607. AddReg2RegInfo(o.ref^.index, o.ref^.index, RegInfo);
  608. End;
  609. End;
  610. End;
  611. Function RegsEquivalent(OldReg, NewReg: TRegister; Var RegInfo: TRegInfo; OPAct: TOpAction): Boolean;
  612. Begin
  613. If Not((OldReg = R_NO) Or (NewReg = R_NO)) Then
  614. If RegsSameSize(OldReg, NewReg) Then
  615. With RegInfo Do
  616. {here we always check for the 32 bit component, because it is possible that
  617. the 8 bit component has not been set, event though NewReg already has been
  618. processed. This happens if it has been compared with a register that doesn't
  619. have an 8 bit component (such as EDI). In that case the 8 bit component is
  620. still set to R_NO and the comparison in the Else-part will fail}
  621. If (Reg32(OldReg) in OldRegsEncountered) Then
  622. If (Reg32(NewReg) in NewRegsEncountered) Then
  623. RegsEquivalent := (OldReg = New2OldReg[NewReg])
  624. { If we haven't encountered the new register yet, but we have encountered the
  625. old one already, the new one can only be correct if it's being written to
  626. (and consequently the old one is also being written to), otherwise
  627. movl -8(%ebp), %eax and movl -8(%ebp), %eax
  628. movl (%eax), %eax movl (%edx), %edx
  629. are considered equivalent}
  630. Else
  631. If (OpAct = OpAct_Write) Then
  632. Begin
  633. AddReg2RegInfo(OldReg, NewReg, RegInfo);
  634. RegsEquivalent := True
  635. End
  636. Else Regsequivalent := False
  637. Else
  638. If Not(Reg32(NewReg) in NewRegsEncountered) and
  639. ((OpAct = OpAct_Write) or
  640. (newReg = oldReg)) Then
  641. Begin
  642. AddReg2RegInfo(OldReg, NewReg, RegInfo);
  643. RegsEquivalent := True
  644. End
  645. Else RegsEquivalent := False
  646. Else RegsEquivalent := False
  647. Else RegsEquivalent := OldReg = NewReg
  648. End;
  649. Function RefsEquivalent(Const R1, R2: TReference; var RegInfo: TRegInfo; OpAct: TOpAction): Boolean;
  650. Begin
  651. If R1.is_immediate Then
  652. RefsEquivalent := R2.is_immediate and (R1.Offset = R2.Offset)
  653. Else
  654. RefsEquivalent := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup) And
  655. RegsEquivalent(R1.Base, R2.Base, RegInfo, OpAct) And
  656. RegsEquivalent(R1.Index, R2.Index, RegInfo, OpAct) And
  657. (R1.Segment = R2.Segment) And (R1.ScaleFactor = R2.ScaleFactor) And
  658. (R1.Symbol = R2.Symbol);
  659. End;
  660. Function RefsEqual(Const R1, R2: TReference): Boolean;
  661. Begin
  662. If R1.is_immediate Then
  663. RefsEqual := R2.is_immediate and (R1.Offset = R2.Offset)
  664. Else
  665. RefsEqual := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup) And
  666. (R1.Segment = R2.Segment) And (R1.Base = R2.Base) And
  667. (R1.Index = R2.Index) And (R1.ScaleFactor = R2.ScaleFactor) And
  668. (R1.Symbol=R2.Symbol);
  669. End;
  670. Function IsGP32Reg(Reg: TRegister): Boolean;
  671. {Checks if the register is a 32 bit general purpose register}
  672. Begin
  673. If (Reg >= R_EAX) and (Reg <= R_EBX)
  674. Then IsGP32Reg := True
  675. Else IsGP32reg := False
  676. End;
  677. Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
  678. Begin {checks whether Ref contains a reference to Reg}
  679. Reg := Reg32(Reg);
  680. RegInRef := (Ref.Base = Reg) Or (Ref.Index = Reg)
  681. End;
  682. function RegReadByInstruction(reg: TRegister; hp: pai): boolean;
  683. var p: paicpu;
  684. opCount: byte;
  685. begin
  686. RegReadByInstruction := false;
  687. reg := reg32(reg);
  688. p := paicpu(hp);
  689. if hp^.typ <> ait_instruction then
  690. exit;
  691. case p^.opcode of
  692. A_IMUL:
  693. case p^.ops of
  694. 1: regReadByInstruction := (reg = R_EAX) or reginOp(reg,p^.oper[0]);
  695. 2,3:
  696. regReadByInstruction := regInOp(reg,p^.oper[0]) or
  697. regInOp(reg,p^.oper[1]);
  698. end;
  699. A_IDIV,A_DIV,A_MUL:
  700. begin
  701. regReadByInstruction :=
  702. regInOp(reg,p^.oper[0]) or (reg = R_EAX);
  703. end;
  704. else
  705. begin
  706. for opCount := 0 to 2 do
  707. if (p^.oper[opCount].typ = top_ref) and
  708. RegInRef(reg,p^.oper[opCount].ref^) then
  709. begin
  710. RegReadByInstruction := true;
  711. exit
  712. end;
  713. for opCount := 1 to MaxCh do
  714. case InsProp[p^.opcode].Ch[opCount] of
  715. Ch_REAX..CH_REDI,CH_RWEAX..Ch_MEDI:
  716. if reg = TCh2Reg(InsProp[p^.opcode].Ch[opCount]) then
  717. begin
  718. RegReadByInstruction := true;
  719. exit
  720. end;
  721. Ch_RWOp1,Ch_ROp1,Ch_MOp1:
  722. if (p^.oper[0].typ = top_reg) and
  723. (reg32(p^.oper[0].reg) = reg) then
  724. begin
  725. RegReadByInstruction := true;
  726. exit
  727. end;
  728. Ch_RWOp2,Ch_ROp2,Ch_MOp2:
  729. if (p^.oper[1].typ = top_reg) and
  730. (reg32(p^.oper[1].reg) = reg) then
  731. begin
  732. RegReadByInstruction := true;
  733. exit
  734. end;
  735. Ch_RWOp3,Ch_ROp3,Ch_MOp3:
  736. if (p^.oper[2].typ = top_reg) and
  737. (reg32(p^.oper[2].reg) = reg) then
  738. begin
  739. RegReadByInstruction := true;
  740. exit
  741. end;
  742. end;
  743. end;
  744. end;
  745. end;
  746. function regInInstruction(Reg: TRegister; p1: Pai): Boolean;
  747. { Checks if Reg is used by the instruction p1 }
  748. { Difference with "regReadBysinstruction() or regModifiedByInstruction()": }
  749. { this one ignores CH_ALL opcodes, while regModifiedByInstruction doesn't }
  750. var p: paicpu;
  751. opCount: byte;
  752. begin
  753. reg := reg32(reg);
  754. regInInstruction := false;
  755. p := paicpu(p1);
  756. if p1^.typ <> ait_instruction then
  757. exit;
  758. case p^.opcode of
  759. A_IMUL:
  760. case p^.ops of
  761. 1: regInInstruction := (reg = R_EAX) or reginOp(reg,p^.oper[0]);
  762. 2,3:
  763. regInInstruction := regInOp(reg,p^.oper[0]) or
  764. regInOp(reg,p^.oper[1]) or regInOp(reg,p^.oper[2]);
  765. end;
  766. A_IDIV,A_DIV,A_MUL:
  767. regInInstruction :=
  768. regInOp(reg,p^.oper[0]) or
  769. (reg = R_EAX) or (reg = R_EDX)
  770. else
  771. begin
  772. for opCount := 1 to MaxCh do
  773. case InsProp[p^.opcode].Ch[opCount] of
  774. CH_REAX..CH_MEDI:
  775. if tch2reg(InsProp[p^.opcode].Ch[opCount]) = reg then
  776. begin
  777. regInInstruction := true;
  778. exit;
  779. end;
  780. Ch_ROp1..Ch_MOp1:
  781. if regInOp(reg,p^.oper[0]) then
  782. begin
  783. regInInstruction := true;
  784. exit
  785. end;
  786. Ch_ROp2..Ch_MOp2:
  787. if regInOp(reg,p^.oper[1]) then
  788. begin
  789. regInInstruction := true;
  790. exit
  791. end;
  792. Ch_ROp3..Ch_MOp3:
  793. if regInOp(reg,p^.oper[2]) then
  794. begin
  795. regInInstruction := true;
  796. exit
  797. end;
  798. end;
  799. end;
  800. end;
  801. end;
  802. Function RegInOp(Reg: TRegister; const o:toper): Boolean;
  803. Begin
  804. RegInOp := False;
  805. reg := reg32(reg);
  806. Case o.typ Of
  807. top_reg: RegInOp := Reg = reg32(o.reg);
  808. top_ref: RegInOp := (Reg = o.ref^.Base) Or
  809. (Reg = o.ref^.Index);
  810. End;
  811. End;
  812. Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
  813. Var InstrProp: TInsProp;
  814. TmpResult: Boolean;
  815. Cnt: Byte;
  816. Begin
  817. TmpResult := False;
  818. Reg := Reg32(Reg);
  819. If (p1^.typ = ait_instruction) Then
  820. Case paicpu(p1)^.opcode of
  821. A_IMUL:
  822. With paicpu(p1)^ Do
  823. TmpResult :=
  824. ((ops = 1) and (reg in [R_EAX,R_EDX])) or
  825. ((ops = 2) and (Reg32(oper[1].reg) = reg)) or
  826. ((ops = 3) and (Reg32(oper[2].reg) = reg));
  827. A_DIV, A_IDIV, A_MUL:
  828. With paicpu(p1)^ Do
  829. TmpResult :=
  830. (Reg = R_EAX) or
  831. (Reg = R_EDX);
  832. Else
  833. Begin
  834. Cnt := 1;
  835. InstrProp := InsProp[paicpu(p1)^.OpCode];
  836. While (Cnt <= MaxCh) And
  837. (InstrProp.Ch[Cnt] <> Ch_None) And
  838. Not(TmpResult) Do
  839. Begin
  840. Case InstrProp.Ch[Cnt] Of
  841. Ch_WEAX..Ch_MEDI:
  842. TmpResult := Reg = TCh2Reg(InstrProp.Ch[Cnt]);
  843. Ch_RWOp1,Ch_WOp1,Ch_Mop1:
  844. TmpResult := (paicpu(p1)^.oper[0].typ = top_reg) and
  845. (Reg32(paicpu(p1)^.oper[0].reg) = reg);
  846. Ch_RWOp2,Ch_WOp2,Ch_Mop2:
  847. TmpResult := (paicpu(p1)^.oper[1].typ = top_reg) and
  848. (Reg32(paicpu(p1)^.oper[1].reg) = reg);
  849. Ch_RWOp3,Ch_WOp3,Ch_Mop3:
  850. TmpResult := (paicpu(p1)^.oper[2].typ = top_reg) and
  851. (Reg32(paicpu(p1)^.oper[2].reg) = reg);
  852. Ch_FPU: TmpResult := Reg in [R_ST..R_ST7,R_MM0..R_MM7];
  853. Ch_ALL: TmpResult := true;
  854. End;
  855. Inc(Cnt)
  856. End
  857. End
  858. End;
  859. RegModifiedByInstruction := TmpResult
  860. End;
  861. {********************* GetNext and GetLastInstruction *********************}
  862. Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
  863. { skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
  864. { next pai object in Next. Returns false if there isn't any }
  865. Begin
  866. Repeat
  867. If (Current^.typ = ait_marker) And
  868. (Pai_Marker(Current)^.Kind = AsmBlockStart) Then
  869. Begin
  870. GetNextInstruction := False;
  871. Next := Nil;
  872. Exit
  873. End;
  874. Current := Pai(Current^.Next);
  875. While Assigned(Current) And
  876. ((current^.typ In skipInstr) or
  877. ((current^.typ = ait_label) and
  878. labelCanBeSkipped(pai_label(current)))) do
  879. Current := Pai(Current^.Next);
  880. { If Assigned(Current) And
  881. (Current^.typ = ait_Marker) And
  882. (Pai_Marker(Current)^.Kind = NoPropInfoStart) Then
  883. Begin
  884. While Assigned(Current) And
  885. ((Current^.typ <> ait_Marker) Or
  886. (Pai_Marker(Current)^.Kind <> NoPropInfoEnd)) Do
  887. Current := Pai(Current^.Next);
  888. End;}
  889. Until Not(Assigned(Current)) Or
  890. (Current^.typ <> ait_Marker) Or
  891. not(Pai_Marker(Current)^.Kind in [NoPropInfoStart,NoPropInfoEnd]);
  892. Next := Current;
  893. If Assigned(Current) And
  894. Not((Current^.typ In SkipInstr) or
  895. ((Current^.typ = ait_label) And
  896. labelCanBeSkipped(pai_label(current))))
  897. Then
  898. GetNextInstruction :=
  899. not((current^.typ = ait_marker) and
  900. (pai_marker(current)^.kind = asmBlockStart))
  901. Else
  902. Begin
  903. GetNextInstruction := False;
  904. Next := nil;
  905. End;
  906. End;
  907. Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
  908. {skips the ait-types in SkipInstr puts the previous pai object in
  909. Last. Returns false if there isn't any}
  910. Begin
  911. Repeat
  912. Current := Pai(Current^.previous);
  913. While Assigned(Current) And
  914. (((Current^.typ = ait_Marker) And
  915. Not(Pai_Marker(Current)^.Kind in [AsmBlockEnd{,NoPropInfoEnd}])) or
  916. (Current^.typ In SkipInstr) or
  917. ((Current^.typ = ait_label) And
  918. labelCanBeSkipped(pai_label(current)))) Do
  919. Current := Pai(Current^.previous);
  920. { If Assigned(Current) And
  921. (Current^.typ = ait_Marker) And
  922. (Pai_Marker(Current)^.Kind = NoPropInfoEnd) Then
  923. Begin
  924. While Assigned(Current) And
  925. ((Current^.typ <> ait_Marker) Or
  926. (Pai_Marker(Current)^.Kind <> NoPropInfoStart)) Do
  927. Current := Pai(Current^.previous);
  928. End;}
  929. Until Not(Assigned(Current)) Or
  930. (Current^.typ <> ait_Marker) Or
  931. not(Pai_Marker(Current)^.Kind in [NoPropInfoStart,NoPropInfoEnd]);
  932. If Not(Assigned(Current)) or
  933. (Current^.typ In SkipInstr) or
  934. ((Current^.typ = ait_label) And
  935. labelCanBeSkipped(pai_label(current))) or
  936. ((Current^.typ = ait_Marker) And
  937. (Pai_Marker(Current)^.Kind = AsmBlockEnd))
  938. Then
  939. Begin
  940. Last := nil;
  941. GetLastInstruction := False
  942. End
  943. Else
  944. Begin
  945. Last := Current;
  946. GetLastInstruction := True;
  947. End;
  948. End;
  949. Procedure SkipHead(var P: Pai);
  950. Var OldP: Pai;
  951. Begin
  952. Repeat
  953. OldP := P;
  954. If (P^.typ in SkipInstr) Or
  955. ((P^.typ = ait_marker) And
  956. (Pai_Marker(P)^.Kind = AsmBlockEnd)) Then
  957. GetNextInstruction(P, P)
  958. Else If ((P^.Typ = Ait_Marker) And
  959. (Pai_Marker(P)^.Kind = NoPropInfoStart)) Then
  960. {a marker of the NoPropInfoStart can't be the first instruction of a
  961. paasmoutput list}
  962. GetNextInstruction(Pai(P^.Previous),P);
  963. Until P = OldP
  964. End;
  965. function labelCanBeSkipped(p: pai_label): boolean;
  966. begin
  967. labelCanBeSkipped := not(p^.l^.is_used) or p^.l^.is_addr;
  968. end;
  969. {******************* The Data Flow Analyzer functions ********************}
  970. function regLoadedWithNewValue(reg: tregister; canDependOnPrevValue: boolean;
  971. hp: pai): boolean;
  972. { assumes reg is a 32bit register }
  973. var p: paicpu;
  974. begin
  975. p := paicpu(hp);
  976. regLoadedWithNewValue :=
  977. assigned(hp) and
  978. (hp^.typ = ait_instruction) and
  979. (((p^.opcode = A_MOV) or
  980. (p^.opcode = A_MOVZX) or
  981. (p^.opcode = A_MOVSX) or
  982. (p^.opcode = A_LEA)) and
  983. (p^.oper[1].typ = top_reg) and
  984. (Reg32(p^.oper[1].reg) = reg) and
  985. (canDependOnPrevValue or
  986. (p^.oper[0].typ <> top_ref) or
  987. not regInRef(reg,p^.oper[0].ref^)) or
  988. ((p^.opcode = A_POP) and
  989. (Reg32(p^.oper[0].reg) = reg)));
  990. end;
  991. Procedure UpdateUsedRegs(Var UsedRegs: TRegSet; p: Pai);
  992. {updates UsedRegs with the RegAlloc Information coming after P}
  993. Begin
  994. Repeat
  995. While Assigned(p) And
  996. ((p^.typ in (SkipInstr - [ait_RegAlloc])) or
  997. ((p^.typ = ait_label) And
  998. labelCanBeSkipped(pai_label(p)))) Do
  999. p := Pai(p^.next);
  1000. While Assigned(p) And
  1001. (p^.typ=ait_RegAlloc) Do
  1002. Begin
  1003. if pairegalloc(p)^.allocation then
  1004. UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
  1005. else
  1006. UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
  1007. p := pai(p^.next);
  1008. End;
  1009. Until Not(Assigned(p)) Or
  1010. (Not(p^.typ in SkipInstr) And
  1011. Not((p^.typ = ait_label) And
  1012. labelCanBeSkipped(pai_label(p))));
  1013. End;
  1014. Procedure AllocRegBetween(AsmL: PAasmOutput; Reg: TRegister; p1, p2: Pai);
  1015. { allocates register Reg between (and including) instructions p1 and p2 }
  1016. { the type of p1 and p2 must not be in SkipInstr }
  1017. var
  1018. hp: pai;
  1019. lastRemovedWasDealloc: boolean;
  1020. Begin
  1021. If not(reg in usableregs+[R_EDI,R_ESI]) or
  1022. not(assigned(p1)) Then
  1023. { this happens with registers which are loaded implicitely, outside the }
  1024. { current block (e.g. esi with self) }
  1025. exit;
  1026. lastRemovedWasDealloc := false;
  1027. {$ifdef allocregdebug}
  1028. hp := new(pai_asm_comment,init(strpnew('allocating '+att_reg2str[reg]+
  1029. ' from here...')));
  1030. insertllitem(asml,p1^.previous,p1,hp);
  1031. hp := new(pai_asm_comment,init(strpnew('allocated '+att_reg2str[reg]+
  1032. ' till here...')));
  1033. insertllitem(asml,p2,p1^.next,hp);
  1034. {$endif allocregdebug}
  1035. if Assigned(p1^.optInfo) and
  1036. not (reg in PPaiProp(p1^.OptInfo)^.UsedRegs) then
  1037. begin
  1038. hp := new(paiRegalloc,alloc(reg));
  1039. insertLLItem(asmL,p1^.previous,p1,hp);
  1040. end;
  1041. Repeat
  1042. If Assigned(p1^.OptInfo) Then
  1043. Include(PPaiProp(p1^.OptInfo)^.UsedRegs,Reg);
  1044. p1 := Pai(p1^.next);
  1045. Repeat
  1046. While assigned(p1) and
  1047. (p1^.typ in (SkipInstr-[ait_regalloc])) Do
  1048. p1 := Pai(p1^.next);
  1049. { remove all allocation/deallocation info about the register in between }
  1050. If assigned(p1) and
  1051. (p1^.typ = ait_regalloc) Then
  1052. If (PaiRegAlloc(p1)^.Reg = Reg) Then
  1053. Begin
  1054. lastRemovedWasDealloc := not PaiRegAlloc(p1)^.allocation;
  1055. hp := Pai(p1^.Next);
  1056. AsmL^.Remove(p1);
  1057. Dispose(p1, Done);
  1058. p1 := hp;
  1059. End
  1060. Else p1 := Pai(p1^.next);
  1061. Until not(assigned(p1)) or
  1062. Not(p1^.typ in SkipInstr);
  1063. Until not(assigned(p1)) or
  1064. (p1 = p2);
  1065. if assigned(p1) then
  1066. begin
  1067. if assigned(p1^.optinfo) then
  1068. include(PPaiProp(p1^.OptInfo)^.UsedRegs,Reg);
  1069. if lastRemovedWasDealloc then
  1070. begin
  1071. hp := new(paiRegalloc,dealloc(reg));
  1072. insertLLItem(asmL,p1,p1^.next,hp);
  1073. end;
  1074. end;
  1075. End;
  1076. function FindRegDealloc(reg: tregister; p: pai): boolean;
  1077. { assumes reg is a 32bit register }
  1078. var
  1079. hp: pai;
  1080. first: boolean;
  1081. begin
  1082. findregdealloc := false;
  1083. first := true;
  1084. while assigned(p^.previous) and
  1085. ((Pai(p^.previous)^.typ in (skipinstr+[ait_align])) or
  1086. ((Pai(p^.previous)^.typ = ait_label) and
  1087. labelCanBeSkipped(pai_label(p^.previous)))) do
  1088. begin
  1089. p := pai(p^.previous);
  1090. if (p^.typ = ait_regalloc) and
  1091. (pairegalloc(p)^.reg = reg) then
  1092. if not(pairegalloc(p)^.allocation) then
  1093. if first then
  1094. begin
  1095. findregdealloc := true;
  1096. break;
  1097. end
  1098. else
  1099. begin
  1100. findRegDealloc :=
  1101. getNextInstruction(p,hp) and
  1102. regLoadedWithNewValue(reg,false,hp);
  1103. break
  1104. end
  1105. else
  1106. first := false;
  1107. end
  1108. end;
  1109. Procedure IncState(Var S: Byte; amount: longint);
  1110. {Increases S by 1, wraps around at $ffff to 0 (so we won't get overflow
  1111. errors}
  1112. Begin
  1113. if (s <= $ff - amount) then
  1114. inc(s, amount)
  1115. else s := longint(s) + amount - $ff;
  1116. End;
  1117. Function sequenceDependsonReg(Const Content: TContent; seqReg, Reg: TRegister): Boolean;
  1118. { Content is the sequence of instructions that describes the contents of }
  1119. { seqReg. Reg is being overwritten by the current instruction. If the }
  1120. { content of seqReg depends on reg (ie. because of a }
  1121. { "movl (seqreg,reg), seqReg" instruction), this function returns true }
  1122. Var p: Pai;
  1123. Counter: Byte;
  1124. TmpResult: Boolean;
  1125. RegsChecked: TRegSet;
  1126. Begin
  1127. RegsChecked := [];
  1128. p := Content.StartMod;
  1129. TmpResult := False;
  1130. Counter := 1;
  1131. While Not(TmpResult) And
  1132. (Counter <= Content.NrOfMods) Do
  1133. Begin
  1134. If (p^.typ = ait_instruction) and
  1135. ((Paicpu(p)^.opcode = A_MOV) or
  1136. (Paicpu(p)^.opcode = A_MOVZX) or
  1137. (Paicpu(p)^.opcode = A_MOVSX) or
  1138. (paicpu(p)^.opcode = A_LEA)) and
  1139. (Paicpu(p)^.oper[0].typ = top_ref) Then
  1140. With Paicpu(p)^.oper[0].ref^ Do
  1141. If ((Base = procinfo^.FramePointer) or
  1142. (assigned(symbol) and (base = R_NO))) And
  1143. (Index = R_NO) Then
  1144. Begin
  1145. RegsChecked := RegsChecked + [Reg32(Paicpu(p)^.oper[1].reg)];
  1146. If Reg = Reg32(Paicpu(p)^.oper[1].reg) Then
  1147. Break;
  1148. End
  1149. Else
  1150. tmpResult :=
  1151. regReadByInstruction(reg,p) and
  1152. regModifiedByInstruction(seqReg,p)
  1153. Else
  1154. tmpResult :=
  1155. regReadByInstruction(reg,p) and
  1156. regModifiedByInstruction(seqReg,p);
  1157. Inc(Counter);
  1158. GetNextInstruction(p,p)
  1159. End;
  1160. sequenceDependsonReg := TmpResult
  1161. End;
  1162. procedure invalidateDependingRegs(p1: ppaiProp; reg: tregister);
  1163. var
  1164. counter: tregister;
  1165. begin
  1166. for counter := R_EAX to R_EDI Do
  1167. if counter <> reg then
  1168. with p1^.regs[counter] Do
  1169. if (typ in [con_ref,con_noRemoveRef]) and
  1170. sequenceDependsOnReg(p1^.Regs[counter],counter,reg) then
  1171. if typ in [con_ref,con_invalid] then
  1172. typ := con_invalid
  1173. { con_invalid and con_noRemoveRef = con_unknown }
  1174. else typ := con_unknown;
  1175. end;
  1176. Procedure DestroyReg(p1: PPaiProp; Reg: TRegister; doIncState:Boolean);
  1177. {Destroys the contents of the register Reg in the PPaiProp p1, as well as the
  1178. contents of registers are loaded with a memory location based on Reg.
  1179. doIncState is false when this register has to be destroyed not because
  1180. it's contents are directly modified/overwritten, but because of an indirect
  1181. action (e.g. this register holds the contents of a variable and the value
  1182. of the variable in memory is changed) }
  1183. Begin
  1184. Reg := Reg32(Reg);
  1185. { the following happens for fpu registers }
  1186. if (reg < low(NrOfInstrSinceLastMod)) or
  1187. (reg > high(NrOfInstrSinceLastMod)) then
  1188. exit;
  1189. NrOfInstrSinceLastMod[Reg] := 0;
  1190. if (reg >= R_EAX) and (reg <= R_EDI) then
  1191. begin
  1192. with p1^.regs[reg] do
  1193. begin
  1194. if doIncState then
  1195. begin
  1196. incState(wstate,1);
  1197. typ := con_unknown;
  1198. end
  1199. else
  1200. if typ in [con_ref,con_invalid] then
  1201. typ := con_invalid
  1202. { con_invalid and con_noRemoveRef = con_unknown }
  1203. else typ := con_unknown;
  1204. end;
  1205. invalidateDependingRegs(p1,reg);
  1206. end;
  1207. End;
  1208. {Procedure AddRegsToSet(p: Pai; Var RegSet: TRegSet);
  1209. Begin
  1210. If (p^.typ = ait_instruction) Then
  1211. Begin
  1212. Case Paicpu(p)^.oper[0].typ Of
  1213. top_reg:
  1214. If Not(Paicpu(p)^.oper[0].reg in [R_NO,R_ESP,procinfo^.FramePointer]) Then
  1215. RegSet := RegSet + [Paicpu(p)^.oper[0].reg];
  1216. top_ref:
  1217. With TReference(Paicpu(p)^.oper[0]^) Do
  1218. Begin
  1219. If Not(Base in [procinfo^.FramePointer,R_NO,R_ESP])
  1220. Then RegSet := RegSet + [Base];
  1221. If Not(Index in [procinfo^.FramePointer,R_NO,R_ESP])
  1222. Then RegSet := RegSet + [Index];
  1223. End;
  1224. End;
  1225. Case Paicpu(p)^.oper[1].typ Of
  1226. top_reg:
  1227. If Not(Paicpu(p)^.oper[1].reg in [R_NO,R_ESP,procinfo^.FramePointer]) Then
  1228. If RegSet := RegSet + [TRegister(TwoWords(Paicpu(p)^.oper[1]).Word1];
  1229. top_ref:
  1230. With TReference(Paicpu(p)^.oper[1]^) Do
  1231. Begin
  1232. If Not(Base in [procinfo^.FramePointer,R_NO,R_ESP])
  1233. Then RegSet := RegSet + [Base];
  1234. If Not(Index in [procinfo^.FramePointer,R_NO,R_ESP])
  1235. Then RegSet := RegSet + [Index];
  1236. End;
  1237. End;
  1238. End;
  1239. End;}
  1240. Function OpsEquivalent(const o1, o2: toper; Var RegInfo: TRegInfo; OpAct: TopAction): Boolean;
  1241. Begin {checks whether the two ops are equivalent}
  1242. OpsEquivalent := False;
  1243. if o1.typ=o2.typ then
  1244. Case o1.typ Of
  1245. Top_Reg:
  1246. OpsEquivalent :=RegsEquivalent(o1.reg,o2.reg, RegInfo, OpAct);
  1247. Top_Ref:
  1248. OpsEquivalent := RefsEquivalent(o1.ref^, o2.ref^, RegInfo, OpAct);
  1249. Top_Const:
  1250. OpsEquivalent := o1.val = o2.val;
  1251. Top_None:
  1252. OpsEquivalent := True
  1253. End;
  1254. End;
  1255. Function OpsEqual(const o1,o2:toper): Boolean;
  1256. Begin {checks whether the two ops are equal}
  1257. OpsEqual := False;
  1258. if o1.typ=o2.typ then
  1259. Case o1.typ Of
  1260. Top_Reg :
  1261. OpsEqual:=o1.reg=o2.reg;
  1262. Top_Ref :
  1263. OpsEqual := RefsEqual(o1.ref^, o2.ref^);
  1264. Top_Const :
  1265. OpsEqual:=o1.val=o2.val;
  1266. Top_Symbol :
  1267. OpsEqual:=(o1.sym=o2.sym) and (o1.symofs=o2.symofs);
  1268. Top_None :
  1269. OpsEqual := True
  1270. End;
  1271. End;
  1272. Function InstructionsEquivalent(p1, p2: Pai; Var RegInfo: TRegInfo): Boolean;
  1273. {$ifdef csdebug}
  1274. var
  1275. hp: pai;
  1276. {$endif csdebug}
  1277. Begin {checks whether two Paicpu instructions are equal}
  1278. If Assigned(p1) And Assigned(p2) And
  1279. (Pai(p1)^.typ = ait_instruction) And
  1280. (Pai(p1)^.typ = ait_instruction) And
  1281. (Paicpu(p1)^.opcode = Paicpu(p2)^.opcode) And
  1282. (Paicpu(p1)^.oper[0].typ = Paicpu(p2)^.oper[0].typ) And
  1283. (Paicpu(p1)^.oper[1].typ = Paicpu(p2)^.oper[1].typ) And
  1284. (Paicpu(p1)^.oper[2].typ = Paicpu(p2)^.oper[2].typ)
  1285. Then
  1286. {both instructions have the same structure:
  1287. "<operator> <operand of type1>, <operand of type 2>"}
  1288. If ((Paicpu(p1)^.opcode = A_MOV) or
  1289. (Paicpu(p1)^.opcode = A_MOVZX) or
  1290. (Paicpu(p1)^.opcode = A_MOVSX)) And
  1291. (Paicpu(p1)^.oper[0].typ = top_ref) {then .oper[1]t = top_reg} Then
  1292. If Not(RegInRef(Paicpu(p1)^.oper[1].reg, Paicpu(p1)^.oper[0].ref^)) Then
  1293. {the "old" instruction is a load of a register with a new value, not with
  1294. a value based on the contents of this register (so no "mov (reg), reg")}
  1295. If Not(RegInRef(Paicpu(p2)^.oper[1].reg, Paicpu(p2)^.oper[0].ref^)) And
  1296. RefsEqual(Paicpu(p1)^.oper[0].ref^, Paicpu(p2)^.oper[0].ref^)
  1297. Then
  1298. {the "new" instruction is also a load of a register with a new value, and
  1299. this value is fetched from the same memory location}
  1300. Begin
  1301. With Paicpu(p2)^.oper[0].ref^ Do
  1302. Begin
  1303. If Not(Base in [procinfo^.FramePointer, R_NO, R_ESP]) Then
  1304. RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef + [Base];
  1305. If Not(Index in [procinfo^.FramePointer, R_NO, R_ESP]) Then
  1306. RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef + [Index];
  1307. End;
  1308. {add the registers from the reference (.oper[0]) to the RegInfo, all registers
  1309. from the reference are the same in the old and in the new instruction
  1310. sequence}
  1311. AddOp2RegInfo(Paicpu(p1)^.oper[0], RegInfo);
  1312. {the registers from .oper[1] have to be equivalent, but not necessarily equal}
  1313. InstructionsEquivalent :=
  1314. RegsEquivalent(Paicpu(p1)^.oper[1].reg, Paicpu(p2)^.oper[1].reg, RegInfo, OpAct_Write);
  1315. End
  1316. {the registers are loaded with values from different memory locations. If
  1317. this was allowed, the instructions "mov -4(esi),eax" and "mov -4(ebp),eax"
  1318. would be considered equivalent}
  1319. Else InstructionsEquivalent := False
  1320. Else
  1321. {load register with a value based on the current value of this register}
  1322. Begin
  1323. With Paicpu(p2)^.oper[0].ref^ Do
  1324. Begin
  1325. If Not(Base in [procinfo^.FramePointer,
  1326. Reg32(Paicpu(p2)^.oper[1].reg),R_NO,R_ESP]) Then
  1327. {it won't do any harm if the register is already in RegsLoadedForRef}
  1328. Begin
  1329. RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef + [Base];
  1330. {$ifdef csdebug}
  1331. Writeln(att_reg2str[base], ' added');
  1332. {$endif csdebug}
  1333. end;
  1334. If Not(Index in [procinfo^.FramePointer,
  1335. Reg32(Paicpu(p2)^.oper[1].reg),R_NO,R_ESP]) Then
  1336. Begin
  1337. RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef + [Index];
  1338. {$ifdef csdebug}
  1339. Writeln(att_reg2str[index], ' added');
  1340. {$endif csdebug}
  1341. end;
  1342. End;
  1343. If Not(Reg32(Paicpu(p2)^.oper[1].reg) In [procinfo^.FramePointer,R_NO,R_ESP])
  1344. Then
  1345. Begin
  1346. RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef -
  1347. [Reg32(Paicpu(p2)^.oper[1].reg)];
  1348. {$ifdef csdebug}
  1349. Writeln(att_reg2str[Reg32(Paicpu(p2)^.oper[1].reg)], ' removed');
  1350. {$endif csdebug}
  1351. end;
  1352. InstructionsEquivalent :=
  1353. OpsEquivalent(Paicpu(p1)^.oper[0], Paicpu(p2)^.oper[0], RegInfo, OpAct_Read) And
  1354. OpsEquivalent(Paicpu(p1)^.oper[1], Paicpu(p2)^.oper[1], RegInfo, OpAct_Write)
  1355. End
  1356. Else
  1357. {an instruction <> mov, movzx, movsx}
  1358. begin
  1359. {$ifdef csdebug}
  1360. hp := new(pai_asm_comment,init(strpnew('checking if equivalent')));
  1361. hp^.previous := p2;
  1362. hp^.next := p2^.next;
  1363. p2^.next^.previous := hp;
  1364. p2^.next := hp;
  1365. {$endif csdebug}
  1366. InstructionsEquivalent :=
  1367. OpsEquivalent(Paicpu(p1)^.oper[0], Paicpu(p2)^.oper[0], RegInfo, OpAct_Unknown) And
  1368. OpsEquivalent(Paicpu(p1)^.oper[1], Paicpu(p2)^.oper[1], RegInfo, OpAct_Unknown) And
  1369. OpsEquivalent(Paicpu(p1)^.oper[2], Paicpu(p2)^.oper[2], RegInfo, OpAct_Unknown)
  1370. end
  1371. {the instructions haven't even got the same structure, so they're certainly
  1372. not equivalent}
  1373. Else
  1374. begin
  1375. {$ifdef csdebug}
  1376. hp := new(pai_asm_comment,init(strpnew('different opcodes/format')));
  1377. hp^.previous := p2;
  1378. hp^.next := p2^.next;
  1379. p2^.next^.previous := hp;
  1380. p2^.next := hp;
  1381. {$endif csdebug}
  1382. InstructionsEquivalent := False;
  1383. end;
  1384. {$ifdef csdebug}
  1385. hp := new(pai_asm_comment,init(strpnew('instreq: '+tostr(byte(instructionsequivalent)))));
  1386. hp^.previous := p2;
  1387. hp^.next := p2^.next;
  1388. p2^.next^.previous := hp;
  1389. p2^.next := hp;
  1390. {$endif csdebug}
  1391. End;
  1392. (*
  1393. Function InstructionsEqual(p1, p2: Pai): Boolean;
  1394. Begin {checks whether two Paicpu instructions are equal}
  1395. InstructionsEqual :=
  1396. Assigned(p1) And Assigned(p2) And
  1397. ((Pai(p1)^.typ = ait_instruction) And
  1398. (Pai(p1)^.typ = ait_instruction) And
  1399. (Paicpu(p1)^.opcode = Paicpu(p2)^.opcode) And
  1400. (Paicpu(p1)^.oper[0].typ = Paicpu(p2)^.oper[0].typ) And
  1401. (Paicpu(p1)^.oper[1].typ = Paicpu(p2)^.oper[1].typ) And
  1402. OpsEqual(Paicpu(p1)^.oper[0].typ, Paicpu(p1)^.oper[0], Paicpu(p2)^.oper[0]) And
  1403. OpsEqual(Paicpu(p1)^.oper[1].typ, Paicpu(p1)^.oper[1], Paicpu(p2)^.oper[1]))
  1404. End;
  1405. *)
  1406. Procedure ReadReg(p: PPaiProp; Reg: TRegister);
  1407. Begin
  1408. Reg := Reg32(Reg);
  1409. If Reg in [R_EAX..R_EDI] Then
  1410. incState(p^.regs[Reg].rstate,1)
  1411. End;
  1412. Procedure ReadRef(p: PPaiProp; Ref: PReference);
  1413. Begin
  1414. If Ref^.Base <> R_NO Then
  1415. ReadReg(p, Ref^.Base);
  1416. If Ref^.Index <> R_NO Then
  1417. ReadReg(p, Ref^.Index);
  1418. End;
  1419. Procedure ReadOp(P: PPaiProp;const o:toper);
  1420. Begin
  1421. Case o.typ Of
  1422. top_reg: ReadReg(P, o.reg);
  1423. top_ref: ReadRef(P, o.ref);
  1424. top_symbol : ;
  1425. End;
  1426. End;
  1427. Function RefInInstruction(Const Ref: TReference; p: Pai;
  1428. RefsEq: TRefCompare): Boolean;
  1429. {checks whehter Ref is used in P}
  1430. Var TmpResult: Boolean;
  1431. Begin
  1432. TmpResult := False;
  1433. If (p^.typ = ait_instruction) Then
  1434. Begin
  1435. If (Paicpu(p)^.oper[0].typ = Top_Ref) Then
  1436. TmpResult := RefsEq(Ref, Paicpu(p)^.oper[0].ref^);
  1437. If Not(TmpResult) And (Paicpu(p)^.oper[1].typ = Top_Ref) Then
  1438. TmpResult := RefsEq(Ref, Paicpu(p)^.oper[1].ref^);
  1439. If Not(TmpResult) And (Paicpu(p)^.oper[2].typ = Top_Ref) Then
  1440. TmpResult := RefsEq(Ref, Paicpu(p)^.oper[2].ref^);
  1441. End;
  1442. RefInInstruction := TmpResult;
  1443. End;
  1444. Function RefInSequence(Const Ref: TReference; Content: TContent;
  1445. RefsEq: TRefCompare): Boolean;
  1446. {checks the whole sequence of Content (so StartMod and and the next NrOfMods
  1447. Pai objects) to see whether Ref is used somewhere}
  1448. Var p: Pai;
  1449. Counter: Byte;
  1450. TmpResult: Boolean;
  1451. Begin
  1452. p := Content.StartMod;
  1453. TmpResult := False;
  1454. Counter := 1;
  1455. While Not(TmpResult) And
  1456. (Counter <= Content.NrOfMods) Do
  1457. Begin
  1458. If (p^.typ = ait_instruction) And
  1459. RefInInstruction(Ref, p, RefsEq)
  1460. Then TmpResult := True;
  1461. Inc(Counter);
  1462. GetNextInstruction(p,p)
  1463. End;
  1464. RefInSequence := TmpResult
  1465. End;
  1466. Function ArrayRefsEq(const r1, r2: TReference): Boolean;
  1467. Begin
  1468. ArrayRefsEq := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup) And
  1469. (R1.Segment = R2.Segment) And
  1470. (R1.Symbol=R2.Symbol) And
  1471. (R1.Base = R2.Base)
  1472. End;
  1473. function isSimpleRef(const ref: treference): boolean;
  1474. { returns true if ref is reference to a local or global variable, to a }
  1475. { parameter or to an object field (this includes arrays). Returns false }
  1476. { otherwise. }
  1477. begin
  1478. isSimpleRef :=
  1479. assigned(ref.symbol) or
  1480. (ref.base = procinfo^.framepointer) or
  1481. (assigned(procinfo^._class) and
  1482. (ref.base = R_ESI));
  1483. end;
  1484. function containsPointerRef(p: pai): boolean;
  1485. { checks if an instruction contains a reference which is a pointer location }
  1486. var
  1487. hp: paicpu;
  1488. count: longint;
  1489. begin
  1490. containsPointerRef := false;
  1491. if p^.typ <> ait_instruction then
  1492. exit;
  1493. hp := paicpu(p);
  1494. for count := low(hp^.oper) to high(hp^.oper) do
  1495. begin
  1496. case hp^.oper[count].typ of
  1497. top_ref:
  1498. if not isSimpleRef(hp^.oper[count].ref^) then
  1499. begin
  1500. containsPointerRef := true;
  1501. exit;
  1502. end;
  1503. top_none:
  1504. exit;
  1505. end;
  1506. end;
  1507. end;
  1508. function containsPointerLoad(c: tcontent): boolean;
  1509. { checks whether the contents of a register contain a pointer reference }
  1510. var
  1511. p: pai;
  1512. count: longint;
  1513. begin
  1514. containsPointerLoad := false;
  1515. p := c.startmod;
  1516. for count := c.nrOfMods downto 1 do
  1517. begin
  1518. if containsPointerRef(p) then
  1519. begin
  1520. containsPointerLoad := true;
  1521. exit;
  1522. end;
  1523. getnextinstruction(p,p);
  1524. end;
  1525. end;
  1526. function writeToMemDestroysContents(regWritten: tregister; const ref: treference;
  1527. reg: tregister; const c: tcontent): boolean;
  1528. { returns whether the contents c of reg are invalid after regWritten is }
  1529. { is written to ref }
  1530. var
  1531. refsEq: trefCompare;
  1532. begin
  1533. if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
  1534. begin
  1535. writeToMemDestroysContents := false;
  1536. exit;
  1537. end;
  1538. reg := reg32(reg);
  1539. regWritten := reg32(regWritten);
  1540. if isSimpleRef(ref) then
  1541. begin
  1542. if (ref.index <> R_NO) or
  1543. (assigned(ref.symbol) and
  1544. (ref.base <> R_NO)) then
  1545. { local/global variable or parameter which is an array }
  1546. refsEq := {$ifdef fpc}@{$endif}arrayRefsEq
  1547. else
  1548. { local/global variable or parameter which is not an array }
  1549. refsEq := {$ifdef fpc}@{$endif}refsEqual;
  1550. { write something to a parameter, a local or global variable, so }
  1551. { * with uncertain optimizations on: }
  1552. { - destroy the contents of registers whose contents have somewhere a }
  1553. { "mov?? (Ref), %reg". WhichReg (this is the register whose contents }
  1554. { are being written to memory) is not destroyed if it's StartMod is }
  1555. { of that form and NrOfMods = 1 (so if it holds ref, but is not a }
  1556. { expression based on Ref) }
  1557. { * with uncertain optimizations off: }
  1558. { - also destroy registers that contain any pointer }
  1559. with c do
  1560. writeToMemDestroysContents :=
  1561. (typ in [con_ref,con_noRemoveRef]) and
  1562. ((not(cs_uncertainOpts in aktglobalswitches) and
  1563. containsPointerLoad(c)
  1564. ) or
  1565. (refInSequence(ref,c,refsEq) and
  1566. ((reg <> regWritten) or
  1567. ((nrOfMods <> 1) and
  1568. {StarMod is always of the type ait_instruction}
  1569. (paicpu(StartMod)^.oper[0].typ = top_ref) and
  1570. refsEq(Paicpu(StartMod)^.oper[0].ref^, ref)
  1571. )
  1572. )
  1573. )
  1574. )
  1575. end
  1576. else
  1577. { write something to a pointer location, so }
  1578. { * with uncertain optimzations on: }
  1579. { - do not destroy registers which contain a local/global variable or }
  1580. { a parameter, except if DestroyRefs is called because of a "movsl" }
  1581. { * with uncertain optimzations off: }
  1582. { - destroy every register which contains a memory location }
  1583. with c do
  1584. writeToMemDestroysContents :=
  1585. (typ in [con_ref,con_noRemoveRef]) and
  1586. (not(cs_UncertainOpts in aktglobalswitches) or
  1587. { for movsl }
  1588. ((ref.base = R_EDI) and (ref.index = R_EDI)) or
  1589. { don't destroy if reg contains a parameter, local or global variable }
  1590. containsPointerLoad(c)
  1591. )
  1592. end;
  1593. function writeToRegDestroysContents(destReg: tregister; reg: tregister;
  1594. const c: tcontent): boolean;
  1595. { returns whether the contents c of reg are invalid after destReg is }
  1596. { modified }
  1597. begin
  1598. writeToRegDestroysContents :=
  1599. (c.typ in [con_ref,con_noRemoveRef,con_invalid]) and
  1600. sequenceDependsOnReg(c,reg,reg32(destReg));
  1601. end;
  1602. function writeDestroysContents(const op: toper; reg: tregister;
  1603. const c: tcontent): boolean;
  1604. { returns whether the contents c of reg are invalid after regWritten is }
  1605. { is written to op }
  1606. begin
  1607. reg := reg32(reg);
  1608. case op.typ of
  1609. top_reg:
  1610. writeDestroysContents :=
  1611. writeToRegDestroysContents(op.reg,reg,c);
  1612. top_ref:
  1613. writeDestroysContents :=
  1614. writeToMemDestroysContents(R_NO,op.ref^,reg,c);
  1615. else
  1616. writeDestroysContents := false;
  1617. end;
  1618. end;
  1619. procedure destroyRefs(p: pai; const ref: treference; regWritten: tregister);
  1620. { destroys all registers which possibly contain a reference to Ref, regWritten }
  1621. { is the register whose contents are being written to memory (if this proc }
  1622. { is called because of a "mov?? %reg, (mem)" instruction) }
  1623. var
  1624. counter: TRegister;
  1625. begin
  1626. for counter := R_EAX to R_EDI Do
  1627. if writeToMemDestroysContents(regWritten,ref,counter,
  1628. ppaiProp(p^.optInfo)^.regs[counter]) then
  1629. destroyReg(ppaiProp(p^.optInfo), counter, false)
  1630. End;
  1631. Procedure DestroyAllRegs(p: PPaiProp);
  1632. Var Counter: TRegister;
  1633. Begin {initializes/desrtoys all registers}
  1634. For Counter := R_EAX To R_EDI Do
  1635. Begin
  1636. ReadReg(p, Counter);
  1637. DestroyReg(p, Counter, true);
  1638. End;
  1639. p^.DirFlag := F_Unknown;
  1640. End;
  1641. Procedure DestroyOp(PaiObj: Pai; const o:Toper);
  1642. {$ifdef statedebug}
  1643. var hp: pai;
  1644. {$endif statedebug}
  1645. Begin
  1646. Case o.typ Of
  1647. top_reg:
  1648. begin
  1649. {$ifdef statedebug}
  1650. hp := new(pai_asm_comment,init(strpnew('destroying '+att_reg2str[o.reg])));
  1651. hp^.next := paiobj^.next;
  1652. hp^.previous := paiobj;
  1653. paiobj^.next := hp;
  1654. if assigned(hp^.next) then
  1655. hp^.next^.previous := hp;
  1656. {$endif statedebug}
  1657. DestroyReg(PPaiProp(PaiObj^.OptInfo), reg32(o.reg), true);
  1658. end;
  1659. top_ref:
  1660. Begin
  1661. ReadRef(PPaiProp(PaiObj^.OptInfo), o.ref);
  1662. DestroyRefs(PaiObj, o.ref^, R_NO);
  1663. End;
  1664. top_symbol:;
  1665. End;
  1666. End;
  1667. Function DFAPass1(AsmL: PAasmOutput; BlockStart: Pai): Pai;
  1668. {gathers the RegAlloc data... still need to think about where to store it to
  1669. avoid global vars}
  1670. Var BlockEnd: Pai;
  1671. Begin
  1672. BlockEnd := FindLoHiLabels(LoLab, HiLab, LabDif, BlockStart);
  1673. BuildLabelTableAndFixRegAlloc(AsmL, LTable, LoLab, LabDif, BlockStart, BlockEnd);
  1674. DFAPass1 := BlockEnd;
  1675. End;
  1676. Procedure AddInstr2RegContents({$ifdef statedebug} asml: paasmoutput; {$endif}
  1677. p: paicpu; reg: TRegister);
  1678. {$ifdef statedebug}
  1679. var hp: pai;
  1680. {$endif statedebug}
  1681. Begin
  1682. Reg := Reg32(Reg);
  1683. With PPaiProp(p^.optinfo)^.Regs[reg] Do
  1684. if (typ in [con_ref,con_noRemoveRef])
  1685. Then
  1686. Begin
  1687. incState(wstate,1);
  1688. {also store how many instructions are part of the sequence in the first
  1689. instructions PPaiProp, so it can be easily accessed from within
  1690. CheckSequence}
  1691. Inc(NrOfMods, NrOfInstrSinceLastMod[Reg]);
  1692. PPaiProp(Pai(StartMod)^.OptInfo)^.Regs[Reg].NrOfMods := NrOfMods;
  1693. NrOfInstrSinceLastMod[Reg] := 0;
  1694. {$ifdef StateDebug}
  1695. hp := new(pai_asm_comment,init(strpnew(att_reg2str[reg]+': '+tostr(PPaiProp(p^.optinfo)^.Regs[reg].WState)
  1696. + ' -- ' + tostr(PPaiProp(p^.optinfo)^.Regs[reg].nrofmods))));
  1697. InsertLLItem(AsmL, p, p^.next, hp);
  1698. {$endif StateDebug}
  1699. End
  1700. Else
  1701. Begin
  1702. {$ifdef statedebug}
  1703. hp := new(pai_asm_comment,init(strpnew('destroying '+att_reg2str[reg])));
  1704. insertllitem(asml,p,p^.next,hp);
  1705. {$endif statedebug}
  1706. DestroyReg(PPaiProp(p^.optinfo), Reg, true);
  1707. {$ifdef StateDebug}
  1708. hp := new(pai_asm_comment,init(strpnew(att_reg2str[reg]+': '+tostr(PPaiProp(p^.optinfo)^.Regs[reg].WState))));
  1709. InsertLLItem(AsmL, p, p^.next, hp);
  1710. {$endif StateDebug}
  1711. End
  1712. End;
  1713. Procedure AddInstr2OpContents({$ifdef statedebug} asml: paasmoutput; {$endif}
  1714. p: paicpu; const oper: TOper);
  1715. Begin
  1716. If oper.typ = top_reg Then
  1717. AddInstr2RegContents({$ifdef statedebug} asml, {$endif}p, oper.reg)
  1718. Else
  1719. Begin
  1720. ReadOp(PPaiProp(p^.optinfo), oper);
  1721. DestroyOp(p, oper);
  1722. End
  1723. End;
  1724. Procedure DoDFAPass2(
  1725. {$Ifdef StateDebug}
  1726. AsmL: PAasmOutput;
  1727. {$endif statedebug}
  1728. BlockStart, BlockEnd: Pai);
  1729. {Analyzes the Data Flow of an assembler list. Starts creating the reg
  1730. contents for the instructions starting with p. Returns the last pai which has
  1731. been processed}
  1732. Var
  1733. CurProp: PPaiProp;
  1734. Cnt, InstrCnt : Longint;
  1735. InstrProp: TInsProp;
  1736. UsedRegs: TRegSet;
  1737. p, hp : Pai;
  1738. TmpRef: TReference;
  1739. TmpReg: TRegister;
  1740. {$ifdef AnalyzeLoops}
  1741. TmpState: Byte;
  1742. {$endif AnalyzeLoops}
  1743. Begin
  1744. p := BlockStart;
  1745. UsedRegs := [];
  1746. UpdateUsedregs(UsedRegs, p);
  1747. SkipHead(P);
  1748. BlockStart := p;
  1749. InstrCnt := 1;
  1750. FillChar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0);
  1751. While (P <> BlockEnd) Do
  1752. Begin
  1753. CurProp := @PaiPropBlock^[InstrCnt];
  1754. If (p <> BlockStart)
  1755. Then
  1756. Begin
  1757. {$ifdef JumpAnal}
  1758. If (p^.Typ <> ait_label) Then
  1759. {$endif JumpAnal}
  1760. Begin
  1761. GetLastInstruction(p, hp);
  1762. CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
  1763. CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
  1764. End
  1765. End
  1766. Else
  1767. Begin
  1768. FillChar(CurProp^, SizeOf(CurProp^), 0);
  1769. { For TmpReg := R_EAX to R_EDI Do
  1770. CurProp^.Regs[TmpReg].WState := 1;}
  1771. End;
  1772. CurProp^.UsedRegs := UsedRegs;
  1773. CurProp^.CanBeRemoved := False;
  1774. UpdateUsedRegs(UsedRegs, Pai(p^.Next));
  1775. For TmpReg := R_EAX To R_EDI Do
  1776. Inc(NrOfInstrSinceLastMod[TmpReg]);
  1777. Case p^.typ Of
  1778. ait_marker:;
  1779. ait_label:
  1780. {$Ifndef JumpAnal}
  1781. If not labelCanBeSkipped(pai_label(p)) Then
  1782. DestroyAllRegs(CurProp);
  1783. {$Else JumpAnal}
  1784. Begin
  1785. If not labelCanBeSkipped(pai_label(p)) Then
  1786. With LTable^[Pai_Label(p)^.l^.labelnr-LoLab] Do
  1787. {$IfDef AnalyzeLoops}
  1788. If (RefsFound = Pai_Label(p)^.l^.RefCount)
  1789. {$Else AnalyzeLoops}
  1790. If (JmpsProcessed = Pai_Label(p)^.l^.RefCount)
  1791. {$EndIf AnalyzeLoops}
  1792. Then
  1793. {all jumps to this label have been found}
  1794. {$IfDef AnalyzeLoops}
  1795. If (JmpsProcessed > 0)
  1796. Then
  1797. {$EndIf AnalyzeLoops}
  1798. {we've processed at least one jump to this label}
  1799. Begin
  1800. If (GetLastInstruction(p, hp) And
  1801. Not(((hp^.typ = ait_instruction)) And
  1802. (paicpu_labeled(hp)^.is_jmp))
  1803. Then
  1804. {previous instruction not a JMP -> the contents of the registers after the
  1805. previous intruction has been executed have to be taken into account as well}
  1806. For TmpReg := R_EAX to R_EDI Do
  1807. Begin
  1808. If (CurProp^.Regs[TmpReg].WState <>
  1809. PPaiProp(hp^.OptInfo)^.Regs[TmpReg].WState)
  1810. Then DestroyReg(CurProp, TmpReg, true)
  1811. End
  1812. End
  1813. {$IfDef AnalyzeLoops}
  1814. Else
  1815. {a label from a backward jump (e.g. a loop), no jump to this label has
  1816. already been processed}
  1817. If GetLastInstruction(p, hp) And
  1818. Not(hp^.typ = ait_instruction) And
  1819. (paicpu_labeled(hp)^.opcode = A_JMP))
  1820. Then
  1821. {previous instruction not a jmp, so keep all the registers' contents from the
  1822. previous instruction}
  1823. Begin
  1824. CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
  1825. CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
  1826. End
  1827. Else
  1828. {previous instruction a jmp and no jump to this label processed yet}
  1829. Begin
  1830. hp := p;
  1831. Cnt := InstrCnt;
  1832. {continue until we find a jump to the label or a label which has already
  1833. been processed}
  1834. While GetNextInstruction(hp, hp) And
  1835. Not((hp^.typ = ait_instruction) And
  1836. (paicpu(hp)^.is_jmp) and
  1837. (pasmlabel(paicpu(hp)^.oper[0].sym)^.labelnr = Pai_Label(p)^.l^.labelnr)) And
  1838. Not((hp^.typ = ait_label) And
  1839. (LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].RefsFound
  1840. = Pai_Label(hp)^.l^.RefCount) And
  1841. (LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].JmpsProcessed > 0)) Do
  1842. Inc(Cnt);
  1843. If (hp^.typ = ait_label)
  1844. Then
  1845. {there's a processed label after the current one}
  1846. Begin
  1847. CurProp^.Regs := PaiPropBlock^[Cnt].Regs;
  1848. CurProp^.DirFlag := PaiPropBlock^[Cnt].DirFlag;
  1849. End
  1850. Else
  1851. {there's no label anymore after the current one, or they haven't been
  1852. processed yet}
  1853. Begin
  1854. GetLastInstruction(p, hp);
  1855. CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
  1856. CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
  1857. DestroyAllRegs(PPaiProp(hp^.OptInfo))
  1858. End
  1859. End
  1860. {$EndIf AnalyzeLoops}
  1861. Else
  1862. {not all references to this label have been found, so destroy all registers}
  1863. Begin
  1864. GetLastInstruction(p, hp);
  1865. CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
  1866. CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
  1867. DestroyAllRegs(CurProp)
  1868. End;
  1869. End;
  1870. {$EndIf JumpAnal}
  1871. {$ifdef GDB}
  1872. ait_stabs, ait_stabn, ait_stab_function_name:;
  1873. {$endif GDB}
  1874. ait_align: ; { may destroy flags !!! }
  1875. ait_instruction:
  1876. Begin
  1877. if paicpu(p)^.is_jmp then
  1878. begin
  1879. {$IfNDef JumpAnal}
  1880. for tmpReg := R_EAX to R_EDI do
  1881. with curProp^.regs[tmpReg] do
  1882. case typ of
  1883. con_ref: typ := con_noRemoveRef;
  1884. con_const: typ := con_noRemoveConst;
  1885. con_invalid: typ := con_unknown;
  1886. end;
  1887. {$Else JumpAnal}
  1888. With LTable^[pasmlabel(paicpu(p)^.oper[0].sym)^.labelnr-LoLab] Do
  1889. If (RefsFound = pasmlabel(paicpu(p)^.oper[0].sym)^.RefCount) Then
  1890. Begin
  1891. If (InstrCnt < InstrNr)
  1892. Then
  1893. {forward jump}
  1894. If (JmpsProcessed = 0) Then
  1895. {no jump to this label has been processed yet}
  1896. Begin
  1897. PaiPropBlock^[InstrNr].Regs := CurProp^.Regs;
  1898. PaiPropBlock^[InstrNr].DirFlag := CurProp^.DirFlag;
  1899. Inc(JmpsProcessed);
  1900. End
  1901. Else
  1902. Begin
  1903. For TmpReg := R_EAX to R_EDI Do
  1904. If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
  1905. CurProp^.Regs[TmpReg].WState) Then
  1906. DestroyReg(@PaiPropBlock^[InstrNr], TmpReg, true);
  1907. Inc(JmpsProcessed);
  1908. End
  1909. {$ifdef AnalyzeLoops}
  1910. Else
  1911. { backward jump, a loop for example}
  1912. { If (JmpsProcessed > 0) Or
  1913. Not(GetLastInstruction(PaiObj, hp) And
  1914. (hp^.typ = ait_labeled_instruction) And
  1915. (paicpu_labeled(hp)^.opcode = A_JMP))
  1916. Then}
  1917. {instruction prior to label is not a jmp, or at least one jump to the label
  1918. has yet been processed}
  1919. Begin
  1920. Inc(JmpsProcessed);
  1921. For TmpReg := R_EAX to R_EDI Do
  1922. If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
  1923. CurProp^.Regs[TmpReg].WState)
  1924. Then
  1925. Begin
  1926. TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
  1927. Cnt := InstrNr;
  1928. While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
  1929. Begin
  1930. DestroyReg(@PaiPropBlock^[Cnt], TmpReg, true);
  1931. Inc(Cnt);
  1932. End;
  1933. While (Cnt <= InstrCnt) Do
  1934. Begin
  1935. Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
  1936. Inc(Cnt)
  1937. End
  1938. End;
  1939. End
  1940. { Else }
  1941. {instruction prior to label is a jmp and no jumps to the label have yet been
  1942. processed}
  1943. { Begin
  1944. Inc(JmpsProcessed);
  1945. For TmpReg := R_EAX to R_EDI Do
  1946. Begin
  1947. TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
  1948. Cnt := InstrNr;
  1949. While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
  1950. Begin
  1951. PaiPropBlock^[Cnt].Regs[TmpReg] := CurProp^.Regs[TmpReg];
  1952. Inc(Cnt);
  1953. End;
  1954. TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
  1955. While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
  1956. Begin
  1957. DestroyReg(@PaiPropBlock^[Cnt], TmpReg, true);
  1958. Inc(Cnt);
  1959. End;
  1960. While (Cnt <= InstrCnt) Do
  1961. Begin
  1962. Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
  1963. Inc(Cnt)
  1964. End
  1965. End
  1966. End}
  1967. {$endif AnalyzeLoops}
  1968. End;
  1969. {$EndIf JumpAnal}
  1970. end
  1971. else
  1972. begin
  1973. InstrProp := InsProp[Paicpu(p)^.opcode];
  1974. Case Paicpu(p)^.opcode Of
  1975. A_MOV, A_MOVZX, A_MOVSX:
  1976. Begin
  1977. Case Paicpu(p)^.oper[0].typ Of
  1978. top_ref, top_reg:
  1979. case paicpu(p)^.oper[1].typ Of
  1980. top_reg:
  1981. Begin
  1982. {$ifdef statedebug}
  1983. hp := new(pai_asm_comment,init(strpnew('destroying '+
  1984. att_reg2str[Paicpu(p)^.oper[1].reg])));
  1985. insertllitem(asml,p,p^.next,hp);
  1986. {$endif statedebug}
  1987. readOp(curprop, paicpu(p)^.oper[0]);
  1988. tmpreg := reg32(paicpu(p)^.oper[1].reg);
  1989. if regInOp(tmpreg, paicpu(p)^.oper[0]) and
  1990. (curProp^.regs[tmpReg].typ in [con_ref,con_noRemoveRef]) then
  1991. begin
  1992. with curprop^.regs[tmpreg] Do
  1993. begin
  1994. incState(wstate,1);
  1995. { also store how many instructions are part of the sequence in the first }
  1996. { instruction's PPaiProp, so it can be easily accessed from within }
  1997. { CheckSequence }
  1998. inc(nrOfMods, nrOfInstrSinceLastMod[tmpreg]);
  1999. ppaiprop(startmod^.optinfo)^.regs[tmpreg].nrOfMods := nrOfMods;
  2000. nrOfInstrSinceLastMod[tmpreg] := 0;
  2001. { Destroy the contents of the registers }
  2002. { that depended on the previous value of }
  2003. { this register }
  2004. invalidateDependingRegs(curprop,tmpreg);
  2005. end;
  2006. end
  2007. else
  2008. begin
  2009. {$ifdef statedebug}
  2010. hp := new(pai_asm_comment,init(strpnew('destroying & initing '+att_reg2str[tmpreg])));
  2011. insertllitem(asml,p,p^.next,hp);
  2012. {$endif statedebug}
  2013. destroyReg(curprop, tmpreg, true);
  2014. if not(reginop(tmpreg, paicpu(p)^.oper[0])) then
  2015. with curprop^.regs[tmpreg] Do
  2016. begin
  2017. typ := con_ref;
  2018. startmod := p;
  2019. nrOfMods := 1;
  2020. end
  2021. end;
  2022. {$ifdef StateDebug}
  2023. hp := new(pai_asm_comment,init(strpnew(att_reg2str[TmpReg]+': '+tostr(CurProp^.Regs[TmpReg].WState))));
  2024. InsertLLItem(AsmL, p, p^.next, hp);
  2025. {$endif StateDebug}
  2026. End;
  2027. Top_Ref:
  2028. { can only be if oper[0] = top_reg }
  2029. Begin
  2030. ReadReg(CurProp, Paicpu(p)^.oper[0].reg);
  2031. ReadRef(CurProp, Paicpu(p)^.oper[1].ref);
  2032. DestroyRefs(p, Paicpu(p)^.oper[1].ref^, Paicpu(p)^.oper[0].reg);
  2033. End;
  2034. End;
  2035. top_symbol,Top_Const:
  2036. Begin
  2037. Case Paicpu(p)^.oper[1].typ Of
  2038. Top_Reg:
  2039. Begin
  2040. TmpReg := Reg32(Paicpu(p)^.oper[1].reg);
  2041. {$ifdef statedebug}
  2042. hp := new(pai_asm_comment,init(strpnew('destroying '+att_reg2str[tmpreg])));
  2043. insertllitem(asml,p,p^.next,hp);
  2044. {$endif statedebug}
  2045. With CurProp^.Regs[TmpReg] Do
  2046. Begin
  2047. DestroyReg(CurProp, TmpReg, true);
  2048. typ := Con_Const;
  2049. StartMod := p;
  2050. End
  2051. End;
  2052. Top_Ref:
  2053. Begin
  2054. ReadRef(CurProp, Paicpu(p)^.oper[1].ref);
  2055. DestroyRefs(P, Paicpu(p)^.oper[1].ref^, R_NO);
  2056. End;
  2057. End;
  2058. End;
  2059. End;
  2060. End;
  2061. A_DIV, A_IDIV, A_MUL:
  2062. Begin
  2063. ReadOp(Curprop, Paicpu(p)^.oper[0]);
  2064. ReadReg(CurProp,R_EAX);
  2065. If (Paicpu(p)^.OpCode = A_IDIV) or
  2066. (Paicpu(p)^.OpCode = A_DIV) Then
  2067. ReadReg(CurProp,R_EDX);
  2068. {$ifdef statedebug}
  2069. hp := new(pai_asm_comment,init(strpnew('destroying eax and edx')));
  2070. insertllitem(asml,p,p^.next,hp);
  2071. {$endif statedebug}
  2072. DestroyReg(CurProp, R_EAX, true);
  2073. DestroyReg(CurProp, R_EDX, true)
  2074. End;
  2075. A_IMUL:
  2076. Begin
  2077. ReadOp(CurProp,Paicpu(p)^.oper[0]);
  2078. ReadOp(CurProp,Paicpu(p)^.oper[1]);
  2079. If (Paicpu(p)^.oper[2].typ = top_none) Then
  2080. If (Paicpu(p)^.oper[1].typ = top_none) Then
  2081. Begin
  2082. ReadReg(CurProp,R_EAX);
  2083. {$ifdef statedebug}
  2084. hp := new(pai_asm_comment,init(strpnew('destroying eax and edx')));
  2085. insertllitem(asml,p,p^.next,hp);
  2086. {$endif statedebug}
  2087. DestroyReg(CurProp, R_EAX, true);
  2088. DestroyReg(CurProp, R_EDX, true)
  2089. End
  2090. Else
  2091. AddInstr2OpContents(
  2092. {$ifdef statedebug}asml,{$endif}
  2093. Paicpu(p), Paicpu(p)^.oper[1])
  2094. Else
  2095. AddInstr2OpContents({$ifdef statedebug}asml,{$endif}
  2096. Paicpu(p), Paicpu(p)^.oper[2]);
  2097. End;
  2098. A_LEA:
  2099. begin
  2100. readop(curprop,paicpu(p)^.oper[0]);
  2101. if reginref(paicpu(p)^.oper[1].reg,paicpu(p)^.oper[0].ref^) then
  2102. AddInstr2RegContents({$ifdef statedebug}asml,{$endif}
  2103. paicpu(p), paicpu(p)^.oper[1].reg)
  2104. else
  2105. begin
  2106. {$ifdef statedebug}
  2107. hp := new(pai_asm_comment,init(strpnew('destroying '+
  2108. att_reg2str[paicpu(p)^.oper[1].reg])));
  2109. insertllitem(asml,p,p^.next,hp);
  2110. {$endif statedebug}
  2111. destroyreg(curprop,paicpu(p)^.oper[1].reg,true);
  2112. end;
  2113. end;
  2114. Else
  2115. Begin
  2116. Cnt := 1;
  2117. While (Cnt <= MaxCh) And
  2118. (InstrProp.Ch[Cnt] <> Ch_None) Do
  2119. Begin
  2120. Case InstrProp.Ch[Cnt] Of
  2121. Ch_REAX..Ch_REDI: ReadReg(CurProp,TCh2Reg(InstrProp.Ch[Cnt]));
  2122. Ch_WEAX..Ch_RWEDI:
  2123. Begin
  2124. If (InstrProp.Ch[Cnt] >= Ch_RWEAX) Then
  2125. ReadReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
  2126. {$ifdef statedebug}
  2127. hp := new(pai_asm_comment,init(strpnew('destroying '+
  2128. att_reg2str[TCh2Reg(InstrProp.Ch[Cnt])])));
  2129. insertllitem(asml,p,p^.next,hp);
  2130. {$endif statedebug}
  2131. DestroyReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]), true);
  2132. End;
  2133. Ch_MEAX..Ch_MEDI:
  2134. AddInstr2RegContents({$ifdef statedebug} asml,{$endif}
  2135. Paicpu(p),TCh2Reg(InstrProp.Ch[Cnt]));
  2136. Ch_CDirFlag: CurProp^.DirFlag := F_NotSet;
  2137. Ch_SDirFlag: CurProp^.DirFlag := F_Set;
  2138. Ch_Rop1: ReadOp(CurProp, Paicpu(p)^.oper[0]);
  2139. Ch_Rop2: ReadOp(CurProp, Paicpu(p)^.oper[1]);
  2140. Ch_ROp3: ReadOp(CurProp, Paicpu(p)^.oper[2]);
  2141. Ch_Wop1..Ch_RWop1:
  2142. Begin
  2143. If (InstrProp.Ch[Cnt] in [Ch_RWop1]) Then
  2144. ReadOp(CurProp, Paicpu(p)^.oper[0]);
  2145. DestroyOp(p, Paicpu(p)^.oper[0]);
  2146. End;
  2147. Ch_Mop1:
  2148. AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
  2149. Paicpu(p), Paicpu(p)^.oper[0]);
  2150. Ch_Wop2..Ch_RWop2:
  2151. Begin
  2152. If (InstrProp.Ch[Cnt] = Ch_RWop2) Then
  2153. ReadOp(CurProp, Paicpu(p)^.oper[1]);
  2154. DestroyOp(p, Paicpu(p)^.oper[1]);
  2155. End;
  2156. Ch_Mop2:
  2157. AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
  2158. Paicpu(p), Paicpu(p)^.oper[1]);
  2159. Ch_WOp3..Ch_RWOp3:
  2160. Begin
  2161. If (InstrProp.Ch[Cnt] = Ch_RWOp3) Then
  2162. ReadOp(CurProp, Paicpu(p)^.oper[2]);
  2163. DestroyOp(p, Paicpu(p)^.oper[2]);
  2164. End;
  2165. Ch_Mop3:
  2166. AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
  2167. Paicpu(p), Paicpu(p)^.oper[2]);
  2168. Ch_WMemEDI:
  2169. Begin
  2170. ReadReg(CurProp, R_EDI);
  2171. FillChar(TmpRef, SizeOf(TmpRef), 0);
  2172. TmpRef.Base := R_EDI;
  2173. tmpRef.index := R_EDI;
  2174. DestroyRefs(p, TmpRef, R_NO)
  2175. End;
  2176. Ch_RFlags, Ch_WFlags, Ch_RWFlags, Ch_FPU:
  2177. Else
  2178. Begin
  2179. {$ifdef statedebug}
  2180. hp := new(pai_asm_comment,init(strpnew(
  2181. 'destroying all regs for prev instruction')));
  2182. insertllitem(asml,p, p^.next,hp);
  2183. {$endif statedebug}
  2184. DestroyAllRegs(CurProp);
  2185. End;
  2186. End;
  2187. Inc(Cnt);
  2188. End
  2189. End;
  2190. end;
  2191. End;
  2192. End
  2193. Else
  2194. Begin
  2195. {$ifdef statedebug}
  2196. hp := new(pai_asm_comment,init(strpnew(
  2197. 'destroying all regs: unknown pai: '+tostr(ord(p^.typ)))));
  2198. insertllitem(asml,p, p^.next,hp);
  2199. {$endif statedebug}
  2200. DestroyAllRegs(CurProp);
  2201. End;
  2202. End;
  2203. Inc(InstrCnt);
  2204. GetNextInstruction(p, p);
  2205. End;
  2206. End;
  2207. Function InitDFAPass2(BlockStart, BlockEnd: Pai): Boolean;
  2208. {reserves memory for the PPaiProps in one big memory block when not using
  2209. TP, returns False if not enough memory is available for the optimizer in all
  2210. cases}
  2211. Var p: Pai;
  2212. Count: Longint;
  2213. { TmpStr: String; }
  2214. Begin
  2215. P := BlockStart;
  2216. SkipHead(P);
  2217. NrOfPaiObjs := 0;
  2218. While (P <> BlockEnd) Do
  2219. Begin
  2220. {$IfDef JumpAnal}
  2221. Case P^.Typ Of
  2222. ait_label:
  2223. Begin
  2224. If not labelCanBeSkipped(pai_label(p)) Then
  2225. LTable^[Pai_Label(P)^.l^.labelnr-LoLab].InstrNr := NrOfPaiObjs
  2226. End;
  2227. ait_instruction:
  2228. begin
  2229. if paicpu(p)^.is_jmp then
  2230. begin
  2231. If (pasmlabel(paicpu(P)^.oper[0].sym)^.labelnr >= LoLab) And
  2232. (pasmlabel(paicpu(P)^.oper[0].sym)^.labelnr <= HiLab) Then
  2233. Inc(LTable^[pasmlabel(paicpu(P)^.oper[0].sym)^.labelnr-LoLab].RefsFound);
  2234. end;
  2235. end;
  2236. { ait_instruction:
  2237. Begin
  2238. If (Paicpu(p)^.opcode = A_PUSH) And
  2239. (Paicpu(p)^.oper[0].typ = top_symbol) And
  2240. (PCSymbol(Paicpu(p)^.oper[0])^.offset = 0) Then
  2241. Begin
  2242. TmpStr := StrPas(PCSymbol(Paicpu(p)^.oper[0])^.symbol);
  2243. If}
  2244. End;
  2245. {$EndIf JumpAnal}
  2246. Inc(NrOfPaiObjs);
  2247. GetNextInstruction(p, p);
  2248. End;
  2249. {Uncomment the next line to see how much memory the reloading optimizer needs}
  2250. { Writeln(NrOfPaiObjs*SizeOf(TPaiProp));}
  2251. {no need to check mem/maxavail, we've got as much virtual memory as we want}
  2252. If NrOfPaiObjs <> 0 Then
  2253. Begin
  2254. InitDFAPass2 := True;
  2255. GetMem(PaiPropBlock, NrOfPaiObjs*SizeOf(TPaiProp));
  2256. p := BlockStart;
  2257. SkipHead(p);
  2258. For Count := 1 To NrOfPaiObjs Do
  2259. Begin
  2260. PPaiProp(p^.OptInfo) := @PaiPropBlock^[Count];
  2261. GetNextInstruction(p, p);
  2262. End;
  2263. End
  2264. Else InitDFAPass2 := False;
  2265. End;
  2266. Function DFAPass2(
  2267. {$ifdef statedebug}
  2268. AsmL: PAasmOutPut;
  2269. {$endif statedebug}
  2270. BlockStart, BlockEnd: Pai): Boolean;
  2271. Begin
  2272. If InitDFAPass2(BlockStart, BlockEnd) Then
  2273. Begin
  2274. DoDFAPass2(
  2275. {$ifdef statedebug}
  2276. asml,
  2277. {$endif statedebug}
  2278. BlockStart, BlockEnd);
  2279. DFAPass2 := True
  2280. End
  2281. Else DFAPass2 := False;
  2282. End;
  2283. Procedure ShutDownDFA;
  2284. Begin
  2285. If LabDif <> 0 Then
  2286. FreeMem(LTable, LabDif*SizeOf(TLabelTableItem));
  2287. End;
  2288. End.
  2289. {
  2290. $Log$
  2291. Revision 1.5 2000-11-08 16:04:34 sg
  2292. * Fix for containsPointerRef: Loop now runs in the correct range
  2293. Revision 1.4 2000/11/03 18:06:26 jonas
  2294. * fixed bug in arrayRefsEq
  2295. * object/class fields are now handled the same as local/global vars and
  2296. parameters (ie. a write to a local var can now never destroy a class
  2297. field)
  2298. Revision 1.3 2000/10/24 10:40:53 jonas
  2299. + register renaming ("fixes" bug1088)
  2300. * changed command line options meanings for optimizer:
  2301. O2 now means peepholopts, CSE and register renaming in 1 pass
  2302. O3 is the same, but repeated until no further optimizations are
  2303. possible or until 5 passes have been done (to avoid endless loops)
  2304. * changed aopt386 so it does this looping
  2305. * added some procedures from csopt386 to the interface because they're
  2306. used by rropt386 as well
  2307. * some changes to csopt386 and daopt386 so that newly added instructions
  2308. by the CSE get optimizer info (they were simply skipped previously),
  2309. this fixes some bugs
  2310. Revision 1.2 2000/10/19 15:59:40 jonas
  2311. * fixed bug in allocregbetween (the register wasn't added to the
  2312. usedregs set of the last instruction of the chain) ("merged")
  2313. Revision 1.1 2000/10/15 09:47:43 peter
  2314. * moved to i386/
  2315. Revision 1.16 2000/10/14 10:14:47 peter
  2316. * moehrendorf oct 2000 rewrite
  2317. Revision 1.15 2000/09/30 13:07:23 jonas
  2318. * fixed support for -Or with new features of CSE
  2319. Revision 1.14 2000/09/29 23:14:11 jonas
  2320. + writeToMemDestroysContents() and writeDestroysContents() to support the
  2321. new features of the CSE
  2322. Revision 1.13 2000/09/25 09:50:30 jonas
  2323. - removed TP conditional code
  2324. Revision 1.12 2000/09/24 21:19:50 peter
  2325. * delphi compile fixes
  2326. Revision 1.11 2000/09/24 15:06:15 peter
  2327. * use defines.inc
  2328. Revision 1.10 2000/09/22 15:00:20 jonas
  2329. * fixed bug in regsEquivalent (in some rare cases, registers with
  2330. completely unrelated content were considered equivalent) (merged
  2331. from fixes branch)
  2332. Revision 1.9 2000/09/20 15:00:58 jonas
  2333. + much improved CSE: the CSE now searches further back for sequences it
  2334. can reuse. After I've also implemented register renaming, the effect
  2335. should be even better (afaik web bug 1088 will then even be optimized
  2336. properly). I don't know about the slow down factor this adds. Maybe
  2337. a new optimization level should be introduced?
  2338. Revision 1.8 2000/08/25 19:39:18 jonas
  2339. * bugfix to FindRegAlloc function (caused wrong regalloc info in
  2340. some cases) (merged from fixes branch)
  2341. Revision 1.7 2000/08/23 12:55:10 jonas
  2342. * fix for web bug 1112 and a bit of clean up in csopt386 (merged from
  2343. fixes branch)
  2344. Revision 1.6 2000/08/19 17:53:29 jonas
  2345. * fixed a potential bug in destroyregs regarding the removal of
  2346. unused loads
  2347. * added destroyDependingRegs() procedure and use it for the fix in
  2348. the previous commit (safer/more complete than what was done before)
  2349. Revision 1.5 2000/08/19 09:08:59 jonas
  2350. * fixed bug where the contents of a register would not be destroyed
  2351. if another register on which these contents depend is modified
  2352. (not really merged, but same idea as fix in fixes branch,
  2353. LAST_MERGE tag is updated)
  2354. Revision 1.4 2000/07/21 15:19:54 jonas
  2355. * daopt386: changes to getnextinstruction/getlastinstruction so they
  2356. ignore labels who have is_addr set
  2357. + daopt386/csopt386: remove loads of registers which are overwritten
  2358. before their contents are used (especially usefull for removing superfluous
  2359. maybe_loadesi outputs and push/pops transformed by below optimization
  2360. + popt386: transform pop/pop/pop/.../push/push/push to sequences of
  2361. 'movl x(%esp),%reg' (only active when compiling a go32v2 compiler
  2362. currently because I don't know whether it's safe to do this under Win32/
  2363. Linux (because of problems we had when using esp as frame pointer on
  2364. those os'es)
  2365. Revision 1.3 2000/07/14 05:11:48 michael
  2366. + Patch to 1.1
  2367. Revision 1.2 2000/07/13 11:32:40 michael
  2368. + removed logs
  2369. }