csopt386.pas 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Jonas Maebe, member of the Free Pascal
  4. development team
  5. This unit contains the common subexpression elimination procedure.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. Unit CSOpt386;
  20. {$i defines.inc}
  21. Interface
  22. Uses aasm, cpubase, cpuasm;
  23. function CSE(asmL: TAAsmoutput; first, last: Tai; pass: longint): boolean;
  24. function doReplaceReg(hp: Taicpu; newReg, orgReg: tregister): boolean;
  25. function changeOp(var o: toper; newReg, orgReg: tregister): boolean;
  26. function storeBack(p1: Tai; orgReg, newReg: tregister): boolean;
  27. function NoHardCodedRegs(p: Taicpu; orgReg, newReg: TRegister): boolean;
  28. function RegSizesOK(oldReg,newReg: TRegister; p: Taicpu): boolean;
  29. Implementation
  30. Uses
  31. {$ifdef replaceregdebug}cutils,{$endif}
  32. globtype, verbose, cgbase, globals, daopt386, tgcpu, rropt386;
  33. {
  34. Function TaiInSequence(P: Tai; Const Seq: TContent): Boolean;
  35. Var P1: Tai;
  36. Counter: Byte;
  37. TmpResult: Boolean;
  38. Begin
  39. TmpResult := False;
  40. P1 := Seq.StartMod;
  41. Counter := 1;
  42. While Not(TmpResult) And
  43. (Counter <= Seq.NrOfMods) Do
  44. Begin
  45. If (P = P1) Then TmpResult := True;
  46. Inc(Counter);
  47. p1 := Tai(p1.Next);
  48. End;
  49. TaiInSequence := TmpResult;
  50. End;
  51. }
  52. function modifiesConflictingMemLocation(p1: Tai; reg: tregister; c: tregContent;
  53. var regsStillValid: tregset): boolean;
  54. var
  55. p, hp: Taicpu;
  56. tmpRef: treference;
  57. regCounter: tregister;
  58. opCount: byte;
  59. dummy: boolean;
  60. begin
  61. modifiesConflictingMemLocation := false;
  62. if p1.typ <> ait_instruction then
  63. exit;
  64. p := Taicpu(p1);
  65. case p.opcode of
  66. A_MOV,A_MOVSX,A_MOVZX:
  67. if p.oper[1].typ = top_ref then
  68. for regCounter := R_EAX to R_EDI do
  69. begin
  70. if writeToMemDestroysContents(reg32(p.oper[0].reg),p.oper[1].ref^,
  71. regCounter,c[regCounter],dummy) then
  72. begin
  73. exclude(regsStillValid,regCounter);
  74. modifiesConflictingMemLocation := not(reg in regsStillValid);
  75. end;
  76. end
  77. else
  78. { if is_reg_var[reg32(p.oper[1].reg)] then }
  79. for regCounter := R_EAX to R_EDI do
  80. begin
  81. if writeDestroysContents(p.oper[1],regCounter,c[regCounter]) then
  82. begin
  83. exclude(regsStillValid,regCounter);
  84. modifiesConflictingMemLocation := not(reg in regsStillValid);
  85. end
  86. end;
  87. A_DIV, A_IDIV, A_MUL, A_IMUL:
  88. begin
  89. if (p.ops = 1) then
  90. begin
  91. if is_reg_var[R_EDX] and
  92. (not getNextInstruction(p,hp) or
  93. not((hp.typ = ait_instruction) and
  94. (hp.opcode = A_MOV) and
  95. (hp.oper[0].typ = top_reg) and
  96. (reg32(hp.oper[0].reg) = R_EDX) and
  97. getNextInstruction(hp,hp) and
  98. (hp.typ = ait_instruction) and
  99. (hp.opcode = A_POP) and
  100. (hp.oper[0].reg = R_EDX))) then
  101. for regCounter := R_EAX to R_EDI do
  102. if writeToRegDestroysContents(R_EDX,regCounter,c[regCounter]) then
  103. begin
  104. exclude(regsStillValid,R_EDX);
  105. modifiesConflictingMemLocation := not(reg in regsStillValid);
  106. end
  107. end
  108. else
  109. { only possible for imul }
  110. { last operand is always destination }
  111. if is_reg_var[reg32(p.oper[p.ops-1].reg)] then
  112. for regCounter := R_EAX to R_EDI do
  113. begin
  114. if writeDestroysContents(p.oper[p.ops-1],regCounter,c[regCounter]) then
  115. begin
  116. exclude(regsStillValid,regCounter);
  117. modifiesConflictingMemLocation := not(reg in regsStillValid);
  118. end
  119. end
  120. end;
  121. else
  122. for opCount := 1 to MaxCh do
  123. case InsProp[p.opcode].Ch[opCount] of
  124. Ch_MOp1,CH_WOp1,CH_RWOp1:
  125. { if (p.oper[0].typ = top_ref) or }
  126. { ((p.oper[0].typ = top_reg) and }
  127. { is_reg_var[reg32(p.oper[0].reg)]) then }
  128. for regCounter := R_EAX to R_EDI do
  129. if writeDestroysContents(p.oper[0],regCounter,c[regCounter]) then
  130. begin
  131. exclude(regsStillValid,regCounter);
  132. modifiesConflictingMemLocation := not(reg in regsStillValid);
  133. end;
  134. Ch_MOp2,CH_WOp2,CH_RWOp2:
  135. { if (p.oper[1].typ = top_ref) or }
  136. { ((p.oper[1].typ = top_reg) and }
  137. { is_reg_var[reg32(p.oper[1].reg)]) then }
  138. for regCounter := R_EAX to R_EDI do
  139. if writeDestroysContents(p.oper[1],regCounter,c[regCounter]) then
  140. begin
  141. exclude(regsStillValid,regCounter);
  142. modifiesConflictingMemLocation := not(reg in regsStillValid);
  143. end;
  144. Ch_MOp3,CH_WOp3,CH_RWOp3:
  145. { if (p.oper[2].typ = top_ref) or }
  146. { ((p.oper[2].typ = top_reg) and }
  147. { is_reg_var[reg32(p.oper[2].reg)]) then }
  148. for regCounter := R_EAX to R_EDI do
  149. if writeDestroysContents(p.oper[2],regCounter,c[regCounter]) then
  150. begin
  151. exclude(regsStillValid,regCounter);
  152. modifiesConflictingMemLocation := not(reg in regsStillValid);
  153. end;
  154. Ch_WMemEDI:
  155. begin
  156. fillchar(tmpref,sizeof(tmpref),0);
  157. tmpRef.base := R_EDI;
  158. tmpRef.index := R_EDI;
  159. for regCounter := R_EAX to R_EDI do
  160. if writeToMemDestroysContents(R_NO,tmpRef,regCounter,c[regCounter],dummy) then
  161. begin
  162. exclude(regsStillValid,regCounter);
  163. modifiesConflictingMemLocation := not(reg in regsStillValid);
  164. end;
  165. end;
  166. end;
  167. end;
  168. end;
  169. function isSimpleMemLoc(const ref: treference): boolean;
  170. begin
  171. isSimpleMemLoc :=
  172. (ref.index = R_NO) and
  173. not(ref.base in (usableregs+[R_EDI]));
  174. end;
  175. {checks whether the current instruction sequence (starting with p) and the
  176. one between StartMod and EndMod of Reg are the same. If so, the number of
  177. instructions that match is stored in Found and true is returned, otherwise
  178. Found holds the number of instructions between StartMod and EndMod and false
  179. is returned}
  180. Function CheckSequence(p: Tai; var prev: Tai; Reg: TRegister; Var Found: Longint;
  181. Var RegInfo: TRegInfo; findPrevSeqs: boolean): Boolean;
  182. var
  183. regsNotRead, regsStillValid : tregset;
  184. checkingPrevSequences,
  185. passedFlagsModifyingInstr,
  186. passedJump : boolean;
  187. function getPrevSequence(p: Tai; reg: tregister; currentPrev: Tai; var newPrev: Tai): tregister;
  188. const
  189. current_reg: tregister = R_NO;
  190. function stillValid(p: Tai): boolean;
  191. begin
  192. stillValid :=
  193. (p.typ = ait_instruction) and
  194. (Taicpu(p).opcode <> a_jmp) and
  195. (pTaiprop(p.optinfo)^.regs[reg].wstate =
  196. pTaiprop(currentPrev.optinfo)^.regs[reg].wstate) and
  197. { in case destroyreg is called with doIncState = false }
  198. (pTaiprop(p.optinfo)^.regs[reg].typ =
  199. pTaiprop(currentPrev.optinfo)^.regs[reg].typ) and
  200. (reg in (regsNotRead * regsStillValid));
  201. passedJump :=
  202. (p.typ = ait_instruction) and
  203. (Taicpu(p).is_jmp);
  204. passedFlagsModifyingInstr :=
  205. instrWritesFlags(currentPrev);
  206. end;
  207. function findChangedRegister(p: Tai): tregister;
  208. var
  209. regCounter: tregister;
  210. begin
  211. for regCounter := succ(current_reg) to R_EDI do
  212. with pTaiprop(p.optinfo)^.regs[regCounter] do
  213. if ((startmod <>
  214. pTaiprop(currentPrev.optinfo)^.regs[regCounter].startmod) or
  215. (nrOfMods <>
  216. pTaiprop(currentPrev.optinfo)^.regs[regCounter].nrOfMods)) and
  217. (pTaiprop(p.optinfo)^.regs[regCounter].typ in
  218. [con_ref,con_noRemoveRef]) then
  219. begin
  220. findChangedRegister := regCounter;
  221. current_reg := regCounter;
  222. exit;
  223. end;
  224. current_reg := R_NO;
  225. findChangedRegister := R_NO;
  226. end;
  227. var
  228. hp, prevFound: Tai;
  229. tmpResult, regCounter: tregister;
  230. begin
  231. if not(current_reg in [R_NO,R_EDI]) then
  232. begin
  233. tmpResult := findChangedRegister(currentPrev);
  234. if tmpResult <> R_NO then
  235. begin
  236. getPrevSequence := tmpResult;
  237. exit;
  238. end;
  239. end;
  240. getPrevSequence := R_NO;
  241. passedJump := passedJump or
  242. ((currentPrev.typ = ait_instruction) and
  243. (Taicpu(currentPrev).is_jmp));
  244. passedFlagsModifyingInstr := instrWritesFlags(currentPrev);
  245. if (passedJump and not(reg in (usableregs+[R_EDI]))) or
  246. not getLastInstruction(currentPrev,hp) then
  247. exit;
  248. prevFound := currentPrev;
  249. tmpResult := R_NO;
  250. while (tmpResult = R_NO) and
  251. stillValid(hp) and
  252. (pTaiprop(prevFound.optinfo)^.canBeRemoved or
  253. not(modifiesConflictingMemLocation(prevFound,reg,
  254. pTaiprop(p.optinfo)^.regs,regsStillValid))) do
  255. begin
  256. { only update the regsread for the instructions we already passed }
  257. if not(pTaiprop(prevFound.optinfo)^.canBeRemoved) then
  258. for regCounter := R_EAX to R_EDI do
  259. if regReadByInstruction(regCounter,prevFound) then
  260. exclude(regsNotRead,regCounter);
  261. { in case getPreviousInstruction fails and sets hp to nil in the }
  262. { next iteration }
  263. prevFound := hp;
  264. if not(pTaiprop(hp.optinfo)^.canBeRemoved) then
  265. tmpResult := findChangedRegister(hp);
  266. if { do not load the self pointer or a regvar before a (conditional) }
  267. { jump with a new value, since if the jump is taken, the old value }
  268. { is (probably) still necessary }
  269. (passedJump and not(reg in (usableregs+[R_EDI]))) or
  270. not getLastInstruction(hp,hp) then
  271. break;
  272. end;
  273. getPrevSequence := tmpResult;
  274. if tmpResult <> R_NO then
  275. newPrev := prevFound;
  276. end;
  277. function getNextRegToTest(var prev: Tai; currentReg: tregister): tregister;
  278. begin
  279. if not checkingPrevSequences then
  280. begin
  281. Repeat
  282. Inc(currentReg);
  283. Until (currentReg > R_EDI) or
  284. (pTaiprop(prev.optInfo)^.regs[currentReg].typ
  285. in [con_ref,con_noRemoveRef]);
  286. if currentReg > R_EDI then
  287. begin
  288. if (Taicpu(p).oper[0].typ <> top_ref) or
  289. isSimpleMemLoc(Taicpu(p).oper[0].ref^) then
  290. begin
  291. checkingPrevSequences := true;
  292. passedJump := false;
  293. end
  294. else
  295. getNextRegToTest := R_NO;
  296. end
  297. else getNextRegToTest := currentReg;
  298. end;
  299. if checkingPrevSequences then
  300. if findPrevSeqs then
  301. getNextRegToTest :=
  302. getPrevSequence(p,reg,prev,prev)
  303. else
  304. getNextRegToTest := R_NO;
  305. end;
  306. Var hp2, hp3{, EndMod},highPrev, orgPrev: Tai;
  307. {Cnt,} OldNrOfMods: Longint;
  308. startRegInfo, OrgRegInfo, HighRegInfo: TRegInfo;
  309. regModified: array[R_NO..R_EDI] of boolean;
  310. HighFound, OrgRegFound: Byte;
  311. RegCounter, regCounter2, tmpreg, base, index: TRegister;
  312. OrgRegResult: Boolean;
  313. TmpResult, flagResultsNeeded: Boolean;
  314. Begin {CheckSequence}
  315. Reg := Reg32(Reg);
  316. TmpResult := False;
  317. FillChar(OrgRegInfo, SizeOf(OrgRegInfo), 0);
  318. FillChar(startRegInfo, sizeof(startRegInfo), 0);
  319. OrgRegFound := 0;
  320. HighFound := 0;
  321. OrgRegResult := False;
  322. with startRegInfo do
  323. begin
  324. newRegsEncountered := [procinfo^.FramePointer, stack_pointer];
  325. new2OldReg[procinfo^.FramePointer] := procinfo^.FramePointer;
  326. new2OldReg[stack_pointer] := stack_pointer;
  327. oldRegsEncountered := newRegsEncountered;
  328. end;
  329. checkingPrevSequences := false;
  330. passedFlagsModifyingInstr := false;
  331. flagResultsNeeded := false;
  332. regsNotRead := [R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,R_EDI,R_ESI];
  333. regsStillValid := regsNotRead;
  334. GetLastInstruction(p, prev);
  335. regCounter := getNextRegToTest(prev,R_NO);
  336. While (RegCounter <> R_NO) Do
  337. Begin
  338. fillchar(regModified,sizeof(regModified),0);
  339. regInfo := startRegInfo;
  340. Found := 0;
  341. hp2 := PTaiProp(prev.OptInfo)^.Regs[RegCounter].StartMod;
  342. If (prev <> PTaiProp(prev.OptInfo)^.Regs[RegCounter].StartMod)
  343. Then OldNrOfMods := PTaiProp(prev.OptInfo)^.Regs[RegCounter].NrOfMods
  344. Else OldNrOfMods := 1;
  345. hp3 := p;
  346. While (Found <> OldNrOfMods) And
  347. { old new }
  348. InstructionsEquivalent(hp2, hp3, RegInfo) Do
  349. Begin
  350. if not checkingPrevSequences and
  351. (hp3.typ = ait_instruction) and
  352. ((Taicpu(hp3).opcode = A_MOV) or
  353. (Taicpu(hp3).opcode = A_MOVZX) or
  354. (Taicpu(hp3).opcode = A_LEA) or
  355. (Taicpu(hp3).opcode = A_MOVSX)) and
  356. (Taicpu(hp3).oper[1].typ = top_reg) and
  357. not(regInOp(Taicpu(hp3).oper[1].reg,
  358. Taicpu(hp3).oper[0])) then
  359. begin
  360. tmpreg := reg32(Taicpu(hp3).oper[1].reg);
  361. regInfo.lastReload[tmpreg] := hp3;
  362. case Taicpu(hp3).oper[0].typ of
  363. top_ref:
  364. begin
  365. base := reg32(Taicpu(hp3).oper[0].ref^.base);
  366. index := reg32(Taicpu(hp3).oper[0].ref^.index);
  367. if (found <> 0) and
  368. ((base = R_NO) or
  369. regModified[base] or
  370. (base = procinfo^.framepointer) or
  371. (assigned(procinfo^._class) and (base = R_ESI))) and
  372. ((index = R_NO) or
  373. regModified[index] or
  374. (assigned(procinfo^._class) and (index = R_ESI))) and
  375. not(regInRef(tmpReg,Taicpu(hp3).oper[0].ref^)) then
  376. with pTaiprop(hp3.optinfo)^.regs[tmpreg] do
  377. if nrOfMods > (oldNrOfMods - found) then
  378. oldNrOfMods := found + nrOfMods;
  379. end;
  380. top_reg:
  381. if regModified[reg32(Taicpu(hp3).oper[0].reg)] then
  382. with pTaiprop(hp3.optinfo)^.regs[tmpreg] do
  383. if nrOfMods > (oldNrOfMods - found) then
  384. oldNrOfMods := found + nrOfMods;
  385. end;
  386. end;
  387. for regCounter2 := R_EAX to R_EDI do
  388. regModified[regCounter2] := regModified[regCounter2] or
  389. regModifiedByInstruction(regCounter2,hp3);
  390. if flagResultsNeeded then
  391. flagResultsNeeded := not instrReadsFlags(hp3);
  392. if not flagResultsNeeded then
  393. flagResultsNeeded := pTaiprop(hp3.optinfo)^.FlagsUsed;
  394. GetNextInstruction(hp2, hp2);
  395. GetNextInstruction(hp3, hp3);
  396. Inc(Found);
  397. End;
  398. for regCounter2 := R_EAX to R_EDI do
  399. if (regInfo.new2OldReg[regCounter2] <> R_NO) and
  400. (regCounter2 in PTaiProp(hp3.optInfo)^.usedRegs) and
  401. not regLoadedWithNewValue(regCounter2,false,hp3) then
  402. include(regInfo.regsStillUsedAfterSeq,regCounter2);
  403. if checkingPrevSequences then
  404. begin
  405. for regCounter2 := R_EAX to R_EDI do
  406. if not(regInfo.new2OldReg[regCounter2] in [R_NO,regCounter2]) and
  407. (not(regCounter2 in (regsNotRead * regsStillValid)) or
  408. not(regInfo.new2OldReg[regCounter2] in regsStillValid)) then
  409. begin
  410. found := 0;
  411. break;
  412. end;
  413. if passedFlagsModifyingInstr and flagResultsNeeded then
  414. found := 0;
  415. end;
  416. If (Found <> OldNrOfMods) or
  417. { the following is to avoid problems with rangecheck code (see testcse2) }
  418. (assigned(hp3) and
  419. ((reg in regInfo.regsLoadedForRef) and
  420. (reg in PTaiProp(hp3.optInfo)^.usedRegs) and
  421. not regLoadedWithNewValue(reg,false,hp3))) then
  422. Begin
  423. TmpResult := False;
  424. If (found > 0) then
  425. {this is correct because we only need to turn off the CanBeRemoved flag
  426. when an instruction has already been processed by CheckSequence
  427. (otherwise CanBeRemoved can't be true and thus can't have to be turned off).
  428. If it has already been processed by CheckSequence and flagged to be
  429. removed, it means that it has been checked against a previous sequence
  430. and that it was equal (otherwise CheckSequence would have returned false
  431. and the instruction wouldn't have been removed). If this "If found > 0"
  432. check is left out, incorrect optimizations are performed.}
  433. Found := PTaiProp(Tai(p).OptInfo)^.Regs[Reg].NrOfMods
  434. End
  435. Else TmpResult := True;
  436. If TmpResult And
  437. (Found > HighFound)
  438. Then
  439. Begin
  440. highPrev := prev;
  441. HighFound := Found;
  442. HighRegInfo := RegInfo;
  443. End;
  444. If (RegCounter = Reg) Then
  445. Begin
  446. orgPrev := prev;
  447. OrgRegFound := Found;
  448. OrgRegResult := TmpResult;
  449. OrgRegInfo := RegInfo
  450. End;
  451. regCounter := getNextRegToTest(prev,regCounter);
  452. End;
  453. If (HighFound > 0) And
  454. (Not(OrgRegResult) Or
  455. (HighFound > OrgRegFound))
  456. Then
  457. Begin
  458. {$ifndef fpc}
  459. TmpResult := True;
  460. {$else fpc}
  461. CheckSequence := True;
  462. {$endif fpc}
  463. prev := highPrev;
  464. RegInfo := HighRegInfo;
  465. Found := HighFound
  466. End
  467. Else
  468. Begin
  469. {$ifndef fpc}
  470. TmpResult := OrgRegResult;
  471. {$else fpc}
  472. CheckSequence := OrgRegResult;
  473. {$endif fpc}
  474. prev := orgPrev;
  475. Found := OrgRegFound;
  476. RegInfo := OrgRegInfo;
  477. End;
  478. {$ifndef fpc}
  479. CheckSequence := TmpResult;
  480. {$endif fpc}
  481. End; {CheckSequence}
  482. Procedure SetAlignReg(p: Tai);
  483. Const alignSearch = 12;
  484. var regsUsable: TRegSet;
  485. prevInstrCount, nextInstrCount: Longint;
  486. prevState, nextWState,nextRState: Array[R_EAX..R_EDI] of byte;
  487. regCounter, lastRemoved: TRegister;
  488. prev, next: Tai;
  489. {$ifdef alignregdebug}
  490. temp: Tai;
  491. {$endif alignregdebug}
  492. begin
  493. regsUsable := [R_EAX,R_ECX,R_EDX,R_EBX,{R_ESP,R_EBP,}R_ESI,R_EDI];
  494. for regCounter := R_EAX to R_EDI do
  495. begin
  496. prevState[regCounter] := PTaiProp(p.optInfo)^.Regs[regCounter].wState;
  497. nextWState[regCounter] := PTaiProp(p.optInfo)^.Regs[regCounter].wState;
  498. nextRState[regCounter] := PTaiProp(p.optInfo)^.Regs[regCounter].rState;
  499. end;
  500. getLastInstruction(p,prev);
  501. getNextInstruction(p,next);
  502. lastRemoved := Tai_align(p).reg;
  503. nextInstrCount := 0;
  504. prevInstrCount := 0;
  505. while ((assigned(prev) and
  506. assigned(prev.optInfo) and
  507. (prevInstrCount < alignSearch)) or
  508. (assigned(next) and
  509. assigned(next.optInfo) and
  510. (nextInstrCount < alignSearch))) And
  511. (regsUsable <> []) do
  512. begin
  513. {$ifdef alignregdebug}
  514. if assigned(prev) then
  515. begin
  516. temp := Tai_asm_comment.Create(strpnew('got here'));
  517. temp.next := prev.next;
  518. temp.previous := prev;
  519. prev.next := temp;
  520. if assigned(temp.next) then
  521. temp.next.previous := temp;
  522. end;
  523. {$endif alignregdebug}
  524. if assigned(prev) and assigned(prev.optinfo) and
  525. (prevInstrCount < alignSearch) then
  526. begin
  527. if (prev.typ = ait_instruction) And
  528. (insProp[TaiCpu(prev).opcode].ch[1] <> Ch_ALL) and
  529. (TaiCpu(prev).opcode <> A_JMP) then
  530. begin
  531. inc(prevInstrCount);
  532. for regCounter := R_EAX to R_EDI do
  533. begin
  534. if (regCounter in regsUsable) And
  535. (PTaiProp(prev.optInfo)^.Regs[regCounter].wState <>
  536. prevState[regCounter]) then
  537. begin
  538. lastRemoved := regCounter;
  539. exclude(regsUsable,regCounter);
  540. {$ifdef alignregdebug}
  541. temp := Tai_asm_comment.Create(strpnew(
  542. att_reg2str[regCounter]+' removed')));
  543. temp.next := prev.next;
  544. temp.previous := prev;
  545. prev.next := temp;
  546. if assigned(temp.next) then
  547. temp.next.previous := temp;
  548. if regsUsable = [] then
  549. begin
  550. temp := Tai_asm_comment.Create(strpnew(
  551. 'regsUsable empty here')));
  552. temp.next := prev.next;
  553. temp.previous := prev;
  554. prev.next := temp;
  555. if assigned(temp.next) then
  556. temp.next.previous := temp;
  557. end;
  558. {$endif alignregdebug}
  559. end;
  560. prevState[regCounter] :=
  561. PTaiProp(prev.optInfo)^.Regs[regCounter].wState;
  562. end;
  563. getLastInstruction(prev,prev);
  564. end
  565. else
  566. If GetLastInstruction(prev,prev) and
  567. assigned(prev.optinfo) then
  568. for regCounter := R_EAX to R_EDI do
  569. prevState[regCounter] :=
  570. PTaiProp(prev.optInfo)^.Regs[regCounter].wState
  571. end;
  572. if assigned(next) and assigned(next.optInfo) and
  573. (nextInstrCount < alignSearch) then
  574. begin
  575. if (next.typ = ait_instruction) and
  576. (insProp[TaiCpu(next).opcode].ch[1] <> Ch_ALL) and
  577. (TaiCpu(next).opcode <> A_JMP) then
  578. begin
  579. inc(nextInstrCount);
  580. for regCounter := R_EAX to R_EDI do
  581. begin
  582. if (regCounter in regsUsable) And
  583. ((PTaiProp(next.optInfo)^.Regs[regCounter].wState <>
  584. nextWState[regCounter]) or
  585. (PTaiProp(next.optInfo)^.Regs[regCounter].rState <>
  586. nextRState[regCounter])) Then
  587. begin
  588. lastRemoved := regCounter;
  589. exclude(regsUsable,regCounter);
  590. {$ifdef alignregdebug}
  591. temp := Tai_asm_comment.Create(strpnew(
  592. att_reg2str[regCounter]+' removed')));
  593. temp.next := next.next;
  594. temp.previous := next;
  595. next.next := temp;
  596. if assigned(temp.next) then
  597. temp.next.previous := temp;
  598. if regsUsable = [] then
  599. begin
  600. temp := Tai_asm_comment.Create(strpnew(
  601. 'regsUsable empty here')));
  602. temp.next := next.next;
  603. temp.previous := next;
  604. next.next := temp;
  605. if assigned(temp.next) then
  606. temp.next.previous := temp;
  607. end;
  608. {$endif alignregdebug}
  609. end;
  610. nextWState[regCounter] :=
  611. PTaiProp(next.optInfo)^.Regs[regCounter].wState;
  612. nextRState[regCounter] :=
  613. PTaiProp(next.optInfo)^.Regs[regCounter].rState;
  614. end
  615. end
  616. else
  617. for regCounter := R_EAX to R_EDI do
  618. begin
  619. nextWState[regCounter] :=
  620. PTaiProp(next.optInfo)^.Regs[regCounter].wState;
  621. nextRState[regCounter] :=
  622. PTaiProp(next.optInfo)^.Regs[regCounter].rState;
  623. end;
  624. getNextInstruction(next,next);
  625. end;
  626. end;
  627. if regsUsable <> [] then
  628. for regCounter := R_EAX to R_EDI do
  629. if regCounter in regsUsable then
  630. begin
  631. lastRemoved := regCounter;
  632. break
  633. end;
  634. {$ifdef alignregdebug}
  635. next := Tai_asm_comment.Create(strpnew(att_reg2str[lastRemoved]+
  636. ' chosen as alignment register')));
  637. next.next := p.next;
  638. next.previous := p;
  639. p.next := next;
  640. if assigned(next.next) then
  641. next.next.previous := next;
  642. {$endif alignregdebug}
  643. Tai_align(p).reg := lastRemoved;
  644. End;
  645. Procedure RestoreRegContentsTo(reg: TRegister; const c: TContent; p, endP: Tai);
  646. var
  647. {$ifdef replaceregdebug}
  648. hp: Tai;
  649. l: longint;
  650. {$endif replaceregdebug}
  651. tmpState: byte;
  652. begin
  653. {$ifdef replaceregdebug}
  654. l := random(1000);
  655. hp := Tai_asm_comment.Create(strpnew(
  656. 'restored '+att_reg2str[reg]+' with data from here... '+tostr(l))));
  657. hp.next := p;
  658. hp.previous := p.previous;
  659. p.previous := hp;
  660. if assigned(hp.previous) then
  661. hp.previous^.next := hp;
  662. {$endif replaceregdebug}
  663. { PTaiProp(p.optInfo)^.Regs[reg] := c;}
  664. While (p <> endP) Do
  665. Begin
  666. PTaiProp(p.optInfo)^.Regs[reg] := c;
  667. getNextInstruction(p,p);
  668. end;
  669. tmpState := PTaiProp(p.optInfo)^.Regs[reg].wState;
  670. repeat
  671. PTaiProp(p.optInfo)^.Regs[reg] := c;
  672. until not getNextInstruction(p,p) or
  673. (PTaiProp(p.optInfo)^.Regs[reg].wState <> tmpState);
  674. {$ifdef replaceregdebug}
  675. if assigned(p) then
  676. begin
  677. hp := Tai_asm_comment.Create(strpnew(
  678. 'restored '+att_reg2str[reg]+' till here... '+tostr(l))));
  679. hp.next := p;
  680. hp.previous := p.previous;
  681. p.previous := hp;
  682. if assigned(hp.previous) then
  683. hp.previous^.next := hp;
  684. end;
  685. {$endif replaceregdebug}
  686. end;
  687. procedure clearmemwrites(p: tai; reg: tregister);
  688. var
  689. beginmemwrite: tai;
  690. begin
  691. beginmemwrite := pTaiprop(p.optinfo)^.regs[reg].memwrite;
  692. repeat
  693. pTaiprop(p.optinfo)^.regs[reg].memwrite := nil;
  694. until not getnextinstruction(p,p) or
  695. (pTaiprop(p.optinfo)^.regs[reg].memwrite <> beginmemwrite);
  696. end;
  697. Procedure ClearRegContentsFrom(reg: TRegister; p, endP: Tai);
  698. { first clears the contents of reg from p till endP. Then the contents are }
  699. { cleared until the first instruction that changes reg }
  700. var
  701. {$ifdef replaceregdebug}
  702. hp: Tai;
  703. l: longint;
  704. {$endif replaceregdebug}
  705. regcounter: tregister;
  706. oldStartmod: Tai;
  707. begin
  708. {$ifdef replaceregdebug}
  709. l := random(1000);
  710. hp := Tai_asm_comment.Create(strpnew(
  711. 'cleared '+att_reg2str[reg]+' from here... '+tostr(l))));
  712. hp.next := p;
  713. hp.previous := p.previous;
  714. p.previous := hp;
  715. if assigned(hp.previous) then
  716. hp.previous^.next := hp;
  717. {$endif replaceregdebug}
  718. PTaiProp(p.optInfo)^.Regs[reg].typ := con_unknown;
  719. While (p <> endP) Do
  720. Begin
  721. for regcounter := R_EAX to R_EDI do
  722. if (regcounter <> reg) and
  723. assigned(pTaiprop(p.optinfo)^.regs[reg].memwrite) and
  724. reginref(regcounter,pTaiprop(p.optinfo)^.regs[reg].memwrite.oper[1].ref^) then
  725. clearmemwrites(p,regcounter);
  726. with PTaiProp(p.optInfo)^.Regs[reg] do
  727. begin
  728. typ := con_unknown;
  729. memwrite := nil;
  730. end;
  731. getNextInstruction(p,p);
  732. end;
  733. oldStartmod := PTaiProp(p.optInfo)^.Regs[reg].startmod;
  734. repeat
  735. with PTaiProp(p.optInfo)^.Regs[reg] do
  736. begin
  737. typ := con_unknown;
  738. memwrite := nil;
  739. end;
  740. until not getNextInstruction(p,p) or
  741. (PTaiProp(p.optInfo)^.Regs[reg].startmod <> oldStartmod);
  742. {$ifdef replaceregdebug}
  743. if assigned(p) then
  744. begin
  745. hp := Tai_asm_comment.Create(strpnew(
  746. 'cleared '+att_reg2str[reg]+' till here... '+tostr(l))));
  747. hp.next := p;
  748. hp.previous := p.previous;
  749. p.previous := hp;
  750. if assigned(hp.previous) then
  751. hp.previous^.next := hp;
  752. end;
  753. {$endif replaceregdebug}
  754. end;
  755. function NoHardCodedRegs(p: Taicpu; orgReg, newReg: TRegister): boolean;
  756. var chCount: byte;
  757. begin
  758. case p.opcode of
  759. A_IMUL: noHardCodedRegs := p.ops <> 1;
  760. A_SHL,A_SHR,A_SHLD,A_SHRD: noHardCodedRegs :=
  761. (p.oper[0].typ <> top_reg) or
  762. ((orgReg <> R_ECX) and (newReg <> R_ECX));
  763. else
  764. begin
  765. NoHardCodedRegs := true;
  766. with InsProp[p.opcode] do
  767. for chCount := 1 to MaxCh do
  768. if Ch[chCount] in ([Ch_REAX..Ch_MEDI,Ch_WMemEDI,Ch_All]-[Ch_RESP,Ch_WESP,Ch_RWESP]) then
  769. begin
  770. NoHardCodedRegs := false;
  771. break
  772. end;
  773. end;
  774. end;
  775. end;
  776. function ChangeReg(var Reg: TRegister; newReg, orgReg: TRegister): boolean;
  777. begin
  778. changeReg := true;
  779. if reg = newReg then
  780. reg := orgReg
  781. else if reg = regtoreg8(newReg) then
  782. reg := regtoreg8(orgReg)
  783. else if reg = regtoreg16(newReg) then
  784. reg := regtoreg16(orgReg)
  785. else changeReg := false;
  786. end;
  787. function changeOp(var o: toper; newReg, orgReg: tregister): boolean;
  788. var
  789. tmpresult: boolean;
  790. begin
  791. changeOp := false;
  792. case o.typ of
  793. top_reg: changeOp := changeReg(o.reg,newReg,orgReg);
  794. top_ref:
  795. begin
  796. tmpresult := changeReg(o.ref^.base,newReg,orgReg);
  797. changeop := changeReg(o.ref^.index,newReg,orgReg) or tmpresult;
  798. end;
  799. end;
  800. end;
  801. procedure updateStates(orgReg,newReg: tregister; hp: Tai; writeStateToo: boolean);
  802. var
  803. prev: Tai;
  804. newOrgRegRState, newOrgRegWState: byte;
  805. begin
  806. if getLastInstruction(hp,prev) then
  807. with pTaiprop(prev.optinfo)^ do
  808. begin
  809. {$ifopt r+}
  810. {$define rangeon}
  811. {$r-}
  812. {$endif}
  813. newOrgRegRState := regs[orgReg].rState +
  814. pTaiprop(hp.optinfo)^.regs[newReg].rState - regs[newReg].rstate;
  815. if writeStateToo then
  816. newOrgRegWState := regs[orgReg].wState +
  817. pTaiprop(hp.optinfo)^.regs[newReg].wState - regs[newReg].wstate;
  818. {$ifdef rangeon}
  819. {$undef rangeon}
  820. {$r+}
  821. {$endif}
  822. end
  823. else
  824. with pTaiprop(hp.optinfo)^.regs[newReg] do
  825. begin
  826. newOrgRegRState := rState;
  827. if writeStateToo then
  828. newOrgRegWState := wState;
  829. end;
  830. with pTaiprop(hp.optinfo)^.regs[orgReg] do
  831. begin
  832. rState := newOrgRegRState;
  833. if writeStateToo then
  834. wState := newOrgRegwState;
  835. end;
  836. end;
  837. function doReplaceReg(hp: Taicpu; newReg, orgReg: tregister): boolean;
  838. var
  839. opCount: longint;
  840. tmpResult: boolean;
  841. begin
  842. for opCount := 0 to hp.ops-1 do
  843. tmpResult :=
  844. changeOp(hp.oper[opCount],newReg,orgReg) or tmpResult;
  845. doReplaceReg := tmpResult;
  846. end;
  847. function RegSizesOK(oldReg,newReg: TRegister; p: Taicpu): boolean;
  848. { oldreg and newreg must be 32bit components }
  849. var opCount: byte;
  850. begin
  851. RegSizesOK := true;
  852. { if only one of them is a general purpose register ... }
  853. if (IsGP32reg(oldReg) xor IsGP32Reg(newReg)) then
  854. begin
  855. for opCount := 0 to 2 do
  856. if (p.oper[opCount].typ = top_reg) and
  857. (p.oper[opCount].reg in [R_AL..R_DH]) then
  858. begin
  859. RegSizesOK := false;
  860. break
  861. end
  862. end;
  863. end;
  864. function doReplaceReadReg(p: Taicpu; newReg,orgReg: tregister): boolean;
  865. var opCount: byte;
  866. begin
  867. doReplaceReadReg := false;
  868. { handle special case }
  869. case p.opcode of
  870. A_IMUL:
  871. begin
  872. case p.ops of
  873. 1: internalerror(1301001);
  874. 2,3:
  875. begin
  876. if changeOp(p.oper[0],newReg,orgReg) then
  877. begin
  878. { updateStates(orgReg,newReg,p,false);}
  879. doReplaceReadReg := true;
  880. end;
  881. if p.ops = 3 then
  882. if changeOp(p.oper[1],newReg,orgReg) then
  883. begin
  884. { updateStates(orgReg,newReg,p,false);}
  885. doReplaceReadReg := true;
  886. end;
  887. end;
  888. end;
  889. end;
  890. A_DIV,A_IDIV,A_MUL: internalerror(1301002);
  891. else
  892. begin
  893. for opCount := 0 to 2 do
  894. if p.oper[opCount].typ = top_ref then
  895. if changeOp(p.oper[opCount],newReg,orgReg) then
  896. begin
  897. { updateStates(orgReg,newReg,p,false);}
  898. doReplaceReadReg := true;
  899. end;
  900. for opCount := 1 to MaxCh do
  901. case InsProp[p.opcode].Ch[opCount] of
  902. Ch_ROp1:
  903. if p.oper[0].typ = top_reg then
  904. if changeReg(p.oper[0].reg,newReg,orgReg) then
  905. begin
  906. { updateStates(orgReg,newReg,p,false);}
  907. doReplaceReadReg := true;
  908. end;
  909. Ch_ROp2:
  910. if p.oper[1].typ = top_reg then
  911. if changeReg(p.oper[1].reg,newReg,orgReg) then
  912. begin
  913. { updateStates(orgReg,newReg,p,false);}
  914. doReplaceReadReg := true;
  915. end;
  916. Ch_ROp3:
  917. if p.oper[2].typ = top_reg then
  918. if changeReg(p.oper[2].reg,newReg,orgReg) then
  919. begin
  920. { updateStates(orgReg,newReg,p,false);}
  921. doReplaceReadReg := true;
  922. end;
  923. end;
  924. end;
  925. end;
  926. end;
  927. procedure updateState(reg: tregister; p: Tai);
  928. { this procedure updates the read and write states of the instructions }
  929. { coming after p. It's called when the read/write state of p has been }
  930. { changed and this change has to be propagated to the following }
  931. { instructions as well }
  932. var
  933. newRState, newWState: byte;
  934. prevRState, prevWState: byte;
  935. doRState, doWState: boolean;
  936. begin
  937. { get the new read/write states from p }
  938. with pTaiprop(p.optinfo)^.regs[reg] do
  939. begin
  940. newRState := rState;
  941. newWState := wState;
  942. end;
  943. if not GetNextInstruction(p,p) then
  944. exit;
  945. { get the old read/write states from the next instruction, to know }
  946. { when we can stop updating }
  947. with pTaiprop(p.optinfo)^.regs[reg] do
  948. begin
  949. prevRState := rState;
  950. prevWState := wState;
  951. end;
  952. { adjust the states if this next instruction reads/writes the register }
  953. if regReadByInstruction(reg,p) then
  954. incState(newRState,1);
  955. if regModifiedByInstruction(reg,p) then
  956. incState(newWState,1);
  957. { do we still have to update the read and/or write states? }
  958. doRState := true;
  959. doWState := true;
  960. repeat
  961. { update the states }
  962. with pTaiprop(p.optinfo)^.regs[reg] do
  963. begin
  964. if doRState then
  965. rState := newRState;
  966. if doWState then
  967. wState := newWState;
  968. end;
  969. if not getNextInstruction(p,p) then
  970. break;
  971. with pTaiprop(p.optinfo)^.regs[reg] do
  972. begin
  973. { stop updating the read state if it changes }
  974. doRState :=
  975. doRState and (rState = prevRState);
  976. { if, by accident, this changed state is the same as the one }
  977. { we've been using, change it to a value that's definitely }
  978. { different from the previous and next state }
  979. if not doRState and
  980. (rState = newRState) then
  981. begin
  982. incState(newRState,1);
  983. prevRState := rState;
  984. doRState := true;
  985. end;
  986. { ditto for the write state }
  987. doWState :=
  988. doWState and (WState = prevWState);
  989. if not doWState and
  990. (wState = newWState) then
  991. begin
  992. incState(newWState,1);
  993. prevWState := wState;
  994. doWState := true;
  995. end;
  996. end;
  997. { stop when we don't have to update either state anymore }
  998. until not(doRState or doWState);
  999. end;
  1000. function storeBack(p1: Tai; orgReg, newReg: tregister): boolean;
  1001. { returns true if p1 contains an instruction that stores the contents }
  1002. { of newReg back to orgReg }
  1003. begin
  1004. storeBack :=
  1005. (p1.typ = ait_instruction) and
  1006. (Taicpu(p1).opcode = A_MOV) and
  1007. (Taicpu(p1).oper[0].typ = top_reg) and
  1008. (Taicpu(p1).oper[0].reg = newReg) and
  1009. (Taicpu(p1).oper[1].typ = top_reg) and
  1010. (Taicpu(p1).oper[1].reg = orgReg);
  1011. end;
  1012. function ReplaceReg(asmL: TAAsmOutput; orgReg, newReg: TRegister; p: Tai;
  1013. const c: TContent; orgRegCanBeModified: Boolean;
  1014. var returnEndP: Tai): Boolean;
  1015. { Tries to replace orgreg with newreg in all instructions coming after p }
  1016. { until orgreg gets loaded with a new value. Returns true if successful, }
  1017. { false otherwise. If successful, the contents of newReg are set to c, }
  1018. { which should hold the contents of newReg before the current sequence }
  1019. { started }
  1020. { if the function returns true, returnEndP holds the last instruction }
  1021. { where newReg was replaced by orgReg }
  1022. var endP, hp: Tai;
  1023. removeLast, sequenceEnd, tmpResult, newRegModified, orgRegRead,
  1024. stateChanged, readStateChanged: Boolean;
  1025. begin
  1026. ReplaceReg := false;
  1027. tmpResult := true;
  1028. sequenceEnd := false;
  1029. newRegModified := false;
  1030. orgRegRead := false;
  1031. removeLast := false;
  1032. endP := p;
  1033. while tmpResult and not sequenceEnd do
  1034. begin
  1035. tmpResult :=
  1036. getNextInstruction(endP,endP) and
  1037. (endp.typ = ait_instruction) and
  1038. not(Taicpu(endp).is_jmp);
  1039. if tmpresult and not assigned(endp.optInfo) then
  1040. begin
  1041. { hp := Tai_asm_comment.Create(strpnew('next no optinfo'));
  1042. hp.next := endp;
  1043. hp.previous := endp.previous;
  1044. endp.previous := hp;
  1045. if assigned(hp.previous) then
  1046. hp.previous^.next := hp;}
  1047. exit;
  1048. end;
  1049. If tmpResult and
  1050. { don't take into account instructions that will be removed }
  1051. Not (PTaiProp(endp.optInfo)^.canBeRemoved) then
  1052. begin
  1053. { if the newReg gets stored back to the oldReg, we can change }
  1054. { "mov %oldReg,%newReg; <operations on %newReg>; mov %newReg, }
  1055. { %oldReg" to "<operations on %oldReg>" }
  1056. removeLast := storeBack(endP, orgReg, newReg);
  1057. sequenceEnd :=
  1058. { no support for (i)div, mul and imul with hardcoded operands }
  1059. (noHardCodedRegs(Taicpu(endP),orgReg,newReg) and
  1060. { if newReg gets loaded with a new value, we can stop }
  1061. { replacing newReg with oldReg here (possibly keeping }
  1062. { the original contents of oldReg so we still know them }
  1063. { afterwards) }
  1064. RegLoadedWithNewValue(newReg,true,Taicpu(endP)) or
  1065. { we can also stop if we reached the end of the use of }
  1066. { newReg's current contents }
  1067. (GetNextInstruction(endp,hp) and
  1068. FindRegDealloc(newReg,hp)));
  1069. { to be able to remove the first and last instruction of }
  1070. { movl %reg1, %reg2 }
  1071. { <operations on %reg2> (replacing reg2 with reg1 here) }
  1072. { movl %reg2, %reg1 }
  1073. { %reg2 must not be use afterwards (it can be as the }
  1074. { result of a peepholeoptimization) }
  1075. removeLast := removeLast and sequenceEnd;
  1076. newRegModified :=
  1077. newRegModified or
  1078. (not(regLoadedWithNewValue(newReg,true,Taicpu(endP))) and
  1079. RegModifiedByInstruction(newReg,endP));
  1080. orgRegRead := newRegModified and RegReadByInstruction(orgReg,endP);
  1081. sequenceEnd := SequenceEnd and
  1082. (removeLast or
  1083. { since newReg will be replaced by orgReg, we can't allow that newReg }
  1084. { gets modified if orgReg is still read afterwards (since after }
  1085. { replacing, this would mean that orgReg first gets modified and then }
  1086. { gets read in the assumption it still contains the unmodified value) }
  1087. not(newRegModified and orgRegRead)) (* and
  1088. { since newReg will be replaced by orgReg, we can't allow that newReg }
  1089. { gets modified if orgRegCanBeModified = false }
  1090. { this now gets checked after the loop (JM) }
  1091. (orgRegCanBeModified or not(newRegModified)) *);
  1092. tmpResult :=
  1093. not(removeLast) and
  1094. not(newRegModified and orgRegRead) and
  1095. (* (orgRegCanBeModified or not(newRegModified)) and *)
  1096. (* already check at the top
  1097. (endp.typ = ait_instruction) and *)
  1098. NoHardCodedRegs(Taicpu(endP),orgReg,newReg) and
  1099. RegSizesOk(orgReg,newReg,Taicpu(endP)) and
  1100. not RegModifiedByInstruction(orgReg,endP);
  1101. end;
  1102. end;
  1103. sequenceEnd := sequenceEnd and
  1104. (removeLast or
  1105. (orgRegCanBeModified or not(newRegModified))) and
  1106. (not(assigned(endp)) or
  1107. not(endp.typ = ait_instruction) or
  1108. (noHardCodedRegs(Taicpu(endP),orgReg,newReg) and
  1109. RegSizesOk(orgReg,newReg,Taicpu(endP)) and
  1110. not(newRegModified and
  1111. (orgReg in PTaiProp(endp.optInfo)^.usedRegs) and
  1112. not(RegLoadedWithNewValue(orgReg,true,Taicpu(endP))))));
  1113. if SequenceEnd then
  1114. begin
  1115. {$ifdef replaceregdebug}
  1116. hp := Tai_asm_comment.Create(strpnew(
  1117. 'replacing '+att_reg2str[newreg]+' with '+att_reg2str[orgreg]+
  1118. ' from here...')));
  1119. hp.next := p;
  1120. hp.previous := p.previous;
  1121. p.previous := hp;
  1122. if assigned(hp.previous) then
  1123. hp.previous^.next := hp;
  1124. hp := Tai_asm_comment.Create(strpnew(
  1125. 'replaced '+att_reg2str[newreg]+' with '+att_reg2str[orgreg]+
  1126. ' till here')));
  1127. hp.next := endp.next;
  1128. hp.previous := endp;
  1129. endp.next := hp;
  1130. if assigned(hp.next) then
  1131. hp.next.previous := hp;
  1132. {$endif replaceregdebug}
  1133. replaceReg := true;
  1134. returnEndP := endP;
  1135. getNextInstruction(p,hp);
  1136. stateChanged := false;
  1137. while hp <> endP do
  1138. begin
  1139. if {not(PTaiProp(hp.optInfo)^.canBeRemoved) and }
  1140. (hp.typ = ait_instruction) then
  1141. stateChanged :=
  1142. doReplaceReg(Taicpu(hp),newReg,orgReg) or stateChanged;
  1143. if stateChanged then
  1144. updateStates(orgReg,newReg,hp,true);
  1145. getNextInstruction(hp,hp)
  1146. end;
  1147. if assigned(endp) and (endp.typ = ait_instruction) then
  1148. readStateChanged :=
  1149. DoReplaceReadReg(Taicpu(endP),newReg,orgReg);
  1150. if stateChanged or readStateChanged then
  1151. updateStates(orgReg,newReg,endP,stateChanged);
  1152. if stateChanged or readStateChanged then
  1153. updateState(orgReg,endP);
  1154. { the replacing stops either at the moment that }
  1155. { a) the newreg gets loaded with a new value (one not depending on the }
  1156. { current value of newreg) }
  1157. { b) newreg is completely replaced in this sequence and it's current value }
  1158. { isn't used anymore }
  1159. { In case b, the newreg was completely replaced by oldreg, so it's contents }
  1160. { are unchanged compared the start of this sequence, so restore them }
  1161. If removeLast or
  1162. RegLoadedWithNewValue(newReg,true,endP) then
  1163. GetLastInstruction(endP,hp)
  1164. else hp := endP;
  1165. if removeLast or
  1166. (p <> endp) or
  1167. not RegLoadedWithNewValue(newReg,true,endP) then
  1168. RestoreRegContentsTo(newReg,c,p,hp);
  1169. { In both case a and b, it is possible that the new register was modified }
  1170. { (e.g. an add/sub), so if it was replaced by oldreg in that instruction, }
  1171. { oldreg's contents have been changed. To take this into account, we simply }
  1172. { set the contents of orgreg to "unknown" after this sequence }
  1173. if newRegModified then
  1174. ClearRegContentsFrom(orgReg,p,hp);
  1175. if removeLast then
  1176. pTaiprop(endp.optinfo)^.canBeRemoved := true;
  1177. allocRegBetween(asml,orgReg,p,endP);
  1178. end
  1179. {$ifdef replaceregdebug}
  1180. else
  1181. begin
  1182. hp := Tai_asm_comment.Create(strpnew(
  1183. 'replacing '+att_reg2str[newreg]+' with '+att_reg2str[orgreg]+
  1184. ' from here...')));
  1185. hp.previous := p.previous;
  1186. hp.next := p;
  1187. p.previous := hp;
  1188. if assigned(hp.previous) then
  1189. hp.previous^.next := hp;
  1190. hp := Tai_asm_comment.Create(strpnew(
  1191. 'replacing '+att_reg2str[newreg]+' with '+att_reg2str[orgreg]+
  1192. ' failed here')));
  1193. hp.next := endp.next;
  1194. hp.previous := endp;
  1195. endp.next := hp;
  1196. if assigned(hp.next) then
  1197. hp.next.previous := hp;
  1198. end;
  1199. {$endif replaceregdebug}
  1200. End;
  1201. Function FindRegWithConst(p: Tai; size: topsize; l: longint; Var Res: TRegister): Boolean;
  1202. {Finds a register which contains the constant l}
  1203. Var Counter: TRegister;
  1204. {$ifdef testing}
  1205. hp: Tai;
  1206. {$endif testing}
  1207. tmpresult: boolean;
  1208. Begin
  1209. Counter := R_NO;
  1210. repeat
  1211. inc(counter);
  1212. tmpresult := (pTaiprop(p.optInfo)^.regs[counter].typ in
  1213. [con_const,con_noRemoveConst]) and
  1214. (Taicpu(PTaiProp(p.OptInfo)^.Regs[Counter].StartMod).opsize = size) and
  1215. (Taicpu(PTaiProp(p.OptInfo)^.Regs[Counter].StartMod).oper[0].typ = top_const) and
  1216. (Taicpu(PTaiProp(p.OptInfo)^.Regs[Counter].StartMod).oper[0].val = l);
  1217. {$ifdef testing}
  1218. if (pTaiprop(p.optInfo)^.regs[counter].typ in [con_const,con_noRemoveConst]) then
  1219. begin
  1220. hp := Tai_asm_comment.Create(strpnew(
  1221. 'checking const load of '+tostr(l)+' here...')));
  1222. hp.next := PTaiProp(p.OptInfo)^.Regs[Counter].StartMod;
  1223. hp.previous := PTaiProp(p.OptInfo)^.Regs[Counter].StartMod^.previous;
  1224. PTaiProp(p.OptInfo)^.Regs[Counter].StartMod^.previous := hp;
  1225. if assigned(hp.previous) then
  1226. hp.previous^.next := hp;
  1227. end;
  1228. {$endif testing}
  1229. until tmpresult or (Counter = R_EDI);
  1230. if tmpResult then
  1231. res := Taicpu(PTaiProp(p.OptInfo)^.Regs[Counter].StartMod).oper[1].reg;
  1232. FindRegWithConst := tmpResult;
  1233. End;
  1234. procedure removePrevNotUsedLoad(p: Tai; reg: tRegister; check: boolean);
  1235. { If check = true, it means the procedure has to check whether it isn't }
  1236. { possible that the contents are still used after p (used when removing }
  1237. { instructions because of a "call"), otherwise this is not necessary }
  1238. { (e.g. when you have a "mov 8(%ebp),%eax", you can be sure the previous }
  1239. { value of %eax isn't used anymore later on) }
  1240. var
  1241. hp1: Tai;
  1242. begin
  1243. if getLastInstruction(p,hp1) then
  1244. with pTaiprop(hp1.optInfo)^.regs[reg] do
  1245. if (typ in [con_ref,con_invalid,con_const]) and
  1246. (nrOfMods = 1) and
  1247. (rState = pTaiprop(startmod.optInfo)^.regs[reg].rState) and
  1248. (not(check) or
  1249. (not(regInInstruction(reg,p)) and
  1250. (not(reg in usableregs) and
  1251. (startmod.typ = ait_instruction) and
  1252. ((Taicpu(startmod).opcode = A_MOV) or
  1253. (Taicpu(startmod).opcode = A_MOVZX) or
  1254. (Taicpu(startmod).opcode = A_MOVSX) or
  1255. (Taicpu(startmod).opcode = A_LEA)) and
  1256. (Taicpu(startmod).oper[0].typ = top_ref) and
  1257. (Taicpu(startmod).oper[0].ref^.base = stack_pointer)) or
  1258. not(reg in pTaiprop(hp1.optInfo)^.usedRegs) or
  1259. findRegDealloc(reg,p))) then
  1260. pTaiprop(startMod.optInfo)^.canBeRemoved := true;
  1261. end;
  1262. function is_mov_for_div(p: Taicpu): boolean;
  1263. begin
  1264. is_mov_for_div :=
  1265. (p.opcode = A_MOV) and
  1266. (p.oper[0].typ = top_const) and
  1267. (p.oper[1].typ = top_reg) and
  1268. (p.oper[1].reg = R_EDX) and
  1269. getNextInstruction(p,p) and
  1270. (p.typ = ait_instruction) and
  1271. ((p.opcode = A_DIV) or
  1272. (p.opcode = A_IDIV));
  1273. end;
  1274. function memtoreg(const t: Taicpu; const ref: treference; var startp: tai): tregister;
  1275. var
  1276. hp: tai;
  1277. p: pTaiprop;
  1278. regcounter: tregister;
  1279. optimizable: boolean;
  1280. begin
  1281. if not getlastinstruction(t,hp) or
  1282. not issimplememloc(ref) then
  1283. begin
  1284. memtoreg := R_NO;
  1285. exit;
  1286. end;
  1287. p := pTaiprop(hp.optinfo);
  1288. optimizable := false;
  1289. for regcounter := R_EAX to R_EDI do
  1290. begin
  1291. if (assigned(p^.regs[regcounter].memwrite) and
  1292. refsequal(ref,p^.regs[regcounter].memwrite.oper[1].ref^)) then
  1293. begin
  1294. optimizable := true;
  1295. hp := p^.regs[regcounter].memwrite;
  1296. end
  1297. else if ((p^.regs[regcounter].typ in [CON_REF,CON_NOREMOVEREF]) and
  1298. (p^.regs[regcounter].nrofmods = 1) and
  1299. ((Taicpu(p^.regs[regcounter].startmod).opcode = A_MOV) or
  1300. (Taicpu(p^.regs[regcounter].startmod).opcode = A_MOVZX) or
  1301. (Taicpu(p^.regs[regcounter].startmod).opcode = A_MOVSX)) and
  1302. (taicpu(p^.regs[regcounter].startmod).oper[0].typ = top_ref) and
  1303. refsequal(ref,taicpu(p^.regs[regcounter].startmod).oper[0].ref^)) then
  1304. begin
  1305. optimizable := true;
  1306. hp := p^.regs[regcounter].startmod;
  1307. end;
  1308. if optimizable then
  1309. if ((t.opsize <> S_B) or
  1310. (regcounter <> R_EDI)) and
  1311. sizescompatible(Taicpu(hp).opsize,t.opsize) then
  1312. begin
  1313. case t.opsize of
  1314. S_B,S_BW,S_BL:
  1315. memtoreg := reg32toreg8(regcounter);
  1316. S_W,S_WL:
  1317. memtoreg := reg32toreg16(regcounter);
  1318. S_L:
  1319. memtoreg := regcounter;
  1320. end;
  1321. startp := hp;
  1322. exit;
  1323. end;
  1324. end;
  1325. memtoreg := R_NO;
  1326. end;
  1327. procedure DoCSE(AsmL: TAAsmOutput; First, Last: Tai; findPrevSeqs, doSubOpts: boolean);
  1328. {marks the instructions that can be removed by RemoveInstructs. They're not
  1329. removed immediately because sometimes an instruction needs to be checked in
  1330. two different sequences}
  1331. var cnt, cnt2, cnt3, orgNrOfMods: longint;
  1332. p, hp1, hp2, prevSeq, prevSeq_next: Tai;
  1333. hp3, hp4: Tai;
  1334. hp5 : Tai;
  1335. RegInfo: TRegInfo;
  1336. RegCounter: TRegister;
  1337. Begin
  1338. p := First;
  1339. SkipHead(p);
  1340. While (p <> Last) Do
  1341. Begin
  1342. Case p.typ Of
  1343. ait_align:
  1344. if not(Tai_align(p).use_op) then
  1345. SetAlignReg(p);
  1346. ait_instruction:
  1347. Begin
  1348. Case Taicpu(p).opcode Of
  1349. A_CALL:
  1350. for regCounter := R_EAX to R_EBX do
  1351. removePrevNotUsedLoad(p,regCounter,true);
  1352. A_CLD: If GetLastInstruction(p, hp1) And
  1353. (PTaiProp(hp1.OptInfo)^.DirFlag = F_NotSet) Then
  1354. PTaiProp(Tai(p).OptInfo)^.CanBeRemoved := True;
  1355. A_LEA, A_MOV, A_MOVZX, A_MOVSX:
  1356. Begin
  1357. hp2 := p;
  1358. Case Taicpu(p).oper[0].typ Of
  1359. top_ref, top_reg:
  1360. if (Taicpu(p).oper[1].typ = top_reg) then
  1361. Begin
  1362. With PTaiProp(p.OptInfo)^.Regs[Reg32(Taicpu(p).oper[1].reg)] Do
  1363. Begin
  1364. if (startmod = p) then
  1365. orgNrOfMods := nrOfMods
  1366. else
  1367. orgNrOfMods := 0;
  1368. If (p = StartMod) And
  1369. GetLastInstruction (p, hp1) And
  1370. (hp1.typ <> ait_marker) Then
  1371. {so we don't try to check a sequence when p is the first instruction of the block}
  1372. begin
  1373. {$ifdef csdebug}
  1374. hp5 := Tai_asm_comment.Create(strpnew(
  1375. 'cse checking '+att_reg2str[Reg32(Taicpu(p).oper[1].reg)])));
  1376. insertLLItem(asml,p,p.next,hp5);
  1377. {$endif csdebug}
  1378. If CheckSequence(p,prevSeq,Taicpu(p).oper[1].reg, Cnt, RegInfo, findPrevSeqs) And
  1379. (Cnt > 0) Then
  1380. Begin
  1381. (*
  1382. hp1 := nil;
  1383. { although it's perfectly ok to remove an instruction which doesn't contain }
  1384. { the register that we've just checked (CheckSequence takes care of that), }
  1385. { the sequence containing this other register should also be completely }
  1386. { checked and removed, otherwise we may get situations like this: }
  1387. { }
  1388. { movl 12(%ebp), %edx movl 12(%ebp), %edx }
  1389. { movl 16(%ebp), %eax movl 16(%ebp), %eax }
  1390. { movl 8(%edx), %edx movl 8(%edx), %edx }
  1391. { movl (%eax), eax movl (%eax), eax }
  1392. { cmpl %eax, %edx cmpl %eax, %edx }
  1393. { jnz l123 getting converted to jnz l123 }
  1394. { movl 12(%ebp), %edx movl 4(%eax), eax }
  1395. { movl 16(%ebp), %eax }
  1396. { movl 8(%edx), %edx }
  1397. { movl 4(%eax), eax }
  1398. *)
  1399. { not anymore: if the start of a new sequence is found while checking (e.g. }
  1400. { above that of eax while checking edx, this new sequence is automatically }
  1401. { also checked }
  1402. Cnt2 := 1;
  1403. While Cnt2 <= Cnt Do
  1404. Begin
  1405. (*
  1406. If not(regInInstruction(Taicpu(hp2).oper[1].reg, p)) and
  1407. not(pTaiprop(p.optinfo)^.canBeRemoved) then
  1408. begin
  1409. if (p.typ = ait_instruction) And
  1410. ((Taicpu(p).OpCode = A_MOV) or
  1411. (Taicpu(p).opcode = A_MOVZX) or
  1412. (Taicpu(p).opcode = A_MOVSX)) And
  1413. (Taicpu(p).oper[1].typ = top_reg) then
  1414. if not is_mov_for_div(Taicpu(p)) then
  1415. begin
  1416. regCounter := reg32(Taicpu(p).oper[1].reg);
  1417. if (regCounter in reginfo.regsStillUsedAfterSeq) then
  1418. begin
  1419. if (hp1 = nil) then
  1420. hp1 := reginfo.lastReload[regCounter];
  1421. end
  1422. {$ifndef noremove}
  1423. else
  1424. begin
  1425. hp5 := p;
  1426. for cnt3 := pTaiprop(p.optinfo)^.regs[regCounter].nrofmods downto 1 do
  1427. begin
  1428. if regModifiedByInstruction(regCounter,hp5) then
  1429. PTaiProp(hp5.OptInfo)^.CanBeRemoved := True;
  1430. getNextInstruction(hp5,hp5);
  1431. end;
  1432. end
  1433. {$endif noremove}
  1434. end
  1435. {$ifndef noremove}
  1436. else
  1437. PTaiProp(p.OptInfo)^.CanBeRemoved := True
  1438. {$endif noremove}
  1439. end
  1440. *)
  1441. {$ifndef noremove}
  1442. (* else *)
  1443. PTaiProp(p.OptInfo)^.CanBeRemoved := True
  1444. {$endif noremove}
  1445. ; Inc(Cnt2);
  1446. GetNextInstruction(p, p);
  1447. End;
  1448. {hp4 is used to get the contents of the registers before the sequence}
  1449. GetLastInstruction(hp2, hp4);
  1450. getNextInstruction(prevSeq,prevSeq_next);
  1451. {$IfDef CSDebug}
  1452. For RegCounter := R_EAX To R_EDI Do
  1453. If (RegCounter in RegInfo.RegsLoadedForRef) Then
  1454. Begin
  1455. hp5 := Tai_asm_comment.Create(strpnew('New: '+att_reg2str[RegCounter]+', Old: '+
  1456. att_reg2str[RegInfo.New2OldReg[RegCounter]])));
  1457. InsertLLItem(AsmL, Tai(hp2.previous), hp2, hp5);
  1458. End;
  1459. {$EndIf CSDebug}
  1460. { If some registers were different in the old and the new sequence, move }
  1461. { the contents of those old registers to the new ones }
  1462. For RegCounter := R_EAX To R_EDI Do
  1463. If Not(RegCounter in [R_ESP,procinfo^.framepointer]) And
  1464. (RegInfo.New2OldReg[RegCounter] <> R_NO) Then
  1465. Begin
  1466. AllocRegBetween(AsmL,RegInfo.New2OldReg[RegCounter],
  1467. PTaiProp(prevSeq.OptInfo)^.Regs[RegInfo.New2OldReg[RegCounter]].StartMod,hp2);
  1468. if hp4 <> prevSeq then
  1469. begin
  1470. if assigned(reginfo.lastReload[regCounter]) then
  1471. getLastInstruction(reginfo.lastReload[regCounter],hp3)
  1472. else if assigned(reginfo.lastReload[regInfo.New2OldReg[regCounter]]) then
  1473. getLastInstruction(reginfo.lastReload[regInfo.new2OldReg[regCounter]],hp3)
  1474. else hp3 := hp4;
  1475. clearRegContentsFrom(regCounter,prevSeq_next,hp3);
  1476. getnextInstruction(hp3,hp3);
  1477. allocRegBetween(asmL,regCounter,prevSeq,hp3);
  1478. end;
  1479. If Not(RegCounter In RegInfo.RegsLoadedForRef) And
  1480. {old reg new reg}
  1481. (RegInfo.New2OldReg[RegCounter] <> RegCounter) Then
  1482. Begin
  1483. getLastInstruction(p,hp3);
  1484. If (hp4 <> prevSeq) or
  1485. not(regCounter in usableRegs + [R_EDI,R_ESI]) or
  1486. not ReplaceReg(asmL,RegInfo.New2OldReg[RegCounter],
  1487. regCounter,hp3,
  1488. PTaiProp(PrevSeq.optInfo)^.Regs[regCounter],true,hp5) then
  1489. begin
  1490. hp3 := Tai_Marker.Create(NoPropInfoStart);
  1491. InsertLLItem(AsmL, prevSeq_next.previous,Tai(prevSeq_next), hp3);
  1492. hp5 := Taicpu.Op_Reg_Reg(A_MOV, S_L,
  1493. {old reg new reg}
  1494. RegInfo.New2OldReg[RegCounter], RegCounter);
  1495. new(pTaiprop(hp5.optinfo));
  1496. pTaiprop(hp5.optinfo)^ := pTaiprop(prevSeq_next.optinfo)^;
  1497. pTaiprop(hp5.optinfo)^.canBeRemoved := false;
  1498. InsertLLItem(AsmL, prevSeq_next.previous, Tai(prevSeq_next), hp5);
  1499. hp3 := Tai_Marker.Create(NoPropInfoEnd);
  1500. InsertLLItem(AsmL, prevSeq_next.previous, Tai(prevSeq_next), hp3);
  1501. { adjusts states in previous instruction so that it will }
  1502. { definitely be different from the previous or next state }
  1503. incstate(pTaiprop(hp5.optinfo)^.
  1504. regs[RegInfo.New2OldReg[RegCounter]].rstate,20);
  1505. incstate(pTaiprop(hp5.optinfo)^.
  1506. regs[regCounter].wstate,20);
  1507. updateState(RegInfo.New2OldReg[RegCounter],hp5);
  1508. end
  1509. End
  1510. Else
  1511. { imagine the following code: }
  1512. { normal wrong optimized }
  1513. { movl 8(%ebp), %eax movl 8(%ebp), %eax }
  1514. { movl (%eax), %eax movl (%eax), %eax }
  1515. { cmpl 8(%ebp), %eax cmpl 8(%ebp), %eax }
  1516. { jne l1 jne l1 }
  1517. { movl 8(%ebp), %eax }
  1518. { movl (%eax), %edi movl %eax, %edi }
  1519. { movl %edi, -4(%ebp) movl %edi, -4(%ebp) }
  1520. { movl 8(%ebp), %eax }
  1521. { pushl 70(%eax) pushl 70(%eax) }
  1522. { }
  1523. { The error is that at the moment that the last instruction is executed, }
  1524. { %eax doesn't contain 8(%ebp) anymore. Solution: the contents of }
  1525. { registers that are completely removed from a sequence (= registers in }
  1526. { RegLoadedForRef, have to be changed to their contents from before the }
  1527. { sequence. }
  1528. If RegCounter in RegInfo.RegsLoadedForRef Then
  1529. Begin
  1530. hp3 := hp2;
  1531. { cnt still holds the number of instructions }
  1532. { of the sequence, so go to the end of it }
  1533. for cnt2 := 1 to pred(cnt) Do
  1534. getNextInstruction(hp3,hp3);
  1535. { hp4 = instruction prior to start of sequence }
  1536. restoreRegContentsTo(regCounter,
  1537. PTaiProp(hp4.OptInfo)^.Regs[RegCounter],
  1538. hp2,hp3);
  1539. End;
  1540. End;
  1541. (*
  1542. If hp1 <> nil Then
  1543. p := hp1;
  1544. *)
  1545. Continue;
  1546. End
  1547. (*
  1548. Else
  1549. If (PTaiProp(p.OptInfo)^.
  1550. regs[reg32(Taicpu(p).oper[1].reg)].typ
  1551. in [con_ref,con_noRemoveRef]) and
  1552. (PTaiProp(p.OptInfo)^.CanBeRemoved) Then
  1553. if (cnt > 0) then
  1554. begin
  1555. p := hp2;
  1556. Cnt2 := 1;
  1557. While Cnt2 <= Cnt Do
  1558. Begin
  1559. If RegInInstruction(Taicpu(hp2).oper[1].reg, p) Then
  1560. PTaiProp(p.OptInfo)^.CanBeRemoved := False;
  1561. Inc(Cnt2);
  1562. GetNextInstruction(p, p);
  1563. End;
  1564. Continue;
  1565. End
  1566. else
  1567. begin
  1568. { Fix for web bug 972 }
  1569. regCounter := Reg32(Taicpu(p).oper[1].reg);
  1570. cnt := PTaiProp(p.optInfo)^.Regs[regCounter].nrOfMods;
  1571. hp3 := p;
  1572. for cnt2 := 1 to cnt do
  1573. if not(regModifiedByInstruction(regCounter,hp3) and
  1574. not(PTaiProp(hp3.optInfo)^.canBeRemoved)) then
  1575. getNextInstruction(hp3,hp3)
  1576. else
  1577. break;
  1578. getLastInstruction(p,hp4);
  1579. RestoreRegContentsTo(regCounter,
  1580. PTaiProp(hp4.optInfo)^.Regs[regCounter],
  1581. p,hp3);
  1582. end;
  1583. *)
  1584. End;
  1585. End;
  1586. { try to replace the new reg with the old reg }
  1587. if not(PTaiProp(p.optInfo)^.canBeRemoved) then
  1588. if (Taicpu(p).oper[0].typ = top_reg) and
  1589. (Taicpu(p).oper[1].typ = top_reg) and
  1590. { only remove if we're not storing something in a regvar }
  1591. (Taicpu(p).oper[1].reg in (usableregs+[R_EDI])) and
  1592. (Taicpu(p).opcode = A_MOV) and
  1593. getLastInstruction(p,hp4) and
  1594. { we only have to start replacing from the instruction after the mov, }
  1595. { but replacereg only starts with getnextinstruction(p,p) }
  1596. replaceReg(asmL,Taicpu(p).oper[0].reg,
  1597. Taicpu(p).oper[1].reg,p,
  1598. pTaiprop(hp4.optInfo)^.regs[Taicpu(p).oper[1].reg],false,hp1) then
  1599. begin
  1600. pTaiprop(p.optInfo)^.canBeRemoved := true;
  1601. allocRegBetween(asmL,Taicpu(p).oper[0].reg,
  1602. pTaiProp(p.optInfo)^.regs[Taicpu(p).oper[0].reg].startMod,hp1);
  1603. end
  1604. else
  1605. begin
  1606. if (Taicpu(p).oper[1].typ = top_reg) and
  1607. not regInOp(Taicpu(p).oper[1].reg,Taicpu(p).oper[0]) then
  1608. removePrevNotUsedLoad(p,reg32(Taicpu(p).oper[1].reg),false);
  1609. if doSubOpts and
  1610. (Taicpu(p).opcode <> A_LEA) and
  1611. (Taicpu(p).oper[0].typ = top_ref) then
  1612. begin
  1613. regcounter :=
  1614. memtoreg(taicpu(p),
  1615. Taicpu(p).oper[0].ref^,hp5);
  1616. if regcounter <> R_NO then
  1617. if (taicpu(p).opcode = A_MOV) and
  1618. (taicpu(p).oper[1].typ = top_reg) and
  1619. (taicpu(p).oper[1].reg = regcounter) then
  1620. begin
  1621. pTaiProp(p.optinfo)^.canberemoved := true;
  1622. allocregbetween(asml,reg32(regcounter),hp5,p);
  1623. end
  1624. else
  1625. begin
  1626. Taicpu(p).loadreg(0,regcounter);
  1627. regcounter := reg32(regcounter);
  1628. allocregbetween(asml,regcounter,hp5,p);
  1629. incstate(pTaiProp(p.optinfo)^.regs[regcounter].rstate,1);
  1630. updatestate(regcounter,p);
  1631. end;
  1632. end;
  1633. end;
  1634. { at first, only try optimizations of large blocks, because doing }
  1635. { doing smaller ones may prevent bigger ones from completing in }
  1636. { in the next pass }
  1637. if not doSubOpts and (orgNrOfMods <> 0) then
  1638. begin
  1639. p := hp2;
  1640. for cnt := 1 to pred(orgNrOfMods) do
  1641. getNextInstruction(p,p);
  1642. end;
  1643. End;
  1644. top_symbol,Top_Const:
  1645. Begin
  1646. Case Taicpu(p).oper[1].typ Of
  1647. Top_Reg:
  1648. Begin
  1649. regCounter := Reg32(Taicpu(p).oper[1].reg);
  1650. If GetLastInstruction(p, hp1) Then
  1651. With PTaiProp(hp1.OptInfo)^.Regs[regCounter] Do
  1652. if (typ in [con_const,con_noRemoveConst]) and
  1653. (Taicpu(startMod).opsize >= Taicpu(p).opsize) and
  1654. opsequal(Taicpu(StartMod).oper[0],Taicpu(p).oper[0]) Then
  1655. begin
  1656. PTaiProp(p.OptInfo)^.CanBeRemoved := True;
  1657. allocRegBetween(asmL,regCounter,startMod,p);
  1658. end
  1659. else
  1660. removePrevNotUsedLoad(p,reg32(Taicpu(p).oper[1].reg),false);
  1661. End;
  1662. Top_Ref:
  1663. if (Taicpu(p).oper[0].typ = top_const) and
  1664. getLastInstruction(p,hp1) and
  1665. findRegWithConst(hp1,Taicpu(p).opsize,Taicpu(p).oper[0].val,regCounter) then
  1666. begin
  1667. Taicpu(p).loadreg(0,regCounter);
  1668. allocRegBetween(AsmL,reg32(regCounter),
  1669. PTaiProp(hp1.optinfo)^.regs[regCounter].startMod,p);
  1670. end;
  1671. End;
  1672. End;
  1673. End;
  1674. End;
  1675. A_STD: If GetLastInstruction(p, hp1) And
  1676. (PTaiProp(hp1.OptInfo)^.DirFlag = F_Set) Then
  1677. PTaiProp(Tai(p).OptInfo)^.CanBeRemoved := True;
  1678. else
  1679. begin
  1680. for cnt := 1 to maxch do
  1681. begin
  1682. case InsProp[taicpu(p).opcode].Ch[cnt] of
  1683. Ch_ROp1:
  1684. if (taicpu(p).oper[0].typ = top_ref) and
  1685. ((taicpu(p).opcode < A_F2XM1) or
  1686. ((taicpu(p).opcode > A_IN) and
  1687. (taicpu(p).opcode < A_OUT)) or
  1688. (taicpu(p).opcode = A_PUSH) or
  1689. ((taicpu(p).opcode >= A_RCL) and
  1690. (taicpu(p).opcode <= A_XOR))) then
  1691. begin
  1692. regcounter :=
  1693. memtoreg(taicpu(p),
  1694. Taicpu(p).oper[0].ref^,hp5);
  1695. if regcounter <> R_NO then
  1696. begin
  1697. Taicpu(p).loadreg(0,regcounter);
  1698. regcounter := reg32(regcounter);
  1699. allocregbetween(asml,regcounter,hp5,p);
  1700. incstate(pTaiProp(p.optinfo)^.regs[regcounter].rstate,1);
  1701. updatestate(regcounter,p);
  1702. end;
  1703. end;
  1704. Ch_MOp1:
  1705. if Not(CS_LittleSize in aktglobalswitches) And
  1706. (taicpu(p).oper[0].typ = top_ref) then
  1707. begin
  1708. regcounter :=
  1709. memtoreg(taicpu(p),
  1710. Taicpu(p).oper[0].ref^,hp5);
  1711. if (regcounter <> R_NO) (* and
  1712. (not getNextInstruction(p,hp1) or
  1713. (RegLoadedWithNewValue(reg32(regcounter),false,hp1) or
  1714. FindRegDealloc(reg32(regcounter),hp1))) *) then
  1715. begin
  1716. hp1 := Tai_Marker.Create(NoPropInfoEnd);
  1717. insertllitem(asml,p,p.next,hp1);
  1718. hp1 := taicpu.op_reg_ref(A_MOV,
  1719. regsize(regcounter),regcounter,
  1720. newreference(taicpu(p).oper[0].ref^));
  1721. new(pTaiprop(hp1.optinfo));
  1722. pTaiProp(hp1.optinfo)^ := pTaiProp(p.optinfo)^;
  1723. insertllitem(asml,p,p.next,hp1);
  1724. incstate(pTaiProp(hp1.optinfo)^.regs[reg32(regcounter)].rstate,1);
  1725. updatestate(reg32(regcounter),hp1);
  1726. hp1 := Tai_Marker.Create(NoPropInfoStart);
  1727. insertllitem(asml,p,p.next,hp1);
  1728. Taicpu(p).loadreg(0,regcounter);
  1729. regcounter := reg32(regcounter);
  1730. allocregbetween(asml,regcounter,hp5,
  1731. tai(p.next.next));
  1732. end;
  1733. end;
  1734. Ch_ROp2:
  1735. if ((taicpu(p).opcode = A_CMP) or
  1736. (taicpu(p).opcode = A_TEST)) and
  1737. (taicpu(p).oper[1].typ = top_ref) then
  1738. begin
  1739. regcounter :=
  1740. memtoreg(taicpu(p),
  1741. Taicpu(p).oper[1].ref^,hp5);
  1742. if regcounter <> R_NO then
  1743. begin
  1744. Taicpu(p).loadreg(1,regcounter);
  1745. regcounter := reg32(regcounter);
  1746. allocregbetween(asml,regcounter,hp5,p);
  1747. incstate(pTaiProp(p.optinfo)^.regs[regcounter].rstate,1);
  1748. updatestate(regcounter,p);
  1749. end;
  1750. end;
  1751. Ch_MOp2:
  1752. if not(cs_littlesize in aktglobalswitches) and
  1753. (taicpu(p).oper[1].typ = top_ref) and
  1754. ((taicpu(p).opcode < A_BT) or
  1755. ((taicpu(p).opcode > A_IN) and
  1756. (taicpu(p).opcode < A_OUT)) or
  1757. (taicpu(p).opcode = A_PUSH) or
  1758. ((taicpu(p).opcode >= A_RCL) and
  1759. (taicpu(p).opcode <= A_XOR))) then
  1760. begin
  1761. regcounter :=
  1762. memtoreg(taicpu(p),
  1763. Taicpu(p).oper[1].ref^,hp5);
  1764. if (regcounter <> R_NO) (* and
  1765. (not getNextInstruction(p,hp1) or
  1766. (RegLoadedWithNewValue(reg32(regcounter),false,hp1) or
  1767. FindRegDealloc(reg32(regcounter),hp1))) *) then
  1768. begin
  1769. hp1 := Tai_Marker.Create(NoPropInfoEnd);
  1770. insertllitem(asml,p,p.next,hp1);
  1771. hp1 := taicpu.op_reg_ref(A_MOV,
  1772. regsize(regcounter),regcounter,
  1773. newreference(taicpu(p).oper[1].ref^));
  1774. new(pTaiprop(hp1.optinfo));
  1775. pTaiProp(hp1.optinfo)^ := pTaiProp(p.optinfo)^;
  1776. insertllitem(asml,p,p.next,hp1);
  1777. incstate(pTaiProp(hp1.optinfo)^.regs[reg32(regcounter)].rstate,1);
  1778. updatestate(reg32(regcounter),hp1);
  1779. hp1 := Tai_Marker.Create(NoPropInfoStart);
  1780. insertllitem(asml,p,p.next,hp1);
  1781. Taicpu(p).loadreg(1,regcounter);
  1782. regcounter := reg32(regcounter);
  1783. allocregbetween(asml,regcounter,hp5,
  1784. tai(p.next.next));
  1785. end;
  1786. end;
  1787. end;
  1788. end;
  1789. end;
  1790. End
  1791. End;
  1792. End;
  1793. GetNextInstruction(p, p);
  1794. End;
  1795. End;
  1796. function removeInstructs(asmL: TAAsmoutput; first, last: Tai): boolean;
  1797. { Removes the marked instructions and disposes the PTaiProps of the other }
  1798. { instructions }
  1799. Var
  1800. p, hp1: Tai;
  1801. nopropinfolevel: longint;
  1802. begin
  1803. removeInstructs := false;
  1804. p := First;
  1805. nopropinfolevel := 0;
  1806. While (p <> Last) Do
  1807. Begin
  1808. If (p.typ = ait_marker) and
  1809. (Tai_marker(p).kind = noPropInfoStart) then
  1810. begin
  1811. hp1 := Tai(p.next);
  1812. asmL.remove(p);
  1813. p.free;
  1814. nopropinfolevel := 1;
  1815. while (nopropinfolevel <> 0) do
  1816. begin
  1817. p := Tai(hp1.next);
  1818. {$ifndef noinstremove}
  1819. { allocregbetween can insert new ait_regalloc objects }
  1820. { without optinfo }
  1821. if (hp1.typ = ait_marker) then
  1822. begin
  1823. case Tai_marker(hp1).kind of
  1824. { they can be nested! }
  1825. noPropInfoStart: inc(nopropinfolevel);
  1826. noPropInfoEnd: dec(nopropinfolevel);
  1827. else
  1828. begin
  1829. hp1 := p;
  1830. continue;
  1831. end;
  1832. end;
  1833. asmL.remove(hp1);
  1834. hp1.free;
  1835. end
  1836. else if assigned(hp1.optinfo) then
  1837. if pTaiprop(hp1.optinfo)^.canBeRemoved then
  1838. begin
  1839. dispose(pTaiprop(hp1.optinfo));
  1840. hp1.optinfo := nil;
  1841. asmL.remove(hp1);
  1842. hp1.free;
  1843. end
  1844. else
  1845. {$endif noinstremove}
  1846. begin
  1847. dispose(pTaiprop(hp1.optinfo));
  1848. hp1.optinfo := nil;
  1849. end;
  1850. hp1 := p;
  1851. end;
  1852. end
  1853. else
  1854. {$ifndef noinstremove}
  1855. if assigned(p.optInfo) and
  1856. PTaiProp(p.optInfo)^.canBeRemoved then
  1857. begin
  1858. hp1 := Tai(p.next);
  1859. AsmL.Remove(p);
  1860. p.free;
  1861. p := hp1;
  1862. removeInstructs := true;
  1863. End
  1864. Else
  1865. {$endif noinstremove}
  1866. Begin
  1867. p.OptInfo := nil;
  1868. p := Tai(p.next);;
  1869. End;
  1870. End;
  1871. FreeMem(TaiPropBlock, NrOfTaiObjs*SizeOf(TTaiProp))
  1872. End;
  1873. function CSE(AsmL: TAAsmOutput; First, Last: Tai; pass: longint): boolean;
  1874. Begin
  1875. DoCSE(AsmL, First, Last, not(cs_slowoptimize in aktglobalswitches) or (pass >= 2),
  1876. not(cs_slowoptimize in aktglobalswitches) or (pass >= 1));
  1877. { register renaming }
  1878. if not(cs_slowoptimize in aktglobalswitches) or (pass > 0) then
  1879. doRenaming(asmL, first, last);
  1880. cse := removeInstructs(asmL, first, last);
  1881. End;
  1882. End.
  1883. {
  1884. $Log$
  1885. Revision 1.23 2001-12-04 15:58:13 jonas
  1886. * unnecessary loads of constants are now also remove by
  1887. removePrevNotUsedLoad()
  1888. Revision 1.22 2001/11/30 16:35:02 jonas
  1889. * added missing allocregbetween() call for a memtoreg() optimization
  1890. Revision 1.21 2001/10/27 10:20:43 jonas
  1891. + replace mem accesses to locations to which a reg was stored recently with that reg
  1892. Revision 1.20 2001/10/14 11:50:21 jonas
  1893. + also replace mem references in modify operands with regs
  1894. Revision 1.19 2001/10/12 13:58:05 jonas
  1895. + memory references are now replaced by register reads in "regular"
  1896. instructions (e.g. "addl ref1,%eax" will be replaced by "addl %ebx,%eax"
  1897. if %ebx contains ref1). Previously only complete load sequences were
  1898. optimized away, but not such small accesses in other instructions than
  1899. mov/movzx/movsx
  1900. Revision 1.18 2001/09/04 14:01:03 jonas
  1901. * commented out some inactive code in csopt386
  1902. + small improvement: lea is now handled the same as mov/zx/sx
  1903. Revision 1.17 2001/08/29 14:07:43 jonas
  1904. * the optimizer now keeps track of flags register usage. This fixes some
  1905. optimizer bugs with int64 calculations (because of the carry flag usage)
  1906. * fixed another bug which caused wrong optimizations with complex
  1907. array expressions
  1908. Revision 1.16 2001/08/26 13:36:55 florian
  1909. * some cg reorganisation
  1910. * some PPC updates
  1911. Revision 1.15 2001/04/06 16:24:38 jonas
  1912. * fixed bug due to short boolean evaluation
  1913. Revision 1.14 2001/04/02 21:20:36 peter
  1914. * resulttype rewrite
  1915. Revision 1.13 2001/01/10 08:52:40 michael
  1916. + Patch from jonas so 1.0.2 can be used to cycle
  1917. Revision 1.12 2001/01/07 15:51:17 jonas
  1918. * fixed crashing bug to due previous changes
  1919. Revision 1.11 2001/01/06 23:35:05 jonas
  1920. * fixed webbug 1323
  1921. Revision 1.10 2000/12/25 00:07:31 peter
  1922. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1923. tlinkedlist objects)
  1924. Revision 1.9 2000/12/05 09:33:42 jonas
  1925. * when searching for constants in registers, the returned register
  1926. sometimes didn't have the same size as the requested size
  1927. Revision 1.8 2000/11/29 00:30:43 florian
  1928. * unused units removed from uses clause
  1929. * some changes for widestrings
  1930. Revision 1.7 2000/11/28 16:32:11 jonas
  1931. + support for optimizing simple sequences with div/idiv/mul opcodes
  1932. Revision 1.6 2000/11/14 12:17:34 jonas
  1933. * fixed some bugs in checksequence
  1934. Revision 1.5 2000/11/09 12:34:44 jonas
  1935. * fixed range check error
  1936. Revision 1.4 2000/11/03 17:53:24 jonas
  1937. * some small improvements
  1938. Revision 1.3 2000/11/01 22:53:30 jonas
  1939. * register contents were not cleared if there was only 1 instruction
  1940. between de previous sequence and the current one
  1941. Revision 1.2 2000/10/24 10:40:53 jonas
  1942. + register renaming ("fixes" bug1088)
  1943. * changed command line options meanings for optimizer:
  1944. O2 now means peepholopts, CSE and register renaming in 1 pass
  1945. O3 is the same, but repeated until no further optimizations are
  1946. possible or until 5 passes have been done (to avoid endless loops)
  1947. * changed aopt386 so it does this looping
  1948. * added some procedures from csopt386 to the interface because they're
  1949. used by rropt386 as well
  1950. * some changes to csopt386 and daopt386 so that newly added instructions
  1951. by the CSE get optimizer info (they were simply skipped previously),
  1952. this fixes some bugs
  1953. Revision 1.1 2000/10/15 09:47:43 peter
  1954. * moved to i386/
  1955. Revision 1.14 2000/09/30 13:07:23 jonas
  1956. * fixed support for -Or with new features of CSE
  1957. Revision 1.13 2000/09/29 23:14:45 jonas
  1958. * search much further back for CSE sequences (non-conflicting stores are
  1959. now passed)
  1960. * remove more unnecessary loads of registers (especially the self pointer)
  1961. Revision 1.12 2000/09/26 11:49:41 jonas
  1962. * writes to register variables and to the self pointer now also count as
  1963. memore writes
  1964. Revision 1.11 2000/09/25 09:50:29 jonas
  1965. - removed TP conditional code
  1966. Revision 1.10 2000/09/24 15:06:14 peter
  1967. * use defines.inc
  1968. Revision 1.9 2000/09/22 15:01:59 jonas
  1969. * fixed some bugs in the previous improvements: in some cases, esi was
  1970. still being replaced before a conditional jump (the code that
  1971. detected conditional jumps sometimes skipped over them)
  1972. Revision 1.8 2000/09/20 15:00:58 jonas
  1973. + much improved CSE: the CSE now searches further back for sequences it
  1974. can reuse. After I've also implemented register renaming, the effect
  1975. should be even better (afaik web bug 1088 will then even be optimized
  1976. properly). I don't know about the slow down factor this adds. Maybe
  1977. a new optimization level should be introduced?
  1978. Revision 1.7 2000/08/25 19:40:45 jonas
  1979. * refined previous fix a bit, some instructions weren't being removed
  1980. while they could (merged from fixes branch)
  1981. * made checksequence a bit faster
  1982. Revision 1.6 2000/08/23 12:55:10 jonas
  1983. * fix for web bug 1112 and a bit of clean up in csopt386 (merged from
  1984. fixes branch)
  1985. Revision 1.5 2000/08/04 20:08:03 jonas
  1986. * improved detection of range of instructions which use a register
  1987. (merged from fixes branch)
  1988. Revision 1.4 2000/07/21 15:19:54 jonas
  1989. * daopt386: changes to getnextinstruction/getlastinstruction so they
  1990. ignore labels who have is_addr set
  1991. + daopt386/csopt386: remove loads of registers which are overwritten
  1992. before their contents are used (especially usefull for removing superfluous
  1993. maybe_loadself outputs and push/pops transformed by below optimization
  1994. + popt386: transform pop/pop/pop/.../push/push/push to sequences of
  1995. 'movl x(%esp),%reg' (only active when compiling a go32v2 compiler
  1996. currently because I don't know whether it's safe to do this under Win32/
  1997. Linux (because of problems we had when using esp as frame pointer on
  1998. those os'es)
  1999. Revision 1.3 2000/07/14 05:11:48 michael
  2000. + Patch to 1.1
  2001. Revision 1.2 2000/07/13 11:32:39 michael
  2002. + removed logs
  2003. }