csopt386.pas 75 KB

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