popt386.pas 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl and Jonas Maebe
  4. This unit contains the peephole optimizer.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit POpt386;
  19. {$i fpcdefs.inc}
  20. Interface
  21. Uses Aasmbase,aasmtai,aasmcpu,verbose;
  22. Procedure PrePeepHoleOpts(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  23. Procedure PeepHoleOptPass1(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  24. Procedure PeepHoleOptPass2(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  25. Procedure PostPeepHoleOpts(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  26. Implementation
  27. Uses
  28. globtype,systems,
  29. globals,cgbase,
  30. symsym,symdef,
  31. {$ifdef finaldestdebug}
  32. cobjects,
  33. {$endif finaldestdebug}
  34. cpuinfo,cpubase,DAOpt386,cginfo,rgobj;
  35. Function RegUsedAfterInstruction(Reg: Tregister; p: Tai; Var UsedRegs: TRegSet): Boolean;
  36. Begin
  37. if reg.enum>lastreg then
  38. internalerror(200301081);
  39. reg := reg32(reg);
  40. UpdateUsedRegs(UsedRegs, Tai(p.Next));
  41. RegUsedAfterInstruction :=
  42. (Reg.enum in UsedRegs) and
  43. (not(getNextInstruction(p,p)) or
  44. not(regLoadedWithNewValue(reg,false,p)));
  45. End;
  46. function doFpuLoadStoreOpt(asmL: TAAsmoutput; var p: Tai): boolean;
  47. { returns true if a "continue" should be done after this optimization }
  48. var hp1, hp2: Tai;
  49. begin
  50. doFpuLoadStoreOpt := false;
  51. if (Taicpu(p).oper[0].typ = top_ref) and
  52. getNextInstruction(p, hp1) and
  53. (hp1.typ = ait_instruction) and
  54. (((Taicpu(hp1).opcode = A_FLD) and
  55. (Taicpu(p).opcode = A_FSTP)) or
  56. ((Taicpu(p).opcode = A_FISTP) and
  57. (Taicpu(hp1).opcode = A_FILD))) and
  58. (Taicpu(hp1).oper[0].typ = top_ref) and
  59. (Taicpu(hp1).opsize = Taicpu(p).opsize) and
  60. refsEqual(Taicpu(p).oper[0].ref^, Taicpu(hp1).oper[0].ref^) then
  61. begin
  62. if getNextInstruction(hp1, hp2) and
  63. (hp2.typ = ait_instruction) and
  64. ((Taicpu(hp2).opcode = A_LEAVE) or
  65. (Taicpu(hp2).opcode = A_RET)) and
  66. (Taicpu(p).oper[0].ref^.Base.enum = current_procinfo.FramePointer.enum) and
  67. (Taicpu(p).oper[0].ref^.Offset >= tvarsym(current_procinfo.procdef.funcretsym).adjusted_address) and
  68. (Taicpu(p).oper[0].ref^.Index.enum = R_NO) then
  69. begin
  70. asml.remove(p);
  71. asml.remove(hp1);
  72. p.free;
  73. hp1.free;
  74. p := hp2;
  75. removeLastDeallocForFuncRes(asmL, p);
  76. doFPULoadStoreOpt := true;
  77. end
  78. else
  79. { fst can't store an extended value! }
  80. if (Taicpu(p).opsize <> S_FX) and
  81. (Taicpu(p).opsize <> S_IQ) then
  82. begin
  83. if (Taicpu(p).opcode = A_FSTP) then
  84. Taicpu(p).opcode := A_FST
  85. else Taicpu(p).opcode := A_FIST;
  86. asml.remove(hp1);
  87. hp1.free;
  88. end
  89. end;
  90. end;
  91. Procedure PrePeepHoleOpts(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  92. var
  93. p,hp1: Tai;
  94. l: Aword;
  95. tmpRef: treference;
  96. Begin
  97. P := BlockStart;
  98. While (P <> BlockEnd) Do
  99. Begin
  100. Case p.Typ Of
  101. Ait_Instruction:
  102. Begin
  103. Case Taicpu(p).opcode Of
  104. A_IMUL:
  105. {changes certain "imul const, %reg"'s to lea sequences}
  106. Begin
  107. If (Taicpu(p).oper[0].typ = Top_Const) And
  108. (Taicpu(p).oper[1].typ = Top_Reg) And
  109. (Taicpu(p).opsize = S_L) Then
  110. If (Taicpu(p).oper[0].val = 1) Then
  111. If (Taicpu(p).oper[2].typ = Top_None) Then
  112. {remove "imul $1, reg"}
  113. Begin
  114. hp1 := Tai(p.Next);
  115. asml.Remove(p);
  116. p.free;
  117. p := hp1;
  118. Continue;
  119. End
  120. Else
  121. {change "imul $1, reg1, reg2" to "mov reg1, reg2"}
  122. Begin
  123. hp1 := Taicpu.Op_Reg_Reg(A_MOV, S_L, Taicpu(p).oper[1].reg,Taicpu(p).oper[2].reg);
  124. InsertLLItem(AsmL, p.previous, p.next, hp1);
  125. p.free;
  126. p := hp1;
  127. End
  128. Else If
  129. ((Taicpu(p).oper[2].typ = Top_Reg) or
  130. (Taicpu(p).oper[2].typ = Top_None)) And
  131. (aktoptprocessor < ClassP6) And
  132. (Taicpu(p).oper[0].val <= 12) And
  133. Not(CS_LittleSize in aktglobalswitches) And
  134. (Not(GetNextInstruction(p, hp1)) Or
  135. {GetNextInstruction(p, hp1) And}
  136. Not((Tai(hp1).typ = ait_instruction) And
  137. ((Taicpu(hp1).opcode=A_Jcc) and
  138. (Taicpu(hp1).condition in [C_O,C_NO]))))
  139. Then
  140. Begin
  141. reference_reset_old(tmpref);
  142. Case Taicpu(p).oper[0].val Of
  143. 3: Begin
  144. {imul 3, reg1, reg2 to
  145. lea (reg1,reg1,2), reg2
  146. imul 3, reg1 to
  147. lea (reg1,reg1,2), reg1}
  148. TmpRef.base := Taicpu(p).oper[1].reg;
  149. TmpRef.Index := Taicpu(p).oper[1].reg;
  150. TmpRef.ScaleFactor := 2;
  151. If (Taicpu(p).oper[2].typ = Top_None) Then
  152. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg)
  153. Else
  154. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  155. InsertLLItem(AsmL,p.previous, p.next, hp1);
  156. p.free;
  157. p := hp1;
  158. End;
  159. 5: Begin
  160. {imul 5, reg1, reg2 to
  161. lea (reg1,reg1,4), reg2
  162. imul 5, reg1 to
  163. lea (reg1,reg1,4), reg1}
  164. TmpRef.base := Taicpu(p).oper[1].reg;
  165. TmpRef.Index := Taicpu(p).oper[1].reg;
  166. TmpRef.ScaleFactor := 4;
  167. If (Taicpu(p).oper[2].typ = Top_None) Then
  168. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg)
  169. Else
  170. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  171. InsertLLItem(AsmL,p.previous, p.next, hp1);
  172. p.free;
  173. p := hp1;
  174. End;
  175. 6: Begin
  176. {imul 6, reg1, reg2 to
  177. lea (,reg1,2), reg2
  178. lea (reg2,reg1,4), reg2
  179. imul 6, reg1 to
  180. lea (reg1,reg1,2), reg1
  181. add reg1, reg1}
  182. If (aktoptprocessor <= Class386)
  183. Then
  184. Begin
  185. TmpRef.Index := Taicpu(p).oper[1].reg;
  186. If (Taicpu(p).oper[2].typ = Top_Reg)
  187. Then
  188. Begin
  189. TmpRef.base := Taicpu(p).oper[2].reg;
  190. TmpRef.ScaleFactor := 4;
  191. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  192. End
  193. Else
  194. Begin
  195. hp1 := Taicpu.op_reg_reg(A_ADD, S_L,
  196. Taicpu(p).oper[1].reg,Taicpu(p).oper[1].reg);
  197. End;
  198. InsertLLItem(AsmL,p, p.next, hp1);
  199. reference_reset_old(tmpref);
  200. TmpRef.Index := Taicpu(p).oper[1].reg;
  201. TmpRef.ScaleFactor := 2;
  202. If (Taicpu(p).oper[2].typ = Top_Reg)
  203. Then
  204. Begin
  205. TmpRef.base.enum := R_NO;
  206. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef,
  207. Taicpu(p).oper[2].reg);
  208. End
  209. Else
  210. Begin
  211. TmpRef.base := Taicpu(p).oper[1].reg;
  212. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  213. End;
  214. InsertLLItem(AsmL,p.previous, p.next, hp1);
  215. p.free;
  216. p := Tai(hp1.next);
  217. End
  218. End;
  219. 9: Begin
  220. {imul 9, reg1, reg2 to
  221. lea (reg1,reg1,8), reg2
  222. imul 9, reg1 to
  223. lea (reg1,reg1,8), reg1}
  224. TmpRef.base := Taicpu(p).oper[1].reg;
  225. TmpRef.Index := Taicpu(p).oper[1].reg;
  226. TmpRef.ScaleFactor := 8;
  227. If (Taicpu(p).oper[2].typ = Top_None) Then
  228. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg)
  229. Else
  230. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  231. InsertLLItem(AsmL,p.previous, p.next, hp1);
  232. p.free;
  233. p := hp1;
  234. End;
  235. 10: Begin
  236. {imul 10, reg1, reg2 to
  237. lea (reg1,reg1,4), reg2
  238. add reg2, reg2
  239. imul 10, reg1 to
  240. lea (reg1,reg1,4), reg1
  241. add reg1, reg1}
  242. If (aktoptprocessor <= Class386) Then
  243. Begin
  244. If (Taicpu(p).oper[2].typ = Top_Reg) Then
  245. hp1 := Taicpu.op_reg_reg(A_ADD, S_L,
  246. Taicpu(p).oper[2].reg,Taicpu(p).oper[2].reg)
  247. Else
  248. hp1 := Taicpu.op_reg_reg(A_ADD, S_L,
  249. Taicpu(p).oper[1].reg,Taicpu(p).oper[1].reg);
  250. InsertLLItem(AsmL,p, p.next, hp1);
  251. TmpRef.base := Taicpu(p).oper[1].reg;
  252. TmpRef.Index := Taicpu(p).oper[1].reg;
  253. TmpRef.ScaleFactor := 4;
  254. If (Taicpu(p).oper[2].typ = Top_Reg)
  255. Then
  256. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg)
  257. Else
  258. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  259. InsertLLItem(AsmL,p.previous, p.next, hp1);
  260. p.free;
  261. p := Tai(hp1.next);
  262. End
  263. End;
  264. 12: Begin
  265. {imul 12, reg1, reg2 to
  266. lea (,reg1,4), reg2
  267. lea (,reg1,8) reg2
  268. imul 12, reg1 to
  269. lea (reg1,reg1,2), reg1
  270. lea (,reg1,4), reg1}
  271. If (aktoptprocessor <= Class386)
  272. Then
  273. Begin
  274. TmpRef.Index := Taicpu(p).oper[1].reg;
  275. If (Taicpu(p).oper[2].typ = Top_Reg) Then
  276. Begin
  277. TmpRef.base := Taicpu(p).oper[2].reg;
  278. TmpRef.ScaleFactor := 8;
  279. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  280. End
  281. Else
  282. Begin
  283. TmpRef.base.enum := R_NO;
  284. TmpRef.ScaleFactor := 4;
  285. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  286. End;
  287. InsertLLItem(AsmL,p, p.next, hp1);
  288. reference_reset_old(tmpref);
  289. TmpRef.Index := Taicpu(p).oper[1].reg;
  290. If (Taicpu(p).oper[2].typ = Top_Reg) Then
  291. Begin
  292. TmpRef.base.enum := R_NO;
  293. TmpRef.ScaleFactor := 4;
  294. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  295. End
  296. Else
  297. Begin
  298. TmpRef.base := Taicpu(p).oper[1].reg;
  299. TmpRef.ScaleFactor := 2;
  300. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  301. End;
  302. InsertLLItem(AsmL,p.previous, p.next, hp1);
  303. p.free;
  304. p := Tai(hp1.next);
  305. End
  306. End
  307. End;
  308. End;
  309. End;
  310. A_SAR, A_SHR:
  311. {changes the code sequence
  312. shr/sar const1, x
  313. shl const2, x
  314. to either "sar/and", "shl/and" or just "and" depending on const1 and const2}
  315. Begin
  316. If GetNextInstruction(p, hp1) And
  317. (Tai(hp1).typ = ait_instruction) and
  318. (Taicpu(hp1).opcode = A_SHL) and
  319. (Taicpu(p).oper[0].typ = top_const) and
  320. (Taicpu(hp1).oper[0].typ = top_const) and
  321. (Taicpu(hp1).opsize = Taicpu(p).opsize) And
  322. (Taicpu(hp1).oper[1].typ = Taicpu(p).oper[1].typ) And
  323. OpsEqual(Taicpu(hp1).oper[1], Taicpu(p).oper[1])
  324. Then
  325. If (Taicpu(p).oper[0].val > Taicpu(hp1).oper[0].val) And
  326. Not(CS_LittleSize In aktglobalswitches)
  327. Then
  328. { shr/sar const1, %reg
  329. shl const2, %reg
  330. with const1 > const2 }
  331. Begin
  332. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val-Taicpu(hp1).oper[0].val);
  333. Taicpu(hp1).opcode := A_AND;
  334. l := (1 shl (Taicpu(hp1).oper[0].val)) - 1;
  335. Case Taicpu(p).opsize Of
  336. S_L: Taicpu(hp1).LoadConst(0,l Xor aword($ffffffff));
  337. S_B: Taicpu(hp1).LoadConst(0,l Xor $ff);
  338. S_W: Taicpu(hp1).LoadConst(0,l Xor $ffff);
  339. End;
  340. End
  341. Else
  342. If (Taicpu(p).oper[0].val<Taicpu(hp1).oper[0].val) And
  343. Not(CS_LittleSize In aktglobalswitches)
  344. Then
  345. { shr/sar const1, %reg
  346. shl const2, %reg
  347. with const1 < const2 }
  348. Begin
  349. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val-Taicpu(p).oper[0].val);
  350. Taicpu(p).opcode := A_AND;
  351. l := (1 shl (Taicpu(p).oper[0].val))-1;
  352. Case Taicpu(p).opsize Of
  353. S_L: Taicpu(p).LoadConst(0,l Xor aword($ffffffff));
  354. S_B: Taicpu(p).LoadConst(0,l Xor $ff);
  355. S_W: Taicpu(p).LoadConst(0,l Xor $ffff);
  356. End;
  357. End
  358. Else
  359. { shr/sar const1, %reg
  360. shl const2, %reg
  361. with const1 = const2 }
  362. if (Taicpu(p).oper[0].val = Taicpu(hp1).oper[0].val) then
  363. Begin
  364. Taicpu(p).opcode := A_AND;
  365. l := (1 shl (Taicpu(p).oper[0].val))-1;
  366. Case Taicpu(p).opsize Of
  367. S_B: Taicpu(p).LoadConst(0,l Xor $ff);
  368. S_W: Taicpu(p).LoadConst(0,l Xor $ffff);
  369. S_L: Taicpu(p).LoadConst(0,l Xor aword($ffffffff));
  370. End;
  371. asml.remove(hp1);
  372. hp1.free;
  373. End;
  374. End;
  375. A_XOR:
  376. If (Taicpu(p).oper[0].typ = top_reg) And
  377. (Taicpu(p).oper[1].typ = top_reg) And
  378. (Taicpu(p).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) then
  379. { temporarily change this to 'mov reg,0' to make it easier }
  380. { for the CSE. Will be changed back in pass 2 }
  381. begin
  382. Taicpu(p).opcode := A_MOV;
  383. Taicpu(p).loadconst(0,0);
  384. end;
  385. End;
  386. End;
  387. End;
  388. p := Tai(p.next)
  389. End;
  390. End;
  391. Procedure PeepHoleOptPass1(Asml: TAAsmOutput; BlockStart, BlockEnd: Tai);
  392. {First pass of peepholeoptimizations}
  393. Var
  394. l,l1 : longint;
  395. p,hp1,hp2 : Tai;
  396. hp3,hp4: Tai;
  397. TmpRef: TReference;
  398. UsedRegs, TmpUsedRegs: TRegSet;
  399. TmpBool1, TmpBool2: Boolean;
  400. r:Tregister;
  401. Function SkipLabels(hp: Tai; var hp2: Tai): boolean;
  402. {skips all labels and returns the next "real" instruction}
  403. Begin
  404. While assigned(hp.next) and
  405. (Tai(hp.next).typ In SkipInstr + [ait_label,ait_align]) Do
  406. hp := Tai(hp.next);
  407. If assigned(hp.next) Then
  408. Begin
  409. SkipLabels := True;
  410. hp2 := Tai(hp.next)
  411. End
  412. Else
  413. Begin
  414. hp2 := hp;
  415. SkipLabels := False
  416. End;
  417. End;
  418. function GetFinalDestination(AsmL: TAAsmOutput; hp: Taicpu; level: longint): boolean;
  419. {traces sucessive jumps to their final destination and sets it, e.g.
  420. je l1 je l3
  421. <code> <code>
  422. l1: becomes l1:
  423. je l2 je l3
  424. <code> <code>
  425. l2: l2:
  426. jmp l3 jmp l3
  427. the level parameter denotes how deeep we have already followed the jump,
  428. to avoid endless loops with constructs such as "l5: ; jmp l5" }
  429. Var p1, p2: Tai;
  430. l: tasmlabel;
  431. Function FindAnyLabel(hp: Tai; var l: tasmlabel): Boolean;
  432. Begin
  433. FindAnyLabel := false;
  434. While assigned(hp.next) and
  435. (Tai(hp.next).typ In (SkipInstr+[ait_align])) Do
  436. hp := Tai(hp.next);
  437. If assigned(hp.next) and
  438. (Tai(hp.next).typ = ait_label) Then
  439. Begin
  440. FindAnyLabel := true;
  441. l := Tai_label(hp.next).l;
  442. End
  443. End;
  444. Begin
  445. if level > 20 then
  446. exit;
  447. GetfinalDestination := false;
  448. p1 := dfa.getlabelwithsym(tasmlabel(hp.oper[0].sym));
  449. if assigned(p1) then
  450. begin
  451. SkipLabels(p1,p1);
  452. If (Tai(p1).typ = ait_instruction) and
  453. (Taicpu(p1).is_jmp) Then
  454. If { the next instruction after the label where the jump hp arrives}
  455. { is unconditional or of the same type as hp, so continue }
  456. (Taicpu(p1).condition in [C_None,hp.condition]) or
  457. { the next instruction after the label where the jump hp arrives}
  458. { is the opposite of hp (so this one is never taken), but after }
  459. { that one there is a branch that will be taken, so perform a }
  460. { little hack: set p1 equal to this instruction (that's what the}
  461. { last SkipLabels is for, only works with short bool evaluation)}
  462. ((Taicpu(p1).condition = inverse_cond[hp.condition]) and
  463. SkipLabels(p1,p2) and
  464. (p2.typ = ait_instruction) and
  465. (Taicpu(p2).is_jmp) and
  466. (Taicpu(p2).condition in [C_None,hp.condition]) and
  467. SkipLabels(p1,p1)) Then
  468. Begin
  469. { quick check for loops of the form "l5: ; jmp l5 }
  470. if (tasmlabel(Taicpu(p1).oper[0].sym).labelnr =
  471. tasmlabel(hp.oper[0].sym).labelnr) then
  472. exit;
  473. if not GetFinalDestination(asml, Taicpu(p1),succ(level)) then
  474. exit;
  475. tasmlabel(hp.oper[0].sym).decrefs;
  476. hp.oper[0].sym:=Taicpu(p1).oper[0].sym;
  477. tasmlabel(hp.oper[0].sym).increfs;
  478. End
  479. Else
  480. If (Taicpu(p1).condition = inverse_cond[hp.condition]) then
  481. if not FindAnyLabel(p1,l) then
  482. begin
  483. {$ifdef finaldestdebug}
  484. insertllitem(asml,p1,p1.next,tai_comment.Create(
  485. strpnew('previous label inserted'))));
  486. {$endif finaldestdebug}
  487. objectlibrary.getlabel(l);
  488. insertllitem(asml,p1,p1.next,Tai_label.Create(l));
  489. tasmlabel(Taicpu(hp).oper[0].sym).decrefs;
  490. hp.oper[0].sym := l;
  491. l.increfs;
  492. { this won't work, since the new label isn't in the labeltable }
  493. { so it will fail the rangecheck. Labeltable should become a }
  494. { hashtable to support this: }
  495. { GetFinalDestination(asml, hp); }
  496. end
  497. else
  498. begin
  499. {$ifdef finaldestdebug}
  500. insertllitem(asml,p1,p1.next,tai_comment.Create(
  501. strpnew('next label reused'))));
  502. {$endif finaldestdebug}
  503. l.increfs;
  504. hp.oper[0].sym := l;
  505. if not GetFinalDestination(asml, hp,succ(level)) then
  506. exit;
  507. end;
  508. End;
  509. GetFinalDestination := true;
  510. End;
  511. Function DoSubAddOpt(var p: Tai): Boolean;
  512. Begin
  513. DoSubAddOpt := False;
  514. If GetLastInstruction(p, hp1) And
  515. (hp1.typ = ait_instruction) And
  516. (Taicpu(hp1).opsize = Taicpu(p).opsize) then
  517. Case Taicpu(hp1).opcode Of
  518. A_DEC:
  519. If (Taicpu(hp1).oper[0].typ = top_reg) And
  520. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  521. Begin
  522. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val+1);
  523. asml.Remove(hp1);
  524. hp1.free;
  525. End;
  526. A_SUB:
  527. If (Taicpu(hp1).oper[0].typ = top_const) And
  528. (Taicpu(hp1).oper[1].typ = top_reg) And
  529. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  530. Begin
  531. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val+Taicpu(hp1).oper[0].val);
  532. asml.Remove(hp1);
  533. hp1.free;
  534. End;
  535. A_ADD:
  536. If (Taicpu(hp1).oper[0].typ = top_const) And
  537. (Taicpu(hp1).oper[1].typ = top_reg) And
  538. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  539. Begin
  540. Taicpu(p).LoadConst(0,AWord(int64(Taicpu(p).oper[0].val)-int64(Taicpu(hp1).oper[0].val)));
  541. asml.Remove(hp1);
  542. hp1.free;
  543. If (Taicpu(p).oper[0].val = 0) Then
  544. Begin
  545. hp1 := Tai(p.next);
  546. asml.Remove(p);
  547. p.free;
  548. If Not GetLastInstruction(hp1, p) Then
  549. p := hp1;
  550. DoSubAddOpt := True;
  551. End
  552. End;
  553. End;
  554. End;
  555. Begin
  556. P := BlockStart;
  557. UsedRegs := [];
  558. While (P <> BlockEnd) Do
  559. Begin
  560. UpDateUsedRegs(UsedRegs, Tai(p.next));
  561. Case p.Typ Of
  562. ait_instruction:
  563. Begin
  564. { Handle Jmp Optimizations }
  565. if Taicpu(p).is_jmp then
  566. begin
  567. {the following if-block removes all code between a jmp and the next label,
  568. because it can never be executed}
  569. If (Taicpu(p).opcode = A_JMP) Then
  570. Begin
  571. While GetNextInstruction(p, hp1) and
  572. (hp1.typ <> ait_label) do
  573. If not(hp1.typ in ([ait_label,ait_align]+skipinstr)) Then
  574. Begin
  575. asml.Remove(hp1);
  576. hp1.free;
  577. End
  578. else break;
  579. End;
  580. { remove jumps to a label coming right after them }
  581. If GetNextInstruction(p, hp1) then
  582. Begin
  583. if FindLabel(tasmlabel(Taicpu(p).oper[0].sym), hp1) and
  584. {$warning FIXME removing the first instruction fails}
  585. (p<>blockstart) then
  586. Begin
  587. hp2:=Tai(hp1.next);
  588. asml.remove(p);
  589. p.free;
  590. p:=hp2;
  591. continue;
  592. end
  593. Else
  594. Begin
  595. if hp1.typ = ait_label then
  596. SkipLabels(hp1,hp1);
  597. If (Tai(hp1).typ=ait_instruction) and
  598. (Taicpu(hp1).opcode=A_JMP) and
  599. GetNextInstruction(hp1, hp2) And
  600. FindLabel(tasmlabel(Taicpu(p).oper[0].sym), hp2)
  601. Then
  602. Begin
  603. if Taicpu(p).opcode=A_Jcc then
  604. Taicpu(p).condition:=inverse_cond[Taicpu(p).condition]
  605. else
  606. begin
  607. GetFinalDestination(asml, Taicpu(p),0);
  608. p:=Tai(p.next);
  609. continue;
  610. end;
  611. Tai_label(hp2).l.decrefs;
  612. Taicpu(p).oper[0].sym:=Taicpu(hp1).oper[0].sym;
  613. Taicpu(p).oper[0].sym.increfs;
  614. asml.remove(hp1);
  615. hp1.free;
  616. GetFinalDestination(asml, Taicpu(p),0);
  617. end
  618. else
  619. GetFinalDestination(asml, Taicpu(p),0);
  620. end;
  621. end;
  622. end
  623. else
  624. { All other optimizes }
  625. begin
  626. For l := 0 to 2 Do
  627. If (Taicpu(p).oper[l].typ = top_ref) Then
  628. With Taicpu(p).oper[l].ref^ Do
  629. Begin
  630. If (base.enum = R_NO) And
  631. (index.enum <> R_NO) And
  632. (scalefactor in [0,1])
  633. Then
  634. Begin
  635. base := index;
  636. index.enum := R_NO
  637. End
  638. End;
  639. Case Taicpu(p).opcode Of
  640. A_AND:
  641. Begin
  642. If (Taicpu(p).oper[0].typ = top_const) And
  643. (Taicpu(p).oper[1].typ = top_reg) And
  644. GetNextInstruction(p, hp1) And
  645. (Tai(hp1).typ = ait_instruction) And
  646. (Taicpu(hp1).opcode = A_AND) And
  647. (Taicpu(hp1).oper[0].typ = top_const) And
  648. (Taicpu(hp1).oper[1].typ = top_reg) And
  649. (Taicpu(p).oper[1].reg.enum = Taicpu(hp1).oper[1].reg.enum)
  650. Then
  651. {change "and const1, reg; and const2, reg" to "and (const1 and const2), reg"}
  652. Begin
  653. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val And Taicpu(hp1).oper[0].val);
  654. asml.Remove(hp1);
  655. hp1.free;
  656. End
  657. Else
  658. {change "and x, reg; jxx" to "test x, reg", if reg is deallocated before the
  659. jump, but only if it's a conditional jump (PFV) }
  660. If (Taicpu(p).oper[1].typ = top_reg) And
  661. GetNextInstruction(p, hp1) And
  662. (hp1.typ = ait_instruction) And
  663. (Taicpu(hp1).is_jmp) and
  664. (Taicpu(hp1).opcode<>A_JMP) and
  665. Not(Taicpu(p).oper[1].reg.enum in UsedRegs) Then
  666. Taicpu(p).opcode := A_TEST;
  667. End;
  668. A_CMP:
  669. Begin
  670. If (Taicpu(p).oper[0].typ = top_const) And
  671. (Taicpu(p).oper[1].typ in [top_reg,top_ref]) And
  672. (Taicpu(p).oper[0].val = 0) and
  673. GetNextInstruction(p, hp1) And
  674. (hp1.typ = ait_instruction) And
  675. (Taicpu(hp1).is_jmp) and
  676. (Taicpu(hp1).opcode=A_Jcc) and
  677. (Taicpu(hp1).condition in [C_LE,C_BE]) and
  678. GetNextInstruction(hp1,hp2) and
  679. (hp2.typ = ait_instruction) and
  680. (Taicpu(hp2).opcode = A_DEC) And
  681. OpsEqual(Taicpu(hp2).oper[0],Taicpu(p).oper[1]) And
  682. GetNextInstruction(hp2, hp3) And
  683. (hp3.typ = ait_instruction) and
  684. (Taicpu(hp3).is_jmp) and
  685. (Taicpu(hp3).opcode = A_JMP) And
  686. GetNextInstruction(hp3, hp4) And
  687. FindLabel(tasmlabel(Taicpu(hp1).oper[0].sym),hp4) Then
  688. Begin
  689. Taicpu(hp2).Opcode := A_SUB;
  690. Taicpu(hp2).Loadoper(1,Taicpu(hp2).oper[0]);
  691. Taicpu(hp2).LoadConst(0,1);
  692. Taicpu(hp2).ops:=2;
  693. Taicpu(hp3).Opcode := A_Jcc;
  694. Case Taicpu(hp1).condition of
  695. C_LE: Taicpu(hp3).condition := C_GE;
  696. C_BE: Taicpu(hp3).condition := C_AE;
  697. End;
  698. asml.Remove(p);
  699. asml.Remove(hp1);
  700. p.free;
  701. hp1.free;
  702. p := hp2;
  703. continue;
  704. End
  705. End;
  706. A_FLD:
  707. Begin
  708. If (Taicpu(p).oper[0].typ = top_reg) And
  709. GetNextInstruction(p, hp1) And
  710. (hp1.typ = Ait_Instruction) And
  711. (Taicpu(hp1).oper[0].typ = top_reg) And
  712. (Taicpu(hp1).oper[1].typ = top_reg) And
  713. (Taicpu(hp1).oper[0].reg.enum = R_ST) And
  714. (Taicpu(hp1).oper[1].reg.enum = R_ST1) Then
  715. { change to
  716. fld reg fxxx reg,st
  717. fxxxp st, st1 (hp1)
  718. Remark: non commutative operations must be reversed!
  719. }
  720. begin
  721. Case Taicpu(hp1).opcode Of
  722. A_FMULP,A_FADDP,
  723. A_FSUBP,A_FDIVP,A_FSUBRP,A_FDIVRP:
  724. begin
  725. Case Taicpu(hp1).opcode Of
  726. A_FADDP: Taicpu(hp1).opcode := A_FADD;
  727. A_FMULP: Taicpu(hp1).opcode := A_FMUL;
  728. A_FSUBP: Taicpu(hp1).opcode := A_FSUBR;
  729. A_FSUBRP: Taicpu(hp1).opcode := A_FSUB;
  730. A_FDIVP: Taicpu(hp1).opcode := A_FDIVR;
  731. A_FDIVRP: Taicpu(hp1).opcode := A_FDIV;
  732. End;
  733. Taicpu(hp1).oper[0].reg := Taicpu(p).oper[0].reg;
  734. Taicpu(hp1).oper[1].reg.enum := R_ST;
  735. asml.Remove(p);
  736. p.free;
  737. p := hp1;
  738. Continue;
  739. end;
  740. end;
  741. end
  742. else
  743. If (Taicpu(p).oper[0].typ = top_ref) And
  744. GetNextInstruction(p, hp2) And
  745. (hp2.typ = Ait_Instruction) And
  746. (Taicpu(hp2).oper[0].typ = top_reg) And
  747. (Taicpu(hp2).oper[1].typ = top_reg) And
  748. (Taicpu(p).opsize in [S_FS, S_FL]) And
  749. (Taicpu(hp2).oper[0].reg.enum = R_ST) And
  750. (Taicpu(hp2).oper[1].reg.enum = R_ST1) Then
  751. If GetLastInstruction(p, hp1) And
  752. (hp1.typ = Ait_Instruction) And
  753. ((Taicpu(hp1).opcode = A_FLD) Or
  754. (Taicpu(hp1).opcode = A_FST)) And
  755. (Taicpu(hp1).opsize = Taicpu(p).opsize) And
  756. (Taicpu(hp1).oper[0].typ = top_ref) And
  757. RefsEqual(Taicpu(p).oper[0].ref^, Taicpu(hp1).oper[0].ref^) Then
  758. If ((Taicpu(hp2).opcode = A_FMULP) Or
  759. (Taicpu(hp2).opcode = A_FADDP)) Then
  760. { change to
  761. fld/fst mem1 (hp1) fld/fst mem1
  762. fld mem1 (p) fadd/
  763. faddp/ fmul st, st
  764. fmulp st, st1 (hp2) }
  765. Begin
  766. asml.Remove(p);
  767. p.free;
  768. p := hp1;
  769. If (Taicpu(hp2).opcode = A_FADDP) Then
  770. Taicpu(hp2).opcode := A_FADD
  771. Else
  772. Taicpu(hp2).opcode := A_FMUL;
  773. Taicpu(hp2).oper[1].reg.enum := R_ST;
  774. End
  775. Else
  776. { change to
  777. fld/fst mem1 (hp1) fld/fst mem1
  778. fld mem1 (p) fld st}
  779. Begin
  780. Taicpu(p).changeopsize(S_FL);
  781. r.enum:=R_ST;
  782. Taicpu(p).loadreg(0,r);
  783. End
  784. Else
  785. Begin
  786. Case Taicpu(hp2).opcode Of
  787. A_FMULP,A_FADDP,A_FSUBP,A_FDIVP,A_FSUBRP,A_FDIVRP:
  788. { change to
  789. fld/fst mem1 (hp1) fld/fst mem1
  790. fld mem2 (p) fxxx mem2
  791. fxxxp st, st1 (hp2) }
  792. Begin
  793. Case Taicpu(hp2).opcode Of
  794. A_FADDP: Taicpu(p).opcode := A_FADD;
  795. A_FMULP: Taicpu(p).opcode := A_FMUL;
  796. A_FSUBP: Taicpu(p).opcode := A_FSUBR;
  797. A_FSUBRP: Taicpu(p).opcode := A_FSUB;
  798. A_FDIVP: Taicpu(p).opcode := A_FDIVR;
  799. A_FDIVRP: Taicpu(p).opcode := A_FDIV;
  800. End;
  801. asml.Remove(hp2);
  802. hp2.free;
  803. End
  804. End
  805. End
  806. End;
  807. A_FSTP,A_FISTP:
  808. if doFpuLoadStoreOpt(asmL,p) then
  809. continue;
  810. A_LEA:
  811. Begin
  812. {removes seg register prefixes from LEA operations, as they
  813. don't do anything}
  814. Taicpu(p).oper[0].ref^.Segment.enum := R_NO;
  815. {changes "lea (%reg1), %reg2" into "mov %reg1, %reg2"}
  816. If (Taicpu(p).oper[0].ref^.Base.enum In [R_EAX..R_EDI]) And
  817. (Taicpu(p).oper[0].ref^.Index.enum = R_NO) And
  818. (Not(Assigned(Taicpu(p).oper[0].ref^.Symbol))) Then
  819. If (Taicpu(p).oper[0].ref^.Base.enum <> Taicpu(p).oper[1].reg.enum)
  820. and (Taicpu(p).oper[0].ref^.Offset = 0)
  821. Then
  822. Begin
  823. hp1 := Taicpu.op_reg_reg(A_MOV, S_L,Taicpu(p).oper[0].ref^.Base,
  824. Taicpu(p).oper[1].reg);
  825. InsertLLItem(AsmL,p.previous,p.next, hp1);
  826. p.free;
  827. p := hp1;
  828. Continue;
  829. End
  830. Else
  831. if (Taicpu(p).oper[0].ref^.Offset = 0) then
  832. Begin
  833. hp1 := Tai(p.Next);
  834. asml.Remove(p);
  835. p.free;
  836. p := hp1;
  837. Continue;
  838. End
  839. else
  840. with Taicpu(p).oper[0].ref^ do
  841. if (Base.enum = Taicpu(p).oper[1].reg.enum) then
  842. begin
  843. l := offset+offsetfixup;
  844. if (l=1) then
  845. begin
  846. Taicpu(p).opcode := A_INC;
  847. Taicpu(p).loadreg(0,Taicpu(p).oper[1].reg);
  848. Taicpu(p).ops := 1
  849. end
  850. else
  851. if (l=-1) then
  852. begin
  853. Taicpu(p).opcode := A_DEC;
  854. Taicpu(p).loadreg(0,Taicpu(p).oper[1].reg);
  855. Taicpu(p).ops := 1;
  856. end
  857. else
  858. begin
  859. Taicpu(p).opcode := A_ADD;
  860. Taicpu(p).loadconst(0,aword(l));
  861. end;
  862. end;
  863. End;
  864. A_MOV:
  865. Begin
  866. TmpUsedRegs := UsedRegs;
  867. If (Taicpu(p).oper[1].typ = top_reg) And
  868. (Taicpu(p).oper[1].reg.enum In [R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI]) And
  869. GetNextInstruction(p, hp1) And
  870. (Tai(hp1).typ = ait_instruction) And
  871. (Taicpu(hp1).opcode = A_MOV) And
  872. (Taicpu(hp1).oper[0].typ = top_reg) And
  873. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum)
  874. Then
  875. {we have "mov x, %treg; mov %treg, y}
  876. If not(RegUsedAfterInstruction(Taicpu(p).oper[1].reg, hp1, TmpUsedRegs)) then
  877. {we've got "mov x, %treg; mov %treg, y; with %treg is not used after }
  878. Case Taicpu(p).oper[0].typ Of
  879. top_reg:
  880. Begin
  881. { change "mov %reg, %treg; mov %treg, y"
  882. to "mov %reg, y" }
  883. Taicpu(p).LoadOper(1,Taicpu(hp1).oper[1]);
  884. asml.Remove(hp1);
  885. hp1.free;
  886. continue;
  887. End;
  888. top_ref:
  889. If (Taicpu(hp1).oper[1].typ = top_reg) Then
  890. Begin
  891. { change "mov mem, %treg; mov %treg, %reg"
  892. to "mov mem, %reg" }
  893. Taicpu(p).Loadoper(1,Taicpu(hp1).oper[1]);
  894. asml.Remove(hp1);
  895. hp1.free;
  896. continue;
  897. End;
  898. End
  899. Else
  900. Else
  901. {Change "mov %reg1, %reg2; xxx %reg2, ???" to
  902. "mov %reg1, %reg2; xxx %reg1, ???" to avoid a write/read
  903. penalty}
  904. If (Taicpu(p).oper[0].typ = top_reg) And
  905. (Taicpu(p).oper[1].typ = top_reg) And
  906. GetNextInstruction(p,hp1) And
  907. (Tai(hp1).typ = ait_instruction) And
  908. (Taicpu(hp1).oper[0].typ = top_reg) And
  909. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum)
  910. Then
  911. {we have "mov %reg1, %reg2; XXX %reg2, ???"}
  912. Begin
  913. If ((Taicpu(hp1).opcode = A_OR) Or
  914. (Taicpu(hp1).opcode = A_TEST)) And
  915. (Taicpu(hp1).oper[1].typ = top_reg) And
  916. (Taicpu(hp1).oper[0].reg.enum = Taicpu(hp1).oper[1].reg.enum)
  917. Then
  918. {we have "mov %reg1, %reg2; test/or %reg2, %reg2"}
  919. Begin
  920. TmpUsedRegs := UsedRegs;
  921. { reg1 will be used after the first instruction, }
  922. { so update the allocation info }
  923. allocRegBetween(asmL,Taicpu(p).oper[0].reg,p,hp1);
  924. If GetNextInstruction(hp1, hp2) And
  925. (hp2.typ = ait_instruction) And
  926. Taicpu(hp2).is_jmp and
  927. Not(RegUsedAfterInstruction(Taicpu(hp1).oper[0].reg, hp1, TmpUsedRegs))
  928. Then
  929. {change "mov %reg1, %reg2; test/or %reg2, %reg2; jxx" to
  930. "test %reg1, %reg1; jxx"}
  931. Begin
  932. Taicpu(hp1).Loadoper(0,Taicpu(p).oper[0]);
  933. Taicpu(hp1).Loadoper(1,Taicpu(p).oper[0]);
  934. asml.Remove(p);
  935. p.free;
  936. p := hp1;
  937. continue
  938. End
  939. Else
  940. {change "mov %reg1, %reg2; test/or %reg2, %reg2" to
  941. "mov %reg1, %reg2; test/or %reg1, %reg1"}
  942. Begin
  943. Taicpu(hp1).Loadoper(0,Taicpu(p).oper[0]);
  944. Taicpu(hp1).Loadoper(1,Taicpu(p).oper[0]);
  945. End;
  946. End
  947. { Else
  948. If (Taicpu(p.next)^.opcode
  949. In [A_PUSH, A_OR, A_XOR, A_AND, A_TEST])}
  950. {change "mov %reg1, %reg2; push/or/xor/... %reg2, ???" to
  951. "mov %reg1, %reg2; push/or/xor/... %reg1, ???"}
  952. End
  953. Else
  954. {leave out the mov from "mov reg, x(%frame_pointer); leave/ret" (with
  955. x >= RetOffset) as it doesn't do anything (it writes either to a
  956. parameter or to the temporary storage room for the function
  957. result)}
  958. If GetNextInstruction(p, hp1) And
  959. (Tai(hp1).typ = ait_instruction)
  960. Then
  961. If ((Taicpu(hp1).opcode = A_LEAVE) Or
  962. (Taicpu(hp1).opcode = A_RET)) And
  963. (Taicpu(p).oper[1].typ = top_ref) And
  964. (Taicpu(p).oper[1].ref^.base.enum = current_procinfo.FramePointer.enum) And
  965. (Taicpu(p).oper[1].ref^.offset >= tvarsym(current_procinfo.procdef.funcretsym).adjusted_address) And
  966. (Taicpu(p).oper[1].ref^.index.enum = R_NO) And
  967. (Taicpu(p).oper[0].typ = top_reg)
  968. Then
  969. Begin
  970. asml.Remove(p);
  971. p.free;
  972. p := hp1;
  973. RemoveLastDeallocForFuncRes(asmL,p);
  974. End
  975. Else
  976. If (Taicpu(p).oper[0].typ = top_reg) And
  977. (Taicpu(p).oper[1].typ = top_ref) And
  978. (Taicpu(p).opsize = Taicpu(hp1).opsize) And
  979. (Taicpu(hp1).opcode = A_CMP) And
  980. (Taicpu(hp1).oper[1].typ = top_ref) And
  981. RefsEqual(Taicpu(p).oper[1].ref^, Taicpu(hp1).oper[1].ref^) Then
  982. {change "mov reg1, mem1; cmp x, mem1" to "mov reg, mem1; cmp x, reg1"}
  983. begin
  984. Taicpu(hp1).loadreg(1,Taicpu(p).oper[0].reg);
  985. allocRegBetween(asmL,Taicpu(p).oper[0].reg,p,hp1);
  986. end;
  987. { Next instruction is also a MOV ? }
  988. If GetNextInstruction(p, hp1) And
  989. (Tai(hp1).typ = ait_instruction) and
  990. (Taicpu(hp1).opcode = A_MOV) and
  991. (Taicpu(hp1).opsize = Taicpu(p).opsize)
  992. Then
  993. Begin
  994. If (Taicpu(hp1).oper[0].typ = Taicpu(p).oper[1].typ) and
  995. (Taicpu(hp1).oper[1].typ = Taicpu(p).oper[0].typ)
  996. Then
  997. {mov reg1, mem1 or mov mem1, reg1
  998. mov mem2, reg2 mov reg2, mem2}
  999. Begin
  1000. If OpsEqual(Taicpu(hp1).oper[1],Taicpu(p).oper[0]) Then
  1001. {mov reg1, mem1 or mov mem1, reg1
  1002. mov mem2, reg1 mov reg2, mem1}
  1003. Begin
  1004. If OpsEqual(Taicpu(hp1).oper[0],Taicpu(p).oper[1]) Then
  1005. { Removes the second statement from
  1006. mov reg1, mem1/reg2
  1007. mov mem1/reg2, reg1 }
  1008. Begin
  1009. if (Taicpu(p).oper[0].typ = top_reg) then
  1010. AllocRegBetween(asmL,Taicpu(p).oper[0].reg,p,hp1);
  1011. asml.remove(hp1);
  1012. hp1.free;
  1013. End
  1014. Else
  1015. Begin
  1016. TmpUsedRegs := UsedRegs;
  1017. UpdateUsedRegs(TmpUsedRegs, Tai(hp1.next));
  1018. If (Taicpu(p).oper[1].typ = top_ref) And
  1019. { mov reg1, mem1
  1020. mov mem2, reg1 }
  1021. GetNextInstruction(hp1, hp2) And
  1022. (hp2.typ = ait_instruction) And
  1023. (Taicpu(hp2).opcode = A_CMP) And
  1024. (Taicpu(hp2).opsize = Taicpu(p).opsize) and
  1025. (Taicpu(hp2).oper[0].typ = TOp_Ref) And
  1026. (Taicpu(hp2).oper[1].typ = TOp_Reg) And
  1027. RefsEqual(Taicpu(hp2).oper[0].ref^, Taicpu(p).oper[1].ref^) And
  1028. (Taicpu(hp2).oper[1].reg .enum= Taicpu(p).oper[0].reg.enum) And
  1029. Not(RegUsedAfterInstruction(Taicpu(p).oper[0].reg, hp2, TmpUsedRegs)) Then
  1030. { change to
  1031. mov reg1, mem1 mov reg1, mem1
  1032. mov mem2, reg1 cmp reg1, mem2
  1033. cmp mem1, reg1 }
  1034. Begin
  1035. asml.Remove(hp2);
  1036. hp2.free;
  1037. Taicpu(hp1).opcode := A_CMP;
  1038. Taicpu(hp1).loadref(1,Taicpu(hp1).oper[0].ref^);
  1039. Taicpu(hp1).loadreg(0,Taicpu(p).oper[0].reg);
  1040. End;
  1041. End;
  1042. End
  1043. Else
  1044. Begin
  1045. tmpUsedRegs := UsedRegs;
  1046. r.enum:=R_EDI;
  1047. If GetNextInstruction(hp1, hp2) And
  1048. (Taicpu(p).oper[0].typ = top_ref) And
  1049. (Taicpu(p).oper[1].typ = top_reg) And
  1050. (Taicpu(hp1).oper[0].typ = top_reg) And
  1051. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) And
  1052. (Taicpu(hp1).oper[1].typ = top_ref) And
  1053. (Tai(hp2).typ = ait_instruction) And
  1054. (Taicpu(hp2).opcode = A_MOV) And
  1055. (Taicpu(hp2).opsize = Taicpu(p).opsize) and
  1056. (Taicpu(hp2).oper[1].typ = top_reg) And
  1057. (Taicpu(hp2).oper[0].typ = top_ref) And
  1058. RefsEqual(Taicpu(hp2).oper[0].ref^, Taicpu(hp1).oper[1].ref^) Then
  1059. If not regInRef(Taicpu(hp2).oper[1].reg,Taicpu(hp2).oper[0].ref^) and
  1060. (Taicpu(p).oper[1].reg.enum in [R_DI,R_EDI]) and
  1061. not(RegUsedAfterInstruction(r,hp1,tmpUsedRegs)) Then
  1062. { mov mem1, %edi
  1063. mov %edi, mem2
  1064. mov mem2, reg2
  1065. to:
  1066. mov mem1, reg2
  1067. mov reg2, mem2}
  1068. Begin
  1069. AllocRegBetween(asmL,reg32(Taicpu(hp2).oper[1].reg),p,hp2);
  1070. Taicpu(p).Loadoper(1,Taicpu(hp2).oper[1]);
  1071. Taicpu(hp1).loadoper(0,Taicpu(hp2).oper[1]);
  1072. asml.Remove(hp2);
  1073. hp2.free;
  1074. End
  1075. Else
  1076. If (Taicpu(p).oper[1].reg.enum <> Taicpu(hp2).oper[1].reg.enum) And
  1077. not(RegInRef(Taicpu(p).oper[1].reg,Taicpu(p).oper[0].ref^)) And
  1078. not(RegInRef(Taicpu(hp2).oper[1].reg,Taicpu(hp2).oper[0].ref^))
  1079. Then
  1080. { mov mem1, reg1 mov mem1, reg1
  1081. mov reg1, mem2 mov reg1, mem2
  1082. mov mem2, reg2 mov mem2, reg1
  1083. to: to:
  1084. mov mem1, reg1 mov mem1, reg1
  1085. mov mem1, reg2 mov reg1, mem2
  1086. mov reg1, mem2
  1087. or (if mem1 depends on reg1
  1088. and/or if mem2 depends on reg2)
  1089. to:
  1090. mov mem1, reg1
  1091. mov reg1, mem2
  1092. mov reg1, reg2
  1093. }
  1094. Begin
  1095. Taicpu(hp1).LoadRef(0,Taicpu(p).oper[0].ref^);
  1096. Taicpu(hp1).LoadReg(1,Taicpu(hp2).oper[1].reg);
  1097. Taicpu(hp2).LoadRef(1,Taicpu(hp2).oper[0].ref^);
  1098. Taicpu(hp2).LoadReg(0,Taicpu(p).oper[1].reg);
  1099. allocRegBetween(asmL,Taicpu(p).oper[1].reg,p,hp2);
  1100. { if (Taicpu(p).oper[0].ref^.base.enum in (rg.usableregsint+[R_EDI])) then
  1101. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.base,p,hp2);
  1102. if (Taicpu(p).oper[0].ref^.index.enum in (rg.usableregsint+[R_EDI])) then
  1103. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.index,p,hp2);}
  1104. if (Taicpu(p).oper[0].ref^.base.enum in [R_EDI]) then
  1105. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.base,p,hp2);
  1106. if (Taicpu(p).oper[0].ref^.index.enum in [R_EDI]) then
  1107. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.index,p,hp2);
  1108. End
  1109. Else
  1110. If (Taicpu(hp1).Oper[0].reg.enum <> Taicpu(hp2).Oper[1].reg.enum) Then
  1111. begin
  1112. Taicpu(hp2).LoadReg(0,Taicpu(hp1).Oper[0].reg);
  1113. allocRegBetween(asmL,Taicpu(p).oper[1].reg,p,hp2);
  1114. end
  1115. else
  1116. begin
  1117. asml.Remove(hp2);
  1118. hp2.free;
  1119. end
  1120. End;
  1121. End
  1122. Else
  1123. (* {movl [mem1],reg1
  1124. movl [mem1],reg2
  1125. to:
  1126. movl [mem1],reg1
  1127. movl reg1,reg2 }
  1128. If (Taicpu(p).oper[0].typ = top_ref) and
  1129. (Taicpu(p).oper[1].typ = top_reg) and
  1130. (Taicpu(hp1).oper[0].typ = top_ref) and
  1131. (Taicpu(hp1).oper[1].typ = top_reg) and
  1132. (Taicpu(p).opsize = Taicpu(hp1).opsize) and
  1133. RefsEqual(TReference(Taicpu(p).oper[0]^),Taicpu(hp1).oper[0]^.ref^) and
  1134. (Taicpu(p).oper[1].reg<>Taicpu(hp1).oper[0]^.ref^.base) and
  1135. (Taicpu(p).oper[1].reg<>Taicpu(hp1).oper[0]^.ref^.index) then
  1136. Taicpu(hp1).LoadReg(0,Taicpu(p).oper[1].reg)
  1137. Else*)
  1138. { movl const1,[mem1]
  1139. movl [mem1],reg1
  1140. to:
  1141. movl const1,reg1
  1142. movl reg1,[mem1] }
  1143. If (Taicpu(p).oper[0].typ = top_const) and
  1144. (Taicpu(p).oper[1].typ = top_ref) and
  1145. (Taicpu(hp1).oper[0].typ = top_ref) and
  1146. (Taicpu(hp1).oper[1].typ = top_reg) and
  1147. (Taicpu(p).opsize = Taicpu(hp1).opsize) and
  1148. RefsEqual(Taicpu(hp1).oper[0].ref^,Taicpu(p).oper[1].ref^) then
  1149. Begin
  1150. allocregbetween(asml,Taicpu(hp1).oper[1].reg,p,hp1);
  1151. { allocregbetween doesn't insert this because at }
  1152. { this time, no regalloc info is available in }
  1153. { the optinfo field, so do it manually (JM) }
  1154. hp2 := tai_regalloc.Alloc(Taicpu(hp1).oper[1].reg);
  1155. insertllitem(asml,p.previous,p,hp2);
  1156. Taicpu(hp1).LoadReg(0,Taicpu(hp1).oper[1].reg);
  1157. Taicpu(hp1).LoadRef(1,Taicpu(p).oper[1].ref^);
  1158. Taicpu(p).LoadReg(1,Taicpu(hp1).oper[0].reg);
  1159. End
  1160. End;
  1161. End;
  1162. A_MOVZX:
  1163. Begin
  1164. {removes superfluous And's after movzx's}
  1165. If (Taicpu(p).oper[1].typ = top_reg) And
  1166. GetNextInstruction(p, hp1) And
  1167. (Tai(hp1).typ = ait_instruction) And
  1168. (Taicpu(hp1).opcode = A_AND) And
  1169. (Taicpu(hp1).oper[0].typ = top_const) And
  1170. (Taicpu(hp1).oper[1].typ = top_reg) And
  1171. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1172. Then
  1173. Case Taicpu(p).opsize Of
  1174. S_BL, S_BW:
  1175. If (Taicpu(hp1).oper[0].val = $ff) Then
  1176. Begin
  1177. asml.Remove(hp1);
  1178. hp1.free;
  1179. End;
  1180. S_WL:
  1181. If (Taicpu(hp1).oper[0].val = $ffff) Then
  1182. Begin
  1183. asml.Remove(hp1);
  1184. hp1.free;
  1185. End;
  1186. End;
  1187. {changes some movzx constructs to faster synonims (all examples
  1188. are given with eax/ax, but are also valid for other registers)}
  1189. If (Taicpu(p).oper[1].typ = top_reg) Then
  1190. If (Taicpu(p).oper[0].typ = top_reg) Then
  1191. Case Taicpu(p).opsize of
  1192. S_BW:
  1193. Begin
  1194. If (changeregsize(Taicpu(p).oper[0].reg,S_W).enum=Taicpu(p).oper[1].reg.enum) And
  1195. Not(CS_LittleSize In aktglobalswitches)
  1196. Then
  1197. {Change "movzbw %al, %ax" to "andw $0x0ffh, %ax"}
  1198. Begin
  1199. Taicpu(p).opcode := A_AND;
  1200. Taicpu(p).changeopsize(S_W);
  1201. Taicpu(p).LoadConst(0,$ff);
  1202. End
  1203. Else
  1204. If GetNextInstruction(p, hp1) And
  1205. (Tai(hp1).typ = ait_instruction) And
  1206. (Taicpu(hp1).opcode = A_AND) And
  1207. (Taicpu(hp1).oper[0].typ = top_const) And
  1208. (Taicpu(hp1).oper[1].typ = top_reg) And
  1209. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1210. Then
  1211. {Change "movzbw %reg1, %reg2; andw $const, %reg2"
  1212. to "movw %reg1, reg2; andw $(const1 and $ff), %reg2"}
  1213. Begin
  1214. Taicpu(p).opcode := A_MOV;
  1215. Taicpu(p).changeopsize(S_W);
  1216. Taicpu(p).LoadReg(0,changeregsize(Taicpu(p).oper[0].reg,S_W));
  1217. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1218. End;
  1219. End;
  1220. S_BL:
  1221. Begin
  1222. If (changeregsize(Taicpu(p).oper[0].reg,S_L).enum=Taicpu(p).oper[1].reg.enum) And
  1223. Not(CS_LittleSize in aktglobalswitches)
  1224. Then
  1225. {Change "movzbl %al, %eax" to "andl $0x0ffh, %eax"}
  1226. Begin
  1227. Taicpu(p).opcode := A_AND;
  1228. Taicpu(p).changeopsize(S_L);
  1229. Taicpu(p).loadconst(0,$ff)
  1230. End
  1231. Else
  1232. If GetNextInstruction(p, hp1) And
  1233. (Tai(hp1).typ = ait_instruction) And
  1234. (Taicpu(hp1).opcode = A_AND) And
  1235. (Taicpu(hp1).oper[0].typ = top_const) And
  1236. (Taicpu(hp1).oper[1].typ = top_reg) And
  1237. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1238. Then
  1239. {Change "movzbl %reg1, %reg2; andl $const, %reg2"
  1240. to "movl %reg1, reg2; andl $(const1 and $ff), %reg2"}
  1241. Begin
  1242. Taicpu(p).opcode := A_MOV;
  1243. Taicpu(p).changeopsize(S_L);
  1244. Taicpu(p).LoadReg(0,changeregsize(Taicpu(p).oper[0].reg,S_L));
  1245. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1246. End
  1247. End;
  1248. S_WL:
  1249. Begin
  1250. If (changeregsize(Taicpu(p).oper[0].reg,S_L).enum=Taicpu(p).oper[1].reg.enum) And
  1251. Not(CS_LittleSize In aktglobalswitches)
  1252. Then
  1253. {Change "movzwl %ax, %eax" to "andl $0x0ffffh, %eax"}
  1254. Begin
  1255. Taicpu(p).opcode := A_AND;
  1256. Taicpu(p).changeopsize(S_L);
  1257. Taicpu(p).LoadConst(0,$ffff);
  1258. End
  1259. Else
  1260. If GetNextInstruction(p, hp1) And
  1261. (Tai(hp1).typ = ait_instruction) And
  1262. (Taicpu(hp1).opcode = A_AND) And
  1263. (Taicpu(hp1).oper[0].typ = top_const) And
  1264. (Taicpu(hp1).oper[1].typ = top_reg) And
  1265. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1266. Then
  1267. {Change "movzwl %reg1, %reg2; andl $const, %reg2"
  1268. to "movl %reg1, reg2; andl $(const1 and $ffff), %reg2"}
  1269. Begin
  1270. Taicpu(p).opcode := A_MOV;
  1271. Taicpu(p).changeopsize(S_L);
  1272. Taicpu(p).LoadReg(0,changeregsize(Taicpu(p).oper[0].reg,S_L));
  1273. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ffff);
  1274. End;
  1275. End;
  1276. End
  1277. Else
  1278. If (Taicpu(p).oper[0].typ = top_ref) Then
  1279. Begin
  1280. If GetNextInstruction(p, hp1) And
  1281. (Tai(hp1).typ = ait_instruction) And
  1282. (Taicpu(hp1).opcode = A_AND) And
  1283. (Taicpu(hp1).oper[0].typ = Top_Const) And
  1284. (Taicpu(hp1).oper[1].typ = Top_Reg) And
  1285. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  1286. Begin
  1287. Taicpu(p).opcode := A_MOV;
  1288. Case Taicpu(p).opsize Of
  1289. S_BL:
  1290. Begin
  1291. Taicpu(p).changeopsize(S_L);
  1292. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1293. End;
  1294. S_WL:
  1295. Begin
  1296. Taicpu(p).changeopsize(S_L);
  1297. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ffff);
  1298. End;
  1299. S_BW:
  1300. Begin
  1301. Taicpu(p).changeopsize(S_W);
  1302. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1303. End;
  1304. End;
  1305. End;
  1306. End;
  1307. End;
  1308. A_POP:
  1309. Begin
  1310. if target_info.system=system_i386_go32v2 then
  1311. begin
  1312. { Transform a series of pop/pop/pop/push/push/push to }
  1313. { 'movl x(%esp),%reg' for go32v2 (not for the rest, }
  1314. { because I'm not sure whether they can cope with }
  1315. { 'movl x(%esp),%reg' with x > 0, I believe we had }
  1316. { such a problem when using esp as frame pointer (JM) }
  1317. if (Taicpu(p).oper[0].typ = top_reg) then
  1318. begin
  1319. hp1 := p;
  1320. hp2 := p;
  1321. l := 0;
  1322. while getNextInstruction(hp1,hp1) and
  1323. (hp1.typ = ait_instruction) and
  1324. (Taicpu(hp1).opcode = A_POP) and
  1325. (Taicpu(hp1).oper[0].typ = top_reg) do
  1326. begin
  1327. hp2 := hp1;
  1328. inc(l,4);
  1329. end;
  1330. getLastInstruction(p,hp3);
  1331. l1 := 0;
  1332. while (hp2 <> hp3) and
  1333. assigned(hp1) and
  1334. (hp1.typ = ait_instruction) and
  1335. (Taicpu(hp1).opcode = A_PUSH) and
  1336. (Taicpu(hp1).oper[0].typ = top_reg) and
  1337. (Taicpu(hp1).oper[0].reg.enum = Taicpu(hp2).oper[0].reg.enum) do
  1338. begin
  1339. { change it to a two op operation }
  1340. Taicpu(hp2).oper[1].typ:=top_none;
  1341. Taicpu(hp2).ops:=2;
  1342. Taicpu(hp2).opcode := A_MOV;
  1343. Taicpu(hp2).Loadoper(1,Taicpu(hp1).oper[0]);
  1344. reference_reset_old(tmpref);
  1345. tmpRef.base.enum:=R_INTREGISTER;
  1346. tmpRef.base.number:=NR_STACK_POINTER_REG;
  1347. convert_register_to_enum(tmpref.base);
  1348. tmpRef.offset := l;
  1349. Taicpu(hp2).loadRef(0,tmpRef);
  1350. hp4 := hp1;
  1351. getNextInstruction(hp1,hp1);
  1352. asml.remove(hp4);
  1353. hp4.free;
  1354. getLastInstruction(hp2,hp2);
  1355. dec(l,4);
  1356. inc(l1);
  1357. end;
  1358. if l <> -4 then
  1359. begin
  1360. inc(l,4);
  1361. for l1 := l1 downto 1 do
  1362. begin
  1363. getNextInstruction(hp2,hp2);
  1364. dec(Taicpu(hp2).oper[0].ref^.offset,l);
  1365. end
  1366. end
  1367. end
  1368. end
  1369. else
  1370. begin
  1371. if (Taicpu(p).oper[0].typ = top_reg) And
  1372. GetNextInstruction(p, hp1) And
  1373. (Tai(hp1).typ=ait_instruction) and
  1374. (Taicpu(hp1).opcode=A_PUSH) and
  1375. (Taicpu(hp1).oper[0].typ = top_reg) And
  1376. (Taicpu(hp1).oper[0].reg.enum=Taicpu(p).oper[0].reg.enum) then
  1377. Begin
  1378. { change it to a two op operation }
  1379. Taicpu(p).oper[1].typ:=top_none;
  1380. Taicpu(p).ops:=2;
  1381. Taicpu(p).opcode := A_MOV;
  1382. Taicpu(p).Loadoper(1,Taicpu(p).oper[0]);
  1383. reference_reset_old(tmpref);
  1384. TmpRef.base.enum := R_ESP;
  1385. Taicpu(p).LoadRef(0,TmpRef);
  1386. asml.Remove(hp1);
  1387. hp1.free;
  1388. End;
  1389. end;
  1390. end;
  1391. A_PUSH:
  1392. Begin
  1393. If (Taicpu(p).opsize = S_W) And
  1394. (Taicpu(p).oper[0].typ = Top_Const) And
  1395. GetNextInstruction(p, hp1) And
  1396. (Tai(hp1).typ = ait_instruction) And
  1397. (Taicpu(hp1).opcode = A_PUSH) And
  1398. (Taicpu(hp1).oper[0].typ = Top_Const) And
  1399. (Taicpu(hp1).opsize = S_W) Then
  1400. Begin
  1401. Taicpu(p).changeopsize(S_L);
  1402. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val shl 16 + word(Taicpu(hp1).oper[0].val));
  1403. asml.Remove(hp1);
  1404. hp1.free;
  1405. End;
  1406. End;
  1407. A_SHL, A_SAL:
  1408. Begin
  1409. If (Taicpu(p).oper[0].typ = Top_Const) And
  1410. (Taicpu(p).oper[1].typ = Top_Reg) And
  1411. (Taicpu(p).opsize = S_L) And
  1412. (Taicpu(p).oper[0].val <= 3)
  1413. {Changes "shl const, %reg32; add const/reg, %reg32" to one lea statement}
  1414. Then
  1415. Begin
  1416. TmpBool1 := True; {should we check the next instruction?}
  1417. TmpBool2 := False; {have we found an add/sub which could be
  1418. integrated in the lea?}
  1419. reference_reset_old(tmpref);
  1420. TmpRef.index := Taicpu(p).oper[1].reg;
  1421. TmpRef.scalefactor := 1 shl Taicpu(p).oper[0].val;
  1422. While TmpBool1 And
  1423. GetNextInstruction(p, hp1) And
  1424. (Tai(hp1).typ = ait_instruction) And
  1425. ((((Taicpu(hp1).opcode = A_ADD) Or
  1426. (Taicpu(hp1).opcode = A_SUB)) And
  1427. (Taicpu(hp1).oper[1].typ = Top_Reg) And
  1428. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)) or
  1429. (((Taicpu(hp1).opcode = A_INC) or
  1430. (Taicpu(hp1).opcode = A_DEC)) and
  1431. (Taicpu(hp1).oper[0].typ = Top_Reg) and
  1432. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum))) Do
  1433. Begin
  1434. TmpBool1 := False;
  1435. If (Taicpu(hp1).oper[0].typ = Top_Const)
  1436. Then
  1437. Begin
  1438. TmpBool1 := True;
  1439. TmpBool2 := True;
  1440. case Taicpu(hp1).opcode of
  1441. A_ADD:
  1442. inc(TmpRef.offset, longint(Taicpu(hp1).oper[0].val));
  1443. A_SUB:
  1444. dec(TmpRef.offset, longint(Taicpu(hp1).oper[0].val));
  1445. end;
  1446. asml.Remove(hp1);
  1447. hp1.free;
  1448. End
  1449. Else
  1450. If (Taicpu(hp1).oper[0].typ = Top_Reg) And
  1451. (((Taicpu(hp1).opcode = A_ADD) And
  1452. (TmpRef.base.enum = R_NO)) or
  1453. (Taicpu(hp1).opcode = A_INC) or
  1454. (Taicpu(hp1).opcode = A_DEC)) Then
  1455. Begin
  1456. TmpBool1 := True;
  1457. TmpBool2 := True;
  1458. case Taicpu(hp1).opcode of
  1459. A_ADD:
  1460. TmpRef.base := Taicpu(hp1).oper[0].reg;
  1461. A_INC:
  1462. inc(TmpRef.offset);
  1463. A_DEC:
  1464. dec(TmpRef.offset);
  1465. end;
  1466. asml.Remove(hp1);
  1467. hp1.free;
  1468. End;
  1469. End;
  1470. If TmpBool2 Or
  1471. ((aktoptprocessor < ClassP6) And
  1472. (Taicpu(p).oper[0].val <= 3) And
  1473. Not(CS_LittleSize in aktglobalswitches))
  1474. Then
  1475. Begin
  1476. If Not(TmpBool2) And
  1477. (Taicpu(p).oper[0].val = 1)
  1478. Then
  1479. Begin
  1480. hp1 := Taicpu.Op_reg_reg(A_ADD,Taicpu(p).opsize,
  1481. Taicpu(p).oper[1].reg, Taicpu(p).oper[1].reg)
  1482. End
  1483. Else hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef,
  1484. Taicpu(p).oper[1].reg);
  1485. InsertLLItem(AsmL,p.previous, p.next, hp1);
  1486. p.free;
  1487. p := hp1;
  1488. End;
  1489. End
  1490. Else
  1491. If (aktoptprocessor < ClassP6) And
  1492. (Taicpu(p).oper[0].typ = top_const) And
  1493. (Taicpu(p).oper[1].typ = top_reg) Then
  1494. If (Taicpu(p).oper[0].val = 1)
  1495. Then
  1496. {changes "shl $1, %reg" to "add %reg, %reg", which is the same on a 386,
  1497. but faster on a 486, and Tairable in both U and V pipes on the Pentium
  1498. (unlike shl, which is only Tairable in the U pipe)}
  1499. Begin
  1500. hp1 := Taicpu.Op_reg_reg(A_ADD,Taicpu(p).opsize,
  1501. Taicpu(p).oper[1].reg, Taicpu(p).oper[1].reg);
  1502. InsertLLItem(AsmL,p.previous, p.next, hp1);
  1503. p.free;
  1504. p := hp1;
  1505. End
  1506. Else If (Taicpu(p).opsize = S_L) and
  1507. (Taicpu(p).oper[0].val<= 3) Then
  1508. {changes "shl $2, %reg" to "lea (,%reg,4), %reg"
  1509. "shl $3, %reg" to "lea (,%reg,8), %reg}
  1510. Begin
  1511. reference_reset_old(tmpref);
  1512. TmpRef.index := Taicpu(p).oper[1].reg;
  1513. TmpRef.scalefactor := 1 shl Taicpu(p).oper[0].val;
  1514. hp1 := Taicpu.Op_ref_reg(A_LEA,S_L,TmpRef, Taicpu(p).oper[1].reg);
  1515. InsertLLItem(AsmL,p.previous, p.next, hp1);
  1516. p.free;
  1517. p := hp1;
  1518. End
  1519. End;
  1520. A_SETcc :
  1521. { changes
  1522. setcc (funcres) setcc reg
  1523. movb (funcres), reg to leave/ret
  1524. leave/ret }
  1525. Begin
  1526. If (Taicpu(p).oper[0].typ = top_ref) And
  1527. GetNextInstruction(p, hp1) And
  1528. GetNextInstruction(hp1, hp2) And
  1529. (hp2.typ = ait_instruction) And
  1530. ((Taicpu(hp2).opcode = A_LEAVE) or
  1531. (Taicpu(hp2).opcode = A_RET)) And
  1532. (Taicpu(p).oper[0].ref^.Base.enum = current_procinfo.FramePointer.enum) And
  1533. (Taicpu(p).oper[0].ref^.Index.enum = R_NO) And
  1534. (Taicpu(p).oper[0].ref^.Offset >= tvarsym(current_procinfo.procdef.funcretsym).adjusted_address) And
  1535. (hp1.typ = ait_instruction) And
  1536. (Taicpu(hp1).opcode = A_MOV) And
  1537. (Taicpu(hp1).opsize = S_B) And
  1538. (Taicpu(hp1).oper[0].typ = top_ref) And
  1539. RefsEqual(Taicpu(hp1).oper[0].ref^, Taicpu(p).oper[0].ref^) Then
  1540. Begin
  1541. Taicpu(p).LoadReg(0,Taicpu(hp1).oper[1].reg);
  1542. asml.Remove(hp1);
  1543. hp1.free;
  1544. End
  1545. End;
  1546. A_SUB:
  1547. { * change "subl $2, %esp; pushw x" to "pushl x"}
  1548. { * change "sub/add const1, reg" or "dec reg" followed by
  1549. "sub const2, reg" to one "sub ..., reg" }
  1550. Begin
  1551. If (Taicpu(p).oper[0].typ = top_const) And
  1552. (Taicpu(p).oper[1].typ = top_reg) Then
  1553. If (Taicpu(p).oper[0].val = 2) And
  1554. (Taicpu(p).oper[1].reg.enum = R_ESP) and
  1555. { Don't do the sub/push optimization if the sub }
  1556. { comes from setting up the stack frame (JM) }
  1557. (not getLastInstruction(p,hp1) or
  1558. (hp1.typ <> ait_instruction) or
  1559. (Taicpu(hp1).opcode <> A_MOV) or
  1560. (Taicpu(hp1).oper[0].typ <> top_reg) or
  1561. (Taicpu(hp1).oper[0].reg.enum <> R_ESP) or
  1562. (Taicpu(hp1).oper[1].typ <> top_reg) or
  1563. (Taicpu(hp1).oper[1].reg.enum <> R_EBP)) then
  1564. Begin
  1565. hp1 := Tai(p.next);
  1566. r.enum:=R_ESP;
  1567. While Assigned(hp1) And
  1568. (Tai(hp1).typ In [ait_instruction]+SkipInstr) And
  1569. not regReadByInstruction(r,hp1) and
  1570. not regModifiedByInstruction(r,hp1) do
  1571. hp1 := Tai(hp1.next);
  1572. If Assigned(hp1) And
  1573. (Tai(hp1).typ = ait_instruction) And
  1574. (Taicpu(hp1).opcode = A_PUSH) And
  1575. (Taicpu(hp1).opsize = S_W)
  1576. Then
  1577. Begin
  1578. Taicpu(hp1).changeopsize(S_L);
  1579. if Taicpu(hp1).oper[0].typ=top_reg then
  1580. Taicpu(hp1).LoadReg(0,changeregsize(Taicpu(hp1).oper[0].reg,S_L));
  1581. hp1 := Tai(p.next);
  1582. asml.Remove(p);
  1583. p.free;
  1584. p := hp1;
  1585. Continue
  1586. End;
  1587. If DoSubAddOpt(p) Then continue;
  1588. End
  1589. Else If DoSubAddOpt(p) Then Continue
  1590. End;
  1591. A_XOR:
  1592. If (Taicpu(p).oper[0].typ = top_reg) And
  1593. (Taicpu(p).oper[1].typ = top_reg) And
  1594. (Taicpu(p).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) then
  1595. { temporarily change this to 'mov reg,0' to make it easier }
  1596. { for the CSE. Will be changed back in pass 2 }
  1597. begin
  1598. Taicpu(p).opcode := A_MOV;
  1599. Taicpu(p).loadconst(0,0);
  1600. end;
  1601. End;
  1602. end; { if is_jmp }
  1603. End;
  1604. { ait_label:
  1605. Begin
  1606. If labelCanBeSkipped(Tai_label(p))
  1607. Then
  1608. Begin
  1609. hp1 := Tai(p.next);
  1610. asml.Remove(p);
  1611. p.free;
  1612. p := hp1;
  1613. Continue
  1614. End;
  1615. End;}
  1616. End;
  1617. updateUsedRegs(UsedRegs,p);
  1618. p:=Tai(p.next);
  1619. end;
  1620. end;
  1621. function isFoldableArithOp(hp1: Taicpu; reg: Toldregister): boolean;
  1622. begin
  1623. IsFoldableArithOp := False;
  1624. case hp1.opcode of
  1625. A_ADD,A_SUB,A_OR,A_XOR,A_AND,A_SHL,A_SHR,A_SAR:
  1626. isFoldableArithOp :=
  1627. ((Taicpu(hp1).oper[0].typ = top_const) or
  1628. ((Taicpu(hp1).oper[0].typ = top_reg) and
  1629. (Taicpu(hp1).oper[0].reg.enum <> reg))) and
  1630. (Taicpu(hp1).oper[1].typ = top_reg) and
  1631. (Taicpu(hp1).oper[1].reg.enum = reg);
  1632. A_INC,A_DEC:
  1633. isFoldableArithOp :=
  1634. (Taicpu(hp1).oper[0].typ = top_reg) and
  1635. (Taicpu(hp1).oper[0].reg.enum = reg);
  1636. end;
  1637. end;
  1638. Procedure PeepHoleOptPass2(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  1639. {$ifdef USECMOV}
  1640. function CanBeCMOV(p : Tai) : boolean;
  1641. begin
  1642. CanBeCMOV:=assigned(p) and (p.typ=ait_instruction) and
  1643. (Taicpu(p).opcode=A_MOV) and
  1644. (Taicpu(p).opsize in [S_L,S_W]) and
  1645. (Taicpu(p).oper[0].typ in [top_reg,top_ref]) and
  1646. (Taicpu(p).oper[1].typ in [top_reg]);
  1647. end;
  1648. {$endif USECMOV}
  1649. var
  1650. p,hp1,hp2: Tai;
  1651. {$ifdef USECMOV}
  1652. l : longint;
  1653. condition : tasmcond;
  1654. hp3: Tai;
  1655. {$endif USECMOV}
  1656. UsedRegs, TmpUsedRegs: TRegSet;
  1657. Begin
  1658. P := BlockStart;
  1659. UsedRegs := [];
  1660. While (P <> BlockEnd) Do
  1661. Begin
  1662. UpdateUsedRegs(UsedRegs, Tai(p.next));
  1663. Case p.Typ Of
  1664. Ait_Instruction:
  1665. Begin
  1666. Case Taicpu(p).opcode Of
  1667. {$ifdef USECMOV}
  1668. A_Jcc:
  1669. if (aktspecificoptprocessor=ClassP6) then
  1670. begin
  1671. { check for
  1672. jCC xxx
  1673. <several movs>
  1674. xxx:
  1675. }
  1676. l:=0;
  1677. GetNextInstruction(p, hp1);
  1678. while assigned(hp1) And
  1679. CanBeCMOV(hp1) do
  1680. begin
  1681. inc(l);
  1682. GetNextInstruction(hp1,hp1);
  1683. end;
  1684. if assigned(hp1) then
  1685. begin
  1686. if FindLabel(tasmlabel(Taicpu(p).oper[0].sym),hp1) then
  1687. begin
  1688. if (l<=4) and (l>0) then
  1689. begin
  1690. condition:=inverse_cond[Taicpu(p).condition];
  1691. GetNextInstruction(p,hp1);
  1692. asml.remove(p);
  1693. p.free;
  1694. p:=hp1;
  1695. repeat
  1696. Taicpu(hp1).opcode:=A_CMOVcc;
  1697. Taicpu(hp1).condition:=condition;
  1698. GetNextInstruction(hp1,hp1);
  1699. until not(assigned(hp1)) or
  1700. not(CanBeCMOV(hp1));
  1701. asml.remove(hp1);
  1702. hp1.free;
  1703. continue;
  1704. end;
  1705. end
  1706. else
  1707. begin
  1708. { check further for
  1709. jCC xxx
  1710. <several movs>
  1711. jmp yyy
  1712. xxx:
  1713. <several movs>
  1714. yyy:
  1715. }
  1716. { hp2 points to jmp xxx }
  1717. hp2:=hp1;
  1718. { skip hp1 to xxx }
  1719. GetNextInstruction(hp1, hp1);
  1720. if assigned(hp2) and
  1721. assigned(hp1) and
  1722. (l<=3) and
  1723. (hp2.typ=ait_instruction) and
  1724. (Taicpu(hp2).is_jmp) and
  1725. (Taicpu(hp2).condition=C_None) and
  1726. FindLabel(tasmlabel(Taicpu(p).oper[0].sym),hp1) then
  1727. begin
  1728. l:=0;
  1729. while assigned(hp1) And
  1730. CanBeCMOV(hp1) do
  1731. begin
  1732. inc(l);
  1733. GetNextInstruction(hp1, hp1);
  1734. end;
  1735. end;
  1736. {
  1737. if assigned(hp1) and
  1738. FindLabel(tasmlabel(Taicpu(hp2).oper[0].sym),hp1) then
  1739. begin
  1740. condition:=inverse_cond[Taicpu(p).condition];
  1741. GetNextInstruction(p,hp1);
  1742. asml.remove(p);
  1743. p.free;
  1744. p:=hp1;
  1745. repeat
  1746. Taicpu(hp1).opcode:=A_CMOVcc;
  1747. Taicpu(hp1).condition:=condition;
  1748. GetNextInstruction(hp1,hp1);
  1749. until not(assigned(hp1)) or
  1750. not(CanBeCMOV(hp1));
  1751. hp2:=hp1.next;
  1752. condition:=inverse_cond[condition];
  1753. asml.remove(hp1.next)
  1754. hp1.next.free;
  1755. asml.remove(hp1);
  1756. hp1.free;
  1757. continue;
  1758. end;
  1759. }
  1760. end;
  1761. end;
  1762. end;
  1763. {$endif USECMOV}
  1764. A_FSTP,A_FISTP:
  1765. if doFpuLoadStoreOpt(asmL,p) then
  1766. continue;
  1767. A_IMUL:
  1768. begin
  1769. if ((Taicpu(p).oper[0].typ = top_const) or
  1770. (Taicpu(p).oper[0].typ = top_symbol)) and
  1771. (Taicpu(p).oper[1].typ = top_reg) and
  1772. ((Taicpu(p).oper[2].typ = top_none) or
  1773. ((Taicpu(p).oper[2].typ = top_reg) and
  1774. (Taicpu(p).oper[2].reg.enum = Taicpu(p).oper[1].reg.enum))) and
  1775. getLastInstruction(p,hp1) and
  1776. (hp1.typ = ait_instruction) and
  1777. (Taicpu(hp1).opcode = A_MOV) and
  1778. (Taicpu(hp1).oper[0].typ = top_reg) and
  1779. (Taicpu(hp1).oper[1].typ = top_reg) and
  1780. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) then
  1781. { change "mov reg1,reg2; imul y,reg2" to "imul y,reg1,reg2" }
  1782. begin
  1783. Taicpu(p).ops := 3;
  1784. Taicpu(p).loadreg(1,Taicpu(hp1).oper[0].reg);
  1785. Taicpu(p).loadreg(2,Taicpu(hp1).oper[1].reg);
  1786. asml.remove(hp1);
  1787. hp1.free;
  1788. end;
  1789. end;
  1790. A_MOV:
  1791. Begin
  1792. If (Taicpu(p).oper[0].typ = top_reg) And
  1793. (Taicpu(p).oper[1].typ = top_reg) And
  1794. GetNextInstruction(p, hp1) And
  1795. (hp1.typ = ait_Instruction) And
  1796. ((Taicpu(hp1).opcode = A_MOV) or
  1797. (Taicpu(hp1).opcode = A_MOVZX) or
  1798. (Taicpu(hp1).opcode = A_MOVSX)) And
  1799. (Taicpu(hp1).oper[0].typ = top_ref) And
  1800. (Taicpu(hp1).oper[1].typ = top_reg) And
  1801. ((Taicpu(hp1).oper[0].ref^.Base.enum = Taicpu(p).oper[1].reg.enum) Or
  1802. (Taicpu(hp1).oper[0].ref^.Index.enum = Taicpu(p).oper[1].reg.enum)) And
  1803. (Reg32(Taicpu(hp1).oper[1].reg).enum = Taicpu(p).oper[1].reg.enum) Then
  1804. {mov reg1, reg2
  1805. mov/zx/sx (reg2, ..), reg2 to mov/zx/sx (reg1, ..), reg2}
  1806. Begin
  1807. If (Taicpu(hp1).oper[0].ref^.Base.enum = Taicpu(p).oper[1].reg.enum) Then
  1808. Taicpu(hp1).oper[0].ref^.Base.enum := Taicpu(p).oper[0].reg.enum;
  1809. If (Taicpu(hp1).oper[0].ref^.Index.enum = Taicpu(p).oper[1].reg.enum) Then
  1810. Taicpu(hp1).oper[0].ref^.Index.enum := Taicpu(p).oper[0].reg.enum;
  1811. asml.Remove(p);
  1812. p.free;
  1813. p := hp1;
  1814. Continue;
  1815. End
  1816. Else If (Taicpu(p).oper[0].typ = top_ref) And
  1817. GetNextInstruction(p,hp1) And
  1818. (hp1.typ = ait_instruction) And
  1819. IsFoldableArithOp(Taicpu(hp1),Taicpu(p).oper[1].reg.enum) And
  1820. GetNextInstruction(hp1,hp2) And
  1821. (hp2.typ = ait_instruction) And
  1822. (Taicpu(hp2).opcode = A_MOV) And
  1823. (Taicpu(hp2).oper[0].typ = top_reg) And
  1824. (Taicpu(hp2).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) And
  1825. (Taicpu(hp2).oper[1].typ = top_ref) Then
  1826. Begin
  1827. TmpUsedRegs := UsedRegs;
  1828. UpdateUsedRegs(TmpUsedRegs,Tai(hp1.next));
  1829. If (RefsEqual(Taicpu(hp2).oper[1].ref^, Taicpu(p).oper[0].ref^) And
  1830. Not(RegUsedAfterInstruction(Taicpu(p).oper[1].reg,
  1831. hp2, TmpUsedRegs)))
  1832. Then
  1833. { change mov (ref), reg }
  1834. { add/sub/or/... reg2/$const, reg }
  1835. { mov reg, (ref) }
  1836. { # release reg }
  1837. { to add/sub/or/... reg2/$const, (ref) }
  1838. Begin
  1839. case Taicpu(hp1).opcode of
  1840. A_INC,A_DEC:
  1841. Taicpu(hp1).LoadRef(0,Taicpu(p).oper[0].ref^)
  1842. else
  1843. Taicpu(hp1).LoadRef(1,Taicpu(p).oper[0].ref^);
  1844. end;
  1845. asml.Remove(p);
  1846. asml.Remove(hp2);
  1847. p.free;
  1848. hp2.free;
  1849. p := hp1
  1850. End;
  1851. End
  1852. End;
  1853. End;
  1854. End;
  1855. End;
  1856. p := Tai(p.next)
  1857. End;
  1858. End;
  1859. Procedure PostPeepHoleOpts(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  1860. var
  1861. p,hp1,hp2: Tai;
  1862. Begin
  1863. P := BlockStart;
  1864. While (P <> BlockEnd) Do
  1865. Begin
  1866. Case p.Typ Of
  1867. Ait_Instruction:
  1868. Begin
  1869. Case Taicpu(p).opcode Of
  1870. A_CALL:
  1871. If (AktOptProcessor < ClassP6) And
  1872. GetNextInstruction(p, hp1) And
  1873. (hp1.typ = ait_instruction) And
  1874. (Taicpu(hp1).opcode = A_JMP) And
  1875. (Taicpu(hp1).oper[0].typ = top_symbol) Then
  1876. Begin
  1877. hp2 := Taicpu.Op_sym(A_PUSH,S_L,Taicpu(hp1).oper[0].sym);
  1878. InsertLLItem(AsmL, p.previous, p, hp2);
  1879. Taicpu(p).opcode := A_JMP;
  1880. Taicpu(p).is_jmp := true;
  1881. asml.Remove(hp1);
  1882. hp1.free;
  1883. End;
  1884. A_CMP:
  1885. Begin
  1886. if (Taicpu(p).oper[0].typ = top_const) and
  1887. (Taicpu(p).oper[0].val = 0) and
  1888. (Taicpu(p).oper[1].typ = top_reg) then
  1889. {change "cmp $0, %reg" to "test %reg, %reg"}
  1890. begin
  1891. Taicpu(p).opcode := A_TEST;
  1892. Taicpu(p).loadreg(0,Taicpu(p).oper[1].reg);
  1893. continue;
  1894. end;
  1895. End;
  1896. (*
  1897. Optimization is not safe; xor clears the carry flag.
  1898. See test/tgadint64 in the test suite.
  1899. A_MOV:
  1900. if (Taicpu(p).oper[0].typ = Top_Const) And
  1901. (Taicpu(p).oper[0].val = 0) And
  1902. (Taicpu(p).oper[1].typ = Top_Reg) Then
  1903. { change "mov $0, %reg" into "xor %reg, %reg" }
  1904. Begin
  1905. Taicpu(p).opcode := A_XOR;
  1906. Taicpu(p).LoadReg(0,Taicpu(p).oper[1].reg);
  1907. End;
  1908. *)
  1909. A_MOVZX:
  1910. { if register vars are on, it's possible there is code like }
  1911. { "cmpl $3,%eax; movzbl 8(%ebp),%ebx; je .Lxxx" }
  1912. { so we can't safely replace the movzx then with xor/mov, }
  1913. { since that would change the flags (JM) }
  1914. if not(cs_regvars in aktglobalswitches) then
  1915. Begin
  1916. If (Taicpu(p).oper[1].typ = top_reg) Then
  1917. If (Taicpu(p).oper[0].typ = top_reg)
  1918. Then
  1919. Case Taicpu(p).opsize of
  1920. S_BL:
  1921. Begin
  1922. If IsGP32Reg(Taicpu(p).oper[1].reg) And
  1923. Not(CS_LittleSize in aktglobalswitches) And
  1924. (aktoptprocessor = ClassP5)
  1925. Then
  1926. {Change "movzbl %reg1, %reg2" to
  1927. "xorl %reg2, %reg2; movb %reg1, %reg2" for Pentium and
  1928. PentiumMMX}
  1929. Begin
  1930. hp1 := Taicpu.op_reg_reg(A_XOR, S_L,
  1931. Taicpu(p).oper[1].reg, Taicpu(p).oper[1].reg);
  1932. InsertLLItem(AsmL,p.previous, p, hp1);
  1933. Taicpu(p).opcode := A_MOV;
  1934. Taicpu(p).changeopsize(S_B);
  1935. Taicpu(p).LoadReg(1,changeregsize(Taicpu(p).oper[1].reg,S_B));
  1936. End;
  1937. End;
  1938. End
  1939. Else
  1940. If (Taicpu(p).oper[0].typ = top_ref) And
  1941. (Taicpu(p).oper[0].ref^.base.enum <> Taicpu(p).oper[1].reg.enum) And
  1942. (Taicpu(p).oper[0].ref^.index.enum <> Taicpu(p).oper[1].reg.enum) And
  1943. Not(CS_LittleSize in aktglobalswitches) And
  1944. IsGP32Reg(Taicpu(p).oper[1].reg) And
  1945. (aktoptprocessor = ClassP5) And
  1946. (Taicpu(p).opsize = S_BL)
  1947. Then
  1948. {changes "movzbl mem, %reg" to "xorl %reg, %reg; movb mem, %reg8" for
  1949. Pentium and PentiumMMX}
  1950. Begin
  1951. hp1 := Taicpu.Op_reg_reg(A_XOR, S_L, Taicpu(p).oper[1].reg,
  1952. Taicpu(p).oper[1].reg);
  1953. Taicpu(p).opcode := A_MOV;
  1954. Taicpu(p).changeopsize(S_B);
  1955. Taicpu(p).LoadReg(1,changeregsize(Taicpu(p).oper[1].reg,S_B));
  1956. InsertLLItem(AsmL,p.previous, p, hp1);
  1957. End;
  1958. End;
  1959. A_TEST, A_OR:
  1960. {removes the line marked with (x) from the sequence
  1961. And/or/xor/add/sub/... $x, %y
  1962. test/or %y, %y (x)
  1963. j(n)z _Label
  1964. as the first instruction already adjusts the ZF}
  1965. Begin
  1966. If OpsEqual(Taicpu(p).oper[0],Taicpu(p).oper[1]) Then
  1967. If GetLastInstruction(p, hp1) And
  1968. (Tai(hp1).typ = ait_instruction) Then
  1969. Case Taicpu(hp1).opcode Of
  1970. A_ADD, A_SUB, A_OR, A_XOR, A_AND{, A_SHL, A_SHR}:
  1971. Begin
  1972. If OpsEqual(Taicpu(hp1).oper[1],Taicpu(p).oper[0]) Then
  1973. Begin
  1974. hp1 := Tai(p.next);
  1975. asml.remove(p);
  1976. p.free;
  1977. p := Tai(hp1);
  1978. continue
  1979. End;
  1980. End;
  1981. A_DEC, A_INC, A_NEG:
  1982. Begin
  1983. If OpsEqual(Taicpu(hp1).oper[0],Taicpu(p).oper[0]) Then
  1984. Begin
  1985. Case Taicpu(hp1).opcode Of
  1986. A_DEC, A_INC:
  1987. {replace inc/dec with add/sub 1, because inc/dec doesn't set the carry flag}
  1988. Begin
  1989. Case Taicpu(hp1).opcode Of
  1990. A_DEC: Taicpu(hp1).opcode := A_SUB;
  1991. A_INC: Taicpu(hp1).opcode := A_ADD;
  1992. End;
  1993. Taicpu(hp1).Loadoper(1,Taicpu(hp1).oper[0]);
  1994. Taicpu(hp1).LoadConst(0,1);
  1995. Taicpu(hp1).ops:=2;
  1996. End
  1997. End;
  1998. hp1 := Tai(p.next);
  1999. asml.remove(p);
  2000. p.free;
  2001. p := Tai(hp1);
  2002. continue
  2003. End;
  2004. End
  2005. End
  2006. End;
  2007. End;
  2008. End;
  2009. End;
  2010. p := Tai(p.next)
  2011. End;
  2012. End;
  2013. End.
  2014. {
  2015. $Log$
  2016. Revision 1.48 2003-08-09 18:56:54 daniel
  2017. * cs_regalloc renamed to cs_regvars to avoid confusion with register
  2018. allocator
  2019. * Some preventive changes to i386 spillinh code
  2020. Revision 1.47 2003/06/08 18:48:03 jonas
  2021. * first small steps towards an oop optimizer
  2022. Revision 1.46 2003/06/03 21:09:05 peter
  2023. * internal changeregsize for optimizer
  2024. * fix with a hack to not remove the first instruction of a block
  2025. which will leave blockstart pointing to invalid memory
  2026. Revision 1.45 2003/06/02 21:42:05 jonas
  2027. * function results can now also be regvars
  2028. - removed tprocinfo.return_offset, never use it again since it's invalid
  2029. if the result is a regvar
  2030. Revision 1.44 2003/05/30 23:57:08 peter
  2031. * more sparc cleanup
  2032. * accumulator removed, splitted in function_return_reg (called) and
  2033. function_result_reg (caller)
  2034. Revision 1.43 2003/04/27 11:21:35 peter
  2035. * aktprocdef renamed to current_procdef
  2036. * procinfo renamed to current_procinfo
  2037. * procinfo will now be stored in current_module so it can be
  2038. cleaned up properly
  2039. * gen_main_procsym changed to create_main_proc and release_main_proc
  2040. to also generate a tprocinfo structure
  2041. * fixed unit implicit initfinal
  2042. Revision 1.42 2003/03/28 19:16:57 peter
  2043. * generic constructor working for i386
  2044. * remove fixed self register
  2045. * esi added as address register for i386
  2046. Revision 1.41 2003/02/26 13:24:59 daniel
  2047. * Disabled mov reg,0 -> xor reg,reg optimization
  2048. Revision 1.40 2003/02/25 07:41:54 daniel
  2049. * Properly fixed reversed operands bug
  2050. Revision 1.39 2003/02/24 21:27:01 daniel
  2051. * Reversed operand order in an optimization in postpeepholeopt
  2052. Revision 1.38 2003/02/19 22:39:56 daniel
  2053. * Fixed a few issues
  2054. Revision 1.37 2003/02/19 22:00:16 daniel
  2055. * Code generator converted to new register notation
  2056. - Horribily outdated todo.txt removed
  2057. Revision 1.36 2003/01/08 18:43:57 daniel
  2058. * Tregister changed into a record
  2059. Revision 1.35 2002/11/15 16:30:54 peter
  2060. * made tasmsymbol.refs private (merged)
  2061. Revision 1.34 2002/08/18 20:06:30 peter
  2062. * inlining is now also allowed in interface
  2063. * renamed write/load to ppuwrite/ppuload
  2064. * tnode storing in ppu
  2065. * nld,ncon,nbas are already updated for storing in ppu
  2066. Revision 1.33 2002/08/17 09:23:46 florian
  2067. * first part of procinfo rewrite
  2068. Revision 1.32 2002/08/11 14:32:30 peter
  2069. * renamed current_library to objectlibrary
  2070. Revision 1.31 2002/08/11 13:24:17 peter
  2071. * saving of asmsymbols in ppu supported
  2072. * asmsymbollist global is removed and moved into a new class
  2073. tasmlibrarydata that will hold the info of a .a file which
  2074. corresponds with a single module. Added librarydata to tmodule
  2075. to keep the library info stored for the module. In the future the
  2076. objectfiles will also be stored to the tasmlibrarydata class
  2077. * all getlabel/newasmsymbol and friends are moved to the new class
  2078. Revision 1.30 2002/07/26 21:15:43 florian
  2079. * rewrote the system handling
  2080. Revision 1.29 2002/07/01 18:46:34 peter
  2081. * internal linker
  2082. * reorganized aasm layer
  2083. Revision 1.28 2002/06/09 12:55:23 jonas
  2084. * fixed detection of register usage
  2085. Revision 1.27 2002/05/18 13:34:25 peter
  2086. * readded missing revisions
  2087. Revision 1.26 2002/05/16 19:46:52 carl
  2088. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  2089. + try to fix temp allocation (still in ifdef)
  2090. + generic constructor calls
  2091. + start of tassembler / tmodulebase class cleanup
  2092. Revision 1.24 2002/05/12 16:53:18 peter
  2093. * moved entry and exitcode to ncgutil and cgobj
  2094. * foreach gets extra argument for passing local data to the
  2095. iterator function
  2096. * -CR checks also class typecasts at runtime by changing them
  2097. into as
  2098. * fixed compiler to cycle with the -CR option
  2099. * fixed stabs with elf writer, finally the global variables can
  2100. be watched
  2101. * removed a lot of routines from cga unit and replaced them by
  2102. calls to cgobj
  2103. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  2104. u32bit then the other is typecasted also to u32bit without giving
  2105. a rangecheck warning/error.
  2106. * fixed pascal calling method with reversing also the high tree in
  2107. the parast, detected by tcalcst3 test
  2108. Revision 1.23 2002/04/21 15:40:49 carl
  2109. * changeregsize -> changeregsize
  2110. Revision 1.22 2002/04/20 21:37:07 carl
  2111. + generic FPC_CHECKPOINTER
  2112. + first parameter offset in stack now portable
  2113. * rename some constants
  2114. + move some cpu stuff to other units
  2115. - remove unused constents
  2116. * fix stacksize for some targets
  2117. * fix generic size problems which depend now on EXTEND_SIZE constant
  2118. * removing frame pointer in routines is only available for : i386,m68k and vis targets
  2119. Revision 1.21 2002/04/15 19:44:21 peter
  2120. * fixed stackcheck that would be called recursively when a stack
  2121. error was found
  2122. * generic changeregsize(reg,size) for i386 register resizing
  2123. * removed some more routines from cga unit
  2124. * fixed returnvalue handling
  2125. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  2126. Revision 1.20 2002/04/02 20:30:16 jonas
  2127. + support for folding inc/dec in shl/add/sub sequences toa single lea
  2128. instruction
  2129. Revision 1.19 2002/04/02 13:01:58 jonas
  2130. * fixed nasty bug in "and" peepholeoptimization that caused wrong
  2131. optimizations after Peter's big location patch
  2132. Revision 1.18 2002/03/31 20:26:40 jonas
  2133. + a_loadfpu_* and a_loadmm_* methods in tcg
  2134. * register allocation is now handled by a class and is mostly processor
  2135. independent (+rgobj.pas and i386/rgcpu.pas)
  2136. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  2137. * some small improvements and fixes to the optimizer
  2138. * some register allocation fixes
  2139. * some fpuvaroffset fixes in the unary minus node
  2140. * push/popusedregisters is now called rg.save/restoreusedregisters and
  2141. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  2142. also better optimizable)
  2143. * fixed and optimized register saving/restoring for new/dispose nodes
  2144. * LOC_FPU locations now also require their "register" field to be set to
  2145. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  2146. - list field removed of the tnode class because it's not used currently
  2147. and can cause hard-to-find bugs
  2148. }