csopt386.pas 83 KB

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