csopt386.pas 87 KB

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