csopt386.pas 90 KB

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