csopt386.pas 61 KB

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