popt386.pas 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200
  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. {$ifdef finaldestdebug}
  31. cobjects,
  32. {$endif finaldestdebug}
  33. cpuinfo,cpubase,DAOpt386,cginfo,rgobj;
  34. Function RegUsedAfterInstruction(Reg: Tregister; p: Tai; Var UsedRegs: TRegSet): Boolean;
  35. Begin
  36. if reg.enum>lastreg then
  37. internalerror(200301081);
  38. reg := reg32(reg);
  39. UpdateUsedRegs(UsedRegs, Tai(p.Next));
  40. RegUsedAfterInstruction :=
  41. (Reg.enum in UsedRegs) and
  42. (not(getNextInstruction(p,p)) or
  43. not(regLoadedWithNewValue(reg,false,p)));
  44. End;
  45. function doFpuLoadStoreOpt(asmL: TAAsmoutput; var p: Tai): boolean;
  46. { returns true if a "continue" should be done after this optimization }
  47. var hp1, hp2: Tai;
  48. begin
  49. doFpuLoadStoreOpt := false;
  50. if (Taicpu(p).oper[0].typ = top_ref) and
  51. getNextInstruction(p, hp1) and
  52. (hp1.typ = ait_instruction) and
  53. (((Taicpu(hp1).opcode = A_FLD) and
  54. (Taicpu(p).opcode = A_FSTP)) or
  55. ((Taicpu(p).opcode = A_FISTP) and
  56. (Taicpu(hp1).opcode = A_FILD))) and
  57. (Taicpu(hp1).oper[0].typ = top_ref) and
  58. (Taicpu(hp1).opsize = Taicpu(p).opsize) and
  59. refsEqual(Taicpu(p).oper[0].ref^, Taicpu(hp1).oper[0].ref^) then
  60. begin
  61. if getNextInstruction(hp1, hp2) and
  62. (hp2.typ = ait_instruction) and
  63. ((Taicpu(hp2).opcode = A_LEAVE) or
  64. (Taicpu(hp2).opcode = A_RET)) and
  65. (Taicpu(p).oper[0].ref^.Base.enum = current_procinfo.FramePointer.enum) and
  66. (Taicpu(p).oper[0].ref^.Offset >= current_procinfo.Return_Offset) and
  67. (Taicpu(p).oper[0].ref^.Index.enum = R_NO) then
  68. begin
  69. asml.remove(p);
  70. asml.remove(hp1);
  71. p.free;
  72. hp1.free;
  73. p := hp2;
  74. removeLastDeallocForFuncRes(asmL, p);
  75. doFPULoadStoreOpt := true;
  76. end
  77. else
  78. { fst can't store an extended value! }
  79. if (Taicpu(p).opsize <> S_FX) and
  80. (Taicpu(p).opsize <> S_IQ) then
  81. begin
  82. if (Taicpu(p).opcode = A_FSTP) then
  83. Taicpu(p).opcode := A_FST
  84. else Taicpu(p).opcode := A_FIST;
  85. asml.remove(hp1);
  86. hp1.free;
  87. end
  88. end;
  89. end;
  90. Procedure PrePeepHoleOpts(AsmL: TAAsmOutput; BlockStart, BlockEnd: Tai);
  91. var
  92. p,hp1: Tai;
  93. l: Aword;
  94. tmpRef: treference;
  95. Begin
  96. P := BlockStart;
  97. While (P <> BlockEnd) Do
  98. Begin
  99. Case p.Typ Of
  100. Ait_Instruction:
  101. Begin
  102. Case Taicpu(p).opcode Of
  103. A_IMUL:
  104. {changes certain "imul const, %reg"'s to lea sequences}
  105. Begin
  106. If (Taicpu(p).oper[0].typ = Top_Const) And
  107. (Taicpu(p).oper[1].typ = Top_Reg) And
  108. (Taicpu(p).opsize = S_L) Then
  109. If (Taicpu(p).oper[0].val = 1) Then
  110. If (Taicpu(p).oper[2].typ = Top_None) Then
  111. {remove "imul $1, reg"}
  112. Begin
  113. hp1 := Tai(p.Next);
  114. asml.Remove(p);
  115. p.free;
  116. p := hp1;
  117. Continue;
  118. End
  119. Else
  120. {change "imul $1, reg1, reg2" to "mov reg1, reg2"}
  121. Begin
  122. hp1 := Taicpu.Op_Reg_Reg(A_MOV, S_L, Taicpu(p).oper[1].reg,Taicpu(p).oper[2].reg);
  123. InsertLLItem(AsmL, p.previous, p.next, hp1);
  124. p.free;
  125. p := hp1;
  126. End
  127. Else If
  128. ((Taicpu(p).oper[2].typ = Top_Reg) or
  129. (Taicpu(p).oper[2].typ = Top_None)) And
  130. (aktoptprocessor < ClassP6) And
  131. (Taicpu(p).oper[0].val <= 12) And
  132. Not(CS_LittleSize in aktglobalswitches) And
  133. (Not(GetNextInstruction(p, hp1)) Or
  134. {GetNextInstruction(p, hp1) And}
  135. Not((Tai(hp1).typ = ait_instruction) And
  136. ((Taicpu(hp1).opcode=A_Jcc) and
  137. (Taicpu(hp1).condition in [C_O,C_NO]))))
  138. Then
  139. Begin
  140. reference_reset_old(tmpref);
  141. Case Taicpu(p).oper[0].val Of
  142. 3: Begin
  143. {imul 3, reg1, reg2 to
  144. lea (reg1,reg1,2), reg2
  145. imul 3, reg1 to
  146. lea (reg1,reg1,2), reg1}
  147. TmpRef.base := Taicpu(p).oper[1].reg;
  148. TmpRef.Index := Taicpu(p).oper[1].reg;
  149. TmpRef.ScaleFactor := 2;
  150. If (Taicpu(p).oper[2].typ = Top_None) Then
  151. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg)
  152. Else
  153. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  154. InsertLLItem(AsmL,p.previous, p.next, hp1);
  155. p.free;
  156. p := hp1;
  157. End;
  158. 5: Begin
  159. {imul 5, reg1, reg2 to
  160. lea (reg1,reg1,4), reg2
  161. imul 5, reg1 to
  162. lea (reg1,reg1,4), reg1}
  163. TmpRef.base := Taicpu(p).oper[1].reg;
  164. TmpRef.Index := Taicpu(p).oper[1].reg;
  165. TmpRef.ScaleFactor := 4;
  166. If (Taicpu(p).oper[2].typ = Top_None) Then
  167. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg)
  168. Else
  169. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  170. InsertLLItem(AsmL,p.previous, p.next, hp1);
  171. p.free;
  172. p := hp1;
  173. End;
  174. 6: Begin
  175. {imul 6, reg1, reg2 to
  176. lea (,reg1,2), reg2
  177. lea (reg2,reg1,4), reg2
  178. imul 6, reg1 to
  179. lea (reg1,reg1,2), reg1
  180. add reg1, reg1}
  181. If (aktoptprocessor <= Class386)
  182. Then
  183. Begin
  184. TmpRef.Index := Taicpu(p).oper[1].reg;
  185. If (Taicpu(p).oper[2].typ = Top_Reg)
  186. Then
  187. Begin
  188. TmpRef.base := Taicpu(p).oper[2].reg;
  189. TmpRef.ScaleFactor := 4;
  190. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  191. End
  192. Else
  193. Begin
  194. hp1 := Taicpu.op_reg_reg(A_ADD, S_L,
  195. Taicpu(p).oper[1].reg,Taicpu(p).oper[1].reg);
  196. End;
  197. InsertLLItem(AsmL,p, p.next, hp1);
  198. reference_reset_old(tmpref);
  199. TmpRef.Index := Taicpu(p).oper[1].reg;
  200. TmpRef.ScaleFactor := 2;
  201. If (Taicpu(p).oper[2].typ = Top_Reg)
  202. Then
  203. Begin
  204. TmpRef.base.enum := R_NO;
  205. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef,
  206. Taicpu(p).oper[2].reg);
  207. End
  208. Else
  209. Begin
  210. TmpRef.base := Taicpu(p).oper[1].reg;
  211. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  212. End;
  213. InsertLLItem(AsmL,p.previous, p.next, hp1);
  214. p.free;
  215. p := Tai(hp1.next);
  216. End
  217. End;
  218. 9: Begin
  219. {imul 9, reg1, reg2 to
  220. lea (reg1,reg1,8), reg2
  221. imul 9, reg1 to
  222. lea (reg1,reg1,8), reg1}
  223. TmpRef.base := Taicpu(p).oper[1].reg;
  224. TmpRef.Index := Taicpu(p).oper[1].reg;
  225. TmpRef.ScaleFactor := 8;
  226. If (Taicpu(p).oper[2].typ = Top_None) Then
  227. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg)
  228. Else
  229. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  230. InsertLLItem(AsmL,p.previous, p.next, hp1);
  231. p.free;
  232. p := hp1;
  233. End;
  234. 10: Begin
  235. {imul 10, reg1, reg2 to
  236. lea (reg1,reg1,4), reg2
  237. add reg2, reg2
  238. imul 10, reg1 to
  239. lea (reg1,reg1,4), reg1
  240. add reg1, reg1}
  241. If (aktoptprocessor <= Class386) Then
  242. Begin
  243. If (Taicpu(p).oper[2].typ = Top_Reg) Then
  244. hp1 := Taicpu.op_reg_reg(A_ADD, S_L,
  245. Taicpu(p).oper[2].reg,Taicpu(p).oper[2].reg)
  246. Else
  247. hp1 := Taicpu.op_reg_reg(A_ADD, S_L,
  248. Taicpu(p).oper[1].reg,Taicpu(p).oper[1].reg);
  249. InsertLLItem(AsmL,p, p.next, hp1);
  250. TmpRef.base := Taicpu(p).oper[1].reg;
  251. TmpRef.Index := Taicpu(p).oper[1].reg;
  252. TmpRef.ScaleFactor := 4;
  253. If (Taicpu(p).oper[2].typ = Top_Reg)
  254. Then
  255. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg)
  256. Else
  257. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  258. InsertLLItem(AsmL,p.previous, p.next, hp1);
  259. p.free;
  260. p := Tai(hp1.next);
  261. End
  262. End;
  263. 12: Begin
  264. {imul 12, reg1, reg2 to
  265. lea (,reg1,4), reg2
  266. lea (,reg1,8) reg2
  267. imul 12, reg1 to
  268. lea (reg1,reg1,2), reg1
  269. lea (,reg1,4), reg1}
  270. If (aktoptprocessor <= Class386)
  271. Then
  272. Begin
  273. TmpRef.Index := Taicpu(p).oper[1].reg;
  274. If (Taicpu(p).oper[2].typ = Top_Reg) Then
  275. Begin
  276. TmpRef.base := Taicpu(p).oper[2].reg;
  277. TmpRef.ScaleFactor := 8;
  278. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  279. End
  280. Else
  281. Begin
  282. TmpRef.base.enum := R_NO;
  283. TmpRef.ScaleFactor := 4;
  284. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  285. End;
  286. InsertLLItem(AsmL,p, p.next, hp1);
  287. reference_reset_old(tmpref);
  288. TmpRef.Index := Taicpu(p).oper[1].reg;
  289. If (Taicpu(p).oper[2].typ = Top_Reg) Then
  290. Begin
  291. TmpRef.base.enum := R_NO;
  292. TmpRef.ScaleFactor := 4;
  293. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[2].reg);
  294. End
  295. Else
  296. Begin
  297. TmpRef.base := Taicpu(p).oper[1].reg;
  298. TmpRef.ScaleFactor := 2;
  299. hp1 := Taicpu.op_ref_reg(A_LEA, S_L, TmpRef, Taicpu(p).oper[1].reg);
  300. End;
  301. InsertLLItem(AsmL,p.previous, p.next, hp1);
  302. p.free;
  303. p := Tai(hp1.next);
  304. End
  305. End
  306. End;
  307. End;
  308. End;
  309. A_SAR, A_SHR:
  310. {changes the code sequence
  311. shr/sar const1, x
  312. shl const2, x
  313. to either "sar/and", "shl/and" or just "and" depending on const1 and const2}
  314. Begin
  315. If GetNextInstruction(p, hp1) And
  316. (Tai(hp1).typ = ait_instruction) and
  317. (Taicpu(hp1).opcode = A_SHL) and
  318. (Taicpu(p).oper[0].typ = top_const) and
  319. (Taicpu(hp1).oper[0].typ = top_const) and
  320. (Taicpu(hp1).opsize = Taicpu(p).opsize) And
  321. (Taicpu(hp1).oper[1].typ = Taicpu(p).oper[1].typ) And
  322. OpsEqual(Taicpu(hp1).oper[1], Taicpu(p).oper[1])
  323. Then
  324. If (Taicpu(p).oper[0].val > Taicpu(hp1).oper[0].val) And
  325. Not(CS_LittleSize In aktglobalswitches)
  326. Then
  327. { shr/sar const1, %reg
  328. shl const2, %reg
  329. with const1 > const2 }
  330. Begin
  331. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val-Taicpu(hp1).oper[0].val);
  332. Taicpu(hp1).opcode := A_AND;
  333. l := (1 shl (Taicpu(hp1).oper[0].val)) - 1;
  334. Case Taicpu(p).opsize Of
  335. S_L: Taicpu(hp1).LoadConst(0,l Xor aword($ffffffff));
  336. S_B: Taicpu(hp1).LoadConst(0,l Xor $ff);
  337. S_W: Taicpu(hp1).LoadConst(0,l Xor $ffff);
  338. End;
  339. End
  340. Else
  341. If (Taicpu(p).oper[0].val<Taicpu(hp1).oper[0].val) And
  342. Not(CS_LittleSize In aktglobalswitches)
  343. Then
  344. { shr/sar const1, %reg
  345. shl const2, %reg
  346. with const1 < const2 }
  347. Begin
  348. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val-Taicpu(p).oper[0].val);
  349. Taicpu(p).opcode := A_AND;
  350. l := (1 shl (Taicpu(p).oper[0].val))-1;
  351. Case Taicpu(p).opsize Of
  352. S_L: Taicpu(p).LoadConst(0,l Xor aword($ffffffff));
  353. S_B: Taicpu(p).LoadConst(0,l Xor $ff);
  354. S_W: Taicpu(p).LoadConst(0,l Xor $ffff);
  355. End;
  356. End
  357. Else
  358. { shr/sar const1, %reg
  359. shl const2, %reg
  360. with const1 = const2 }
  361. if (Taicpu(p).oper[0].val = Taicpu(hp1).oper[0].val) then
  362. Begin
  363. Taicpu(p).opcode := A_AND;
  364. l := (1 shl (Taicpu(p).oper[0].val))-1;
  365. Case Taicpu(p).opsize Of
  366. S_B: Taicpu(p).LoadConst(0,l Xor $ff);
  367. S_W: Taicpu(p).LoadConst(0,l Xor $ffff);
  368. S_L: Taicpu(p).LoadConst(0,l Xor aword($ffffffff));
  369. End;
  370. asml.remove(hp1);
  371. hp1.free;
  372. End;
  373. End;
  374. A_XOR:
  375. If (Taicpu(p).oper[0].typ = top_reg) And
  376. (Taicpu(p).oper[1].typ = top_reg) And
  377. (Taicpu(p).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) then
  378. { temporarily change this to 'mov reg,0' to make it easier }
  379. { for the CSE. Will be changed back in pass 2 }
  380. begin
  381. Taicpu(p).opcode := A_MOV;
  382. Taicpu(p).loadconst(0,0);
  383. end;
  384. End;
  385. End;
  386. End;
  387. p := Tai(p.next)
  388. End;
  389. End;
  390. Procedure PeepHoleOptPass1(Asml: TAAsmOutput; BlockStart, BlockEnd: Tai);
  391. {First pass of peepholeoptimizations}
  392. Var
  393. l,l1 : longint;
  394. p,hp1,hp2 : Tai;
  395. hp3,hp4: Tai;
  396. TmpRef: TReference;
  397. UsedRegs, TmpUsedRegs: TRegSet;
  398. TmpBool1, TmpBool2: Boolean;
  399. r:Tregister;
  400. Function SkipLabels(hp: Tai; var hp2: Tai): boolean;
  401. {skips all labels and returns the next "real" instruction}
  402. Begin
  403. While assigned(hp.next) and
  404. (Tai(hp.next).typ In SkipInstr + [ait_label,ait_align]) Do
  405. hp := Tai(hp.next);
  406. If assigned(hp.next) Then
  407. Begin
  408. SkipLabels := True;
  409. hp2 := Tai(hp.next)
  410. End
  411. Else
  412. Begin
  413. hp2 := hp;
  414. SkipLabels := False
  415. End;
  416. End;
  417. function GetFinalDestination(AsmL: TAAsmOutput; hp: Taicpu; level: longint): boolean;
  418. {traces sucessive jumps to their final destination and sets it, e.g.
  419. je l1 je l3
  420. <code> <code>
  421. l1: becomes l1:
  422. je l2 je l3
  423. <code> <code>
  424. l2: l2:
  425. jmp l3 jmp l3
  426. the level parameter denotes how deeep we have already followed the jump,
  427. to avoid endless loops with constructs such as "l5: ; jmp l5" }
  428. Var p1, p2: Tai;
  429. l: tasmlabel;
  430. Function FindAnyLabel(hp: Tai; var l: tasmlabel): Boolean;
  431. Begin
  432. FindAnyLabel := false;
  433. While assigned(hp.next) and
  434. (Tai(hp.next).typ In (SkipInstr+[ait_align])) Do
  435. hp := Tai(hp.next);
  436. If assigned(hp.next) and
  437. (Tai(hp.next).typ = ait_label) Then
  438. Begin
  439. FindAnyLabel := true;
  440. l := Tai_label(hp.next).l;
  441. End
  442. End;
  443. Begin
  444. if level > 20 then
  445. exit;
  446. GetfinalDestination := false;
  447. If (tasmlabel(hp.oper[0].sym).labelnr >= LoLab) and
  448. (tasmlabel(hp.oper[0].sym).labelnr <= HiLab) and {range check, a jump can go past an assembler block!}
  449. Assigned(LTable^[tasmlabel(hp.oper[0].sym).labelnr-LoLab].TaiObj) Then
  450. Begin
  451. p1 := LTable^[tasmlabel(hp.oper[0].sym).labelnr-LoLab].TaiObj; {the jump's destination}
  452. SkipLabels(p1,p1);
  453. If (Tai(p1).typ = ait_instruction) and
  454. (Taicpu(p1).is_jmp) Then
  455. If { the next instruction after the label where the jump hp arrives}
  456. { is unconditional or of the same type as hp, so continue }
  457. (Taicpu(p1).condition in [C_None,hp.condition]) or
  458. { the next instruction after the label where the jump hp arrives}
  459. { is the opposite of hp (so this one is never taken), but after }
  460. { that one there is a branch that will be taken, so perform a }
  461. { little hack: set p1 equal to this instruction (that's what the}
  462. { last SkipLabels is for, only works with short bool evaluation)}
  463. ((Taicpu(p1).condition = inverse_cond[hp.condition]) and
  464. SkipLabels(p1,p2) and
  465. (p2.typ = ait_instruction) and
  466. (Taicpu(p2).is_jmp) and
  467. (Taicpu(p2).condition in [C_None,hp.condition]) and
  468. SkipLabels(p1,p1)) Then
  469. Begin
  470. { quick check for loops of the form "l5: ; jmp l5 }
  471. if (tasmlabel(Taicpu(p1).oper[0].sym).labelnr =
  472. tasmlabel(hp.oper[0].sym).labelnr) then
  473. exit;
  474. if not GetFinalDestination(asml, Taicpu(p1),succ(level)) then
  475. exit;
  476. tasmlabel(hp.oper[0].sym).decrefs;
  477. hp.oper[0].sym:=Taicpu(p1).oper[0].sym;
  478. tasmlabel(hp.oper[0].sym).increfs;
  479. End
  480. Else
  481. If (Taicpu(p1).condition = inverse_cond[hp.condition]) then
  482. if not FindAnyLabel(p1,l) then
  483. begin
  484. {$ifdef finaldestdebug}
  485. insertllitem(asml,p1,p1.next,tai_comment.Create(
  486. strpnew('previous label inserted'))));
  487. {$endif finaldestdebug}
  488. objectlibrary.getlabel(l);
  489. insertllitem(asml,p1,p1.next,Tai_label.Create(l));
  490. tasmlabel(Taicpu(hp).oper[0].sym).decrefs;
  491. hp.oper[0].sym := l;
  492. l.increfs;
  493. { this won't work, since the new label isn't in the labeltable }
  494. { so it will fail the rangecheck. Labeltable should become a }
  495. { hashtable to support this: }
  496. { GetFinalDestination(asml, hp); }
  497. end
  498. else
  499. begin
  500. {$ifdef finaldestdebug}
  501. insertllitem(asml,p1,p1.next,tai_comment.Create(
  502. strpnew('next label reused'))));
  503. {$endif finaldestdebug}
  504. l.increfs;
  505. hp.oper[0].sym := l;
  506. if not GetFinalDestination(asml, hp,succ(level)) then
  507. exit;
  508. end;
  509. End;
  510. GetFinalDestination := true;
  511. End;
  512. Function DoSubAddOpt(var p: Tai): Boolean;
  513. Begin
  514. DoSubAddOpt := False;
  515. If GetLastInstruction(p, hp1) And
  516. (hp1.typ = ait_instruction) And
  517. (Taicpu(hp1).opsize = Taicpu(p).opsize) then
  518. Case Taicpu(hp1).opcode Of
  519. A_DEC:
  520. If (Taicpu(hp1).oper[0].typ = top_reg) And
  521. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  522. Begin
  523. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val+1);
  524. asml.Remove(hp1);
  525. hp1.free;
  526. End;
  527. A_SUB:
  528. If (Taicpu(hp1).oper[0].typ = top_const) And
  529. (Taicpu(hp1).oper[1].typ = top_reg) And
  530. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  531. Begin
  532. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val+Taicpu(hp1).oper[0].val);
  533. asml.Remove(hp1);
  534. hp1.free;
  535. End;
  536. A_ADD:
  537. If (Taicpu(hp1).oper[0].typ = top_const) And
  538. (Taicpu(hp1).oper[1].typ = top_reg) And
  539. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  540. Begin
  541. Taicpu(p).LoadConst(0,AWord(int64(Taicpu(p).oper[0].val)-int64(Taicpu(hp1).oper[0].val)));
  542. asml.Remove(hp1);
  543. hp1.free;
  544. If (Taicpu(p).oper[0].val = 0) Then
  545. Begin
  546. hp1 := Tai(p.next);
  547. asml.Remove(p);
  548. p.free;
  549. If Not GetLastInstruction(hp1, p) Then
  550. p := hp1;
  551. DoSubAddOpt := True;
  552. End
  553. End;
  554. End;
  555. End;
  556. Begin
  557. P := BlockStart;
  558. UsedRegs := [];
  559. While (P <> BlockEnd) Do
  560. Begin
  561. UpDateUsedRegs(UsedRegs, Tai(p.next));
  562. Case p.Typ Of
  563. ait_instruction:
  564. Begin
  565. { Handle Jmp Optimizations }
  566. if Taicpu(p).is_jmp then
  567. begin
  568. {the following if-block removes all code between a jmp and the next label,
  569. because it can never be executed}
  570. If (Taicpu(p).opcode = A_JMP) Then
  571. Begin
  572. While GetNextInstruction(p, hp1) and
  573. (hp1.typ <> ait_label) do
  574. If not(hp1.typ in ([ait_label,ait_align]+skipinstr)) Then
  575. Begin
  576. asml.Remove(hp1);
  577. hp1.free;
  578. End
  579. else break;
  580. End;
  581. { remove jumps to a label coming right after them }
  582. If GetNextInstruction(p, hp1) then
  583. Begin
  584. if FindLabel(tasmlabel(Taicpu(p).oper[0].sym), hp1) then
  585. Begin
  586. hp2:=Tai(hp1.next);
  587. asml.remove(p);
  588. p.free;
  589. p:=hp2;
  590. continue;
  591. end
  592. Else
  593. Begin
  594. if hp1.typ = ait_label then
  595. SkipLabels(hp1,hp1);
  596. If (Tai(hp1).typ=ait_instruction) and
  597. (Taicpu(hp1).opcode=A_JMP) and
  598. GetNextInstruction(hp1, hp2) And
  599. FindLabel(tasmlabel(Taicpu(p).oper[0].sym), hp2)
  600. Then
  601. Begin
  602. if Taicpu(p).opcode=A_Jcc then
  603. Taicpu(p).condition:=inverse_cond[Taicpu(p).condition]
  604. else
  605. begin
  606. If (LabDif <> 0) Then
  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. If (LabDif <> 0) Then
  617. GetFinalDestination(asml, Taicpu(p),0);
  618. end
  619. else
  620. If (LabDif <> 0) Then
  621. GetFinalDestination(asml, Taicpu(p),0);
  622. end;
  623. end;
  624. end
  625. else
  626. { All other optimizes }
  627. begin
  628. For l := 0 to 2 Do
  629. If (Taicpu(p).oper[l].typ = top_ref) Then
  630. With Taicpu(p).oper[l].ref^ Do
  631. Begin
  632. If (base.enum = R_NO) And
  633. (index.enum <> R_NO) And
  634. (scalefactor in [0,1])
  635. Then
  636. Begin
  637. base := index;
  638. index.enum := R_NO
  639. End
  640. End;
  641. Case Taicpu(p).opcode Of
  642. A_AND:
  643. Begin
  644. If (Taicpu(p).oper[0].typ = top_const) And
  645. (Taicpu(p).oper[1].typ = top_reg) And
  646. GetNextInstruction(p, hp1) And
  647. (Tai(hp1).typ = ait_instruction) And
  648. (Taicpu(hp1).opcode = A_AND) And
  649. (Taicpu(hp1).oper[0].typ = top_const) And
  650. (Taicpu(hp1).oper[1].typ = top_reg) And
  651. (Taicpu(p).oper[1].reg.enum = Taicpu(hp1).oper[1].reg.enum)
  652. Then
  653. {change "and const1, reg; and const2, reg" to "and (const1 and const2), reg"}
  654. Begin
  655. Taicpu(p).LoadConst(0,Taicpu(p).oper[0].val And Taicpu(hp1).oper[0].val);
  656. asml.Remove(hp1);
  657. hp1.free;
  658. End
  659. Else
  660. {change "and x, reg; jxx" to "test x, reg", if reg is deallocated before the
  661. jump, but only if it's a conditional jump (PFV) }
  662. If (Taicpu(p).oper[1].typ = top_reg) And
  663. GetNextInstruction(p, hp1) And
  664. (hp1.typ = ait_instruction) And
  665. (Taicpu(hp1).is_jmp) and
  666. (Taicpu(hp1).opcode<>A_JMP) and
  667. Not(Taicpu(p).oper[1].reg.enum in UsedRegs) Then
  668. Taicpu(p).opcode := A_TEST;
  669. End;
  670. A_CMP:
  671. Begin
  672. If (Taicpu(p).oper[0].typ = top_const) And
  673. (Taicpu(p).oper[1].typ in [top_reg,top_ref]) And
  674. (Taicpu(p).oper[0].val = 0) and
  675. GetNextInstruction(p, hp1) And
  676. (hp1.typ = ait_instruction) And
  677. (Taicpu(hp1).is_jmp) and
  678. (Taicpu(hp1).opcode=A_Jcc) and
  679. (Taicpu(hp1).condition in [C_LE,C_BE]) and
  680. GetNextInstruction(hp1,hp2) and
  681. (hp2.typ = ait_instruction) and
  682. (Taicpu(hp2).opcode = A_DEC) And
  683. OpsEqual(Taicpu(hp2).oper[0],Taicpu(p).oper[1]) And
  684. GetNextInstruction(hp2, hp3) And
  685. (hp3.typ = ait_instruction) and
  686. (Taicpu(hp3).is_jmp) and
  687. (Taicpu(hp3).opcode = A_JMP) And
  688. GetNextInstruction(hp3, hp4) And
  689. FindLabel(tasmlabel(Taicpu(hp1).oper[0].sym),hp4) Then
  690. Begin
  691. Taicpu(hp2).Opcode := A_SUB;
  692. Taicpu(hp2).Loadoper(1,Taicpu(hp2).oper[0]);
  693. Taicpu(hp2).LoadConst(0,1);
  694. Taicpu(hp2).ops:=2;
  695. Taicpu(hp3).Opcode := A_Jcc;
  696. Case Taicpu(hp1).condition of
  697. C_LE: Taicpu(hp3).condition := C_GE;
  698. C_BE: Taicpu(hp3).condition := C_AE;
  699. End;
  700. asml.Remove(p);
  701. asml.Remove(hp1);
  702. p.free;
  703. hp1.free;
  704. p := hp2;
  705. continue;
  706. End
  707. End;
  708. A_FLD:
  709. Begin
  710. If (Taicpu(p).oper[0].typ = top_reg) And
  711. GetNextInstruction(p, hp1) And
  712. (hp1.typ = Ait_Instruction) And
  713. (Taicpu(hp1).oper[0].typ = top_reg) And
  714. (Taicpu(hp1).oper[1].typ = top_reg) And
  715. (Taicpu(hp1).oper[0].reg.enum = R_ST) And
  716. (Taicpu(hp1).oper[1].reg.enum = R_ST1) Then
  717. { change to
  718. fld reg fxxx reg,st
  719. fxxxp st, st1 (hp1)
  720. Remark: non commutative operations must be reversed!
  721. }
  722. begin
  723. Case Taicpu(hp1).opcode Of
  724. A_FMULP,A_FADDP,
  725. A_FSUBP,A_FDIVP,A_FSUBRP,A_FDIVRP:
  726. begin
  727. Case Taicpu(hp1).opcode Of
  728. A_FADDP: Taicpu(hp1).opcode := A_FADD;
  729. A_FMULP: Taicpu(hp1).opcode := A_FMUL;
  730. A_FSUBP: Taicpu(hp1).opcode := A_FSUBR;
  731. A_FSUBRP: Taicpu(hp1).opcode := A_FSUB;
  732. A_FDIVP: Taicpu(hp1).opcode := A_FDIVR;
  733. A_FDIVRP: Taicpu(hp1).opcode := A_FDIV;
  734. End;
  735. Taicpu(hp1).oper[0].reg := Taicpu(p).oper[0].reg;
  736. Taicpu(hp1).oper[1].reg.enum := R_ST;
  737. asml.Remove(p);
  738. p.free;
  739. p := hp1;
  740. Continue;
  741. end;
  742. end;
  743. end
  744. else
  745. If (Taicpu(p).oper[0].typ = top_ref) And
  746. GetNextInstruction(p, hp2) And
  747. (hp2.typ = Ait_Instruction) And
  748. (Taicpu(hp2).oper[0].typ = top_reg) And
  749. (Taicpu(hp2).oper[1].typ = top_reg) And
  750. (Taicpu(p).opsize in [S_FS, S_FL]) And
  751. (Taicpu(hp2).oper[0].reg.enum = R_ST) And
  752. (Taicpu(hp2).oper[1].reg.enum = R_ST1) Then
  753. If GetLastInstruction(p, hp1) And
  754. (hp1.typ = Ait_Instruction) And
  755. ((Taicpu(hp1).opcode = A_FLD) Or
  756. (Taicpu(hp1).opcode = A_FST)) And
  757. (Taicpu(hp1).opsize = Taicpu(p).opsize) And
  758. (Taicpu(hp1).oper[0].typ = top_ref) And
  759. RefsEqual(Taicpu(p).oper[0].ref^, Taicpu(hp1).oper[0].ref^) Then
  760. If ((Taicpu(hp2).opcode = A_FMULP) Or
  761. (Taicpu(hp2).opcode = A_FADDP)) Then
  762. { change to
  763. fld/fst mem1 (hp1) fld/fst mem1
  764. fld mem1 (p) fadd/
  765. faddp/ fmul st, st
  766. fmulp st, st1 (hp2) }
  767. Begin
  768. asml.Remove(p);
  769. p.free;
  770. p := hp1;
  771. If (Taicpu(hp2).opcode = A_FADDP) Then
  772. Taicpu(hp2).opcode := A_FADD
  773. Else
  774. Taicpu(hp2).opcode := A_FMUL;
  775. Taicpu(hp2).oper[1].reg.enum := R_ST;
  776. End
  777. Else
  778. { change to
  779. fld/fst mem1 (hp1) fld/fst mem1
  780. fld mem1 (p) fld st}
  781. Begin
  782. Taicpu(p).changeopsize(S_FL);
  783. r.enum:=R_ST;
  784. Taicpu(p).loadreg(0,r);
  785. End
  786. Else
  787. Begin
  788. Case Taicpu(hp2).opcode Of
  789. A_FMULP,A_FADDP,A_FSUBP,A_FDIVP,A_FSUBRP,A_FDIVRP:
  790. { change to
  791. fld/fst mem1 (hp1) fld/fst mem1
  792. fld mem2 (p) fxxx mem2
  793. fxxxp st, st1 (hp2) }
  794. Begin
  795. Case Taicpu(hp2).opcode Of
  796. A_FADDP: Taicpu(p).opcode := A_FADD;
  797. A_FMULP: Taicpu(p).opcode := A_FMUL;
  798. A_FSUBP: Taicpu(p).opcode := A_FSUBR;
  799. A_FSUBRP: Taicpu(p).opcode := A_FSUB;
  800. A_FDIVP: Taicpu(p).opcode := A_FDIVR;
  801. A_FDIVRP: Taicpu(p).opcode := A_FDIV;
  802. End;
  803. asml.Remove(hp2);
  804. hp2.free;
  805. End
  806. End
  807. End
  808. End;
  809. A_FSTP,A_FISTP:
  810. if doFpuLoadStoreOpt(asmL,p) then
  811. continue;
  812. A_LEA:
  813. Begin
  814. {removes seg register prefixes from LEA operations, as they
  815. don't do anything}
  816. Taicpu(p).oper[0].ref^.Segment.enum := R_NO;
  817. {changes "lea (%reg1), %reg2" into "mov %reg1, %reg2"}
  818. If (Taicpu(p).oper[0].ref^.Base.enum In [R_EAX..R_EDI]) And
  819. (Taicpu(p).oper[0].ref^.Index.enum = R_NO) And
  820. (Not(Assigned(Taicpu(p).oper[0].ref^.Symbol))) Then
  821. If (Taicpu(p).oper[0].ref^.Base.enum <> Taicpu(p).oper[1].reg.enum)
  822. and (Taicpu(p).oper[0].ref^.Offset = 0)
  823. Then
  824. Begin
  825. hp1 := Taicpu.op_reg_reg(A_MOV, S_L,Taicpu(p).oper[0].ref^.Base,
  826. Taicpu(p).oper[1].reg);
  827. InsertLLItem(AsmL,p.previous,p.next, hp1);
  828. p.free;
  829. p := hp1;
  830. Continue;
  831. End
  832. Else
  833. if (Taicpu(p).oper[0].ref^.Offset = 0) then
  834. Begin
  835. hp1 := Tai(p.Next);
  836. asml.Remove(p);
  837. p.free;
  838. p := hp1;
  839. Continue;
  840. End
  841. else
  842. with Taicpu(p).oper[0].ref^ do
  843. if (Base.enum = Taicpu(p).oper[1].reg.enum) then
  844. begin
  845. l := offset+offsetfixup;
  846. if (l=1) then
  847. begin
  848. Taicpu(p).opcode := A_INC;
  849. Taicpu(p).loadreg(0,Taicpu(p).oper[1].reg);
  850. Taicpu(p).ops := 1
  851. end
  852. else
  853. if (l=-1) then
  854. begin
  855. Taicpu(p).opcode := A_DEC;
  856. Taicpu(p).loadreg(0,Taicpu(p).oper[1].reg);
  857. Taicpu(p).ops := 1;
  858. end
  859. else
  860. begin
  861. Taicpu(p).opcode := A_ADD;
  862. Taicpu(p).loadconst(0,aword(l));
  863. end;
  864. end;
  865. End;
  866. A_MOV:
  867. Begin
  868. TmpUsedRegs := UsedRegs;
  869. If (Taicpu(p).oper[1].typ = top_reg) And
  870. (Taicpu(p).oper[1].reg.enum In [R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI]) And
  871. GetNextInstruction(p, hp1) And
  872. (Tai(hp1).typ = ait_instruction) And
  873. (Taicpu(hp1).opcode = A_MOV) And
  874. (Taicpu(hp1).oper[0].typ = top_reg) And
  875. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum)
  876. Then
  877. {we have "mov x, %treg; mov %treg, y}
  878. If not(RegUsedAfterInstruction(Taicpu(p).oper[1].reg, hp1, TmpUsedRegs)) then
  879. {we've got "mov x, %treg; mov %treg, y; with %treg is not used after }
  880. Case Taicpu(p).oper[0].typ Of
  881. top_reg:
  882. Begin
  883. { change "mov %reg, %treg; mov %treg, y"
  884. to "mov %reg, y" }
  885. Taicpu(p).LoadOper(1,Taicpu(hp1).oper[1]);
  886. asml.Remove(hp1);
  887. hp1.free;
  888. continue;
  889. End;
  890. top_ref:
  891. If (Taicpu(hp1).oper[1].typ = top_reg) Then
  892. Begin
  893. { change "mov mem, %treg; mov %treg, %reg"
  894. to "mov mem, %reg" }
  895. Taicpu(p).Loadoper(1,Taicpu(hp1).oper[1]);
  896. asml.Remove(hp1);
  897. hp1.free;
  898. continue;
  899. End;
  900. End
  901. Else
  902. Else
  903. {Change "mov %reg1, %reg2; xxx %reg2, ???" to
  904. "mov %reg1, %reg2; xxx %reg1, ???" to avoid a write/read
  905. penalty}
  906. If (Taicpu(p).oper[0].typ = top_reg) And
  907. (Taicpu(p).oper[1].typ = top_reg) And
  908. GetNextInstruction(p,hp1) And
  909. (Tai(hp1).typ = ait_instruction) And
  910. (Taicpu(hp1).oper[0].typ = top_reg) And
  911. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum)
  912. Then
  913. {we have "mov %reg1, %reg2; XXX %reg2, ???"}
  914. Begin
  915. If ((Taicpu(hp1).opcode = A_OR) Or
  916. (Taicpu(hp1).opcode = A_TEST)) And
  917. (Taicpu(hp1).oper[1].typ = top_reg) And
  918. (Taicpu(hp1).oper[0].reg.enum = Taicpu(hp1).oper[1].reg.enum)
  919. Then
  920. {we have "mov %reg1, %reg2; test/or %reg2, %reg2"}
  921. Begin
  922. TmpUsedRegs := UsedRegs;
  923. { reg1 will be used after the first instruction, }
  924. { so update the allocation info }
  925. allocRegBetween(asmL,Taicpu(p).oper[0].reg,p,hp1);
  926. If GetNextInstruction(hp1, hp2) And
  927. (hp2.typ = ait_instruction) And
  928. Taicpu(hp2).is_jmp and
  929. Not(RegUsedAfterInstruction(Taicpu(hp1).oper[0].reg, hp1, TmpUsedRegs))
  930. Then
  931. {change "mov %reg1, %reg2; test/or %reg2, %reg2; jxx" to
  932. "test %reg1, %reg1; jxx"}
  933. Begin
  934. Taicpu(hp1).Loadoper(0,Taicpu(p).oper[0]);
  935. Taicpu(hp1).Loadoper(1,Taicpu(p).oper[0]);
  936. asml.Remove(p);
  937. p.free;
  938. p := hp1;
  939. continue
  940. End
  941. Else
  942. {change "mov %reg1, %reg2; test/or %reg2, %reg2" to
  943. "mov %reg1, %reg2; test/or %reg1, %reg1"}
  944. Begin
  945. Taicpu(hp1).Loadoper(0,Taicpu(p).oper[0]);
  946. Taicpu(hp1).Loadoper(1,Taicpu(p).oper[0]);
  947. End;
  948. End
  949. { Else
  950. If (Taicpu(p.next)^.opcode
  951. In [A_PUSH, A_OR, A_XOR, A_AND, A_TEST])}
  952. {change "mov %reg1, %reg2; push/or/xor/... %reg2, ???" to
  953. "mov %reg1, %reg2; push/or/xor/... %reg1, ???"}
  954. End
  955. Else
  956. {leave out the mov from "mov reg, x(%frame_pointer); leave/ret" (with
  957. x >= RetOffset) as it doesn't do anything (it writes either to a
  958. parameter or to the temporary storage room for the function
  959. result)}
  960. If GetNextInstruction(p, hp1) And
  961. (Tai(hp1).typ = ait_instruction)
  962. Then
  963. If ((Taicpu(hp1).opcode = A_LEAVE) Or
  964. (Taicpu(hp1).opcode = A_RET)) And
  965. (Taicpu(p).oper[1].typ = top_ref) And
  966. (Taicpu(p).oper[1].ref^.base.enum = current_procinfo.FramePointer.enum) And
  967. (Taicpu(p).oper[1].ref^.offset >= current_procinfo.Return_Offset) And
  968. (Taicpu(p).oper[1].ref^.index.enum = R_NO) And
  969. (Taicpu(p).oper[0].typ = top_reg)
  970. Then
  971. Begin
  972. asml.Remove(p);
  973. p.free;
  974. p := hp1;
  975. RemoveLastDeallocForFuncRes(asmL,p);
  976. End
  977. Else
  978. If (Taicpu(p).oper[0].typ = top_reg) And
  979. (Taicpu(p).oper[1].typ = top_ref) And
  980. (Taicpu(p).opsize = Taicpu(hp1).opsize) And
  981. (Taicpu(hp1).opcode = A_CMP) And
  982. (Taicpu(hp1).oper[1].typ = top_ref) And
  983. RefsEqual(Taicpu(p).oper[1].ref^, Taicpu(hp1).oper[1].ref^) Then
  984. {change "mov reg1, mem1; cmp x, mem1" to "mov reg, mem1; cmp x, reg1"}
  985. begin
  986. Taicpu(hp1).loadreg(1,Taicpu(p).oper[0].reg);
  987. allocRegBetween(asmL,Taicpu(p).oper[0].reg,p,hp1);
  988. end;
  989. { Next instruction is also a MOV ? }
  990. If GetNextInstruction(p, hp1) And
  991. (Tai(hp1).typ = ait_instruction) and
  992. (Taicpu(hp1).opcode = A_MOV) and
  993. (Taicpu(hp1).opsize = Taicpu(p).opsize)
  994. Then
  995. Begin
  996. If (Taicpu(hp1).oper[0].typ = Taicpu(p).oper[1].typ) and
  997. (Taicpu(hp1).oper[1].typ = Taicpu(p).oper[0].typ)
  998. Then
  999. {mov reg1, mem1 or mov mem1, reg1
  1000. mov mem2, reg2 mov reg2, mem2}
  1001. Begin
  1002. If OpsEqual(Taicpu(hp1).oper[1],Taicpu(p).oper[0]) Then
  1003. {mov reg1, mem1 or mov mem1, reg1
  1004. mov mem2, reg1 mov reg2, mem1}
  1005. Begin
  1006. If OpsEqual(Taicpu(hp1).oper[0],Taicpu(p).oper[1]) Then
  1007. { Removes the second statement from
  1008. mov reg1, mem1/reg2
  1009. mov mem1/reg2, reg1 }
  1010. Begin
  1011. if (Taicpu(p).oper[0].typ = top_reg) then
  1012. AllocRegBetween(asmL,Taicpu(p).oper[0].reg,p,hp1);
  1013. asml.remove(hp1);
  1014. hp1.free;
  1015. End
  1016. Else
  1017. Begin
  1018. TmpUsedRegs := UsedRegs;
  1019. UpdateUsedRegs(TmpUsedRegs, Tai(hp1.next));
  1020. If (Taicpu(p).oper[1].typ = top_ref) And
  1021. { mov reg1, mem1
  1022. mov mem2, reg1 }
  1023. GetNextInstruction(hp1, hp2) And
  1024. (hp2.typ = ait_instruction) And
  1025. (Taicpu(hp2).opcode = A_CMP) And
  1026. (Taicpu(hp2).opsize = Taicpu(p).opsize) and
  1027. (Taicpu(hp2).oper[0].typ = TOp_Ref) And
  1028. (Taicpu(hp2).oper[1].typ = TOp_Reg) And
  1029. RefsEqual(Taicpu(hp2).oper[0].ref^, Taicpu(p).oper[1].ref^) And
  1030. (Taicpu(hp2).oper[1].reg .enum= Taicpu(p).oper[0].reg.enum) And
  1031. Not(RegUsedAfterInstruction(Taicpu(p).oper[0].reg, hp2, TmpUsedRegs)) Then
  1032. { change to
  1033. mov reg1, mem1 mov reg1, mem1
  1034. mov mem2, reg1 cmp reg1, mem2
  1035. cmp mem1, reg1 }
  1036. Begin
  1037. asml.Remove(hp2);
  1038. hp2.free;
  1039. Taicpu(hp1).opcode := A_CMP;
  1040. Taicpu(hp1).loadref(1,Taicpu(hp1).oper[0].ref^);
  1041. Taicpu(hp1).loadreg(0,Taicpu(p).oper[0].reg);
  1042. End;
  1043. End;
  1044. End
  1045. Else
  1046. Begin
  1047. tmpUsedRegs := UsedRegs;
  1048. r.enum:=R_EDI;
  1049. If GetNextInstruction(hp1, hp2) And
  1050. (Taicpu(p).oper[0].typ = top_ref) And
  1051. (Taicpu(p).oper[1].typ = top_reg) And
  1052. (Taicpu(hp1).oper[0].typ = top_reg) And
  1053. (Taicpu(hp1).oper[0].reg.enum = Taicpu(p).oper[1].reg.enum) And
  1054. (Taicpu(hp1).oper[1].typ = top_ref) And
  1055. (Tai(hp2).typ = ait_instruction) And
  1056. (Taicpu(hp2).opcode = A_MOV) And
  1057. (Taicpu(hp2).opsize = Taicpu(p).opsize) and
  1058. (Taicpu(hp2).oper[1].typ = top_reg) And
  1059. (Taicpu(hp2).oper[0].typ = top_ref) And
  1060. RefsEqual(Taicpu(hp2).oper[0].ref^, Taicpu(hp1).oper[1].ref^) Then
  1061. If not regInRef(Taicpu(hp2).oper[1].reg,Taicpu(hp2).oper[0].ref^) and
  1062. (Taicpu(p).oper[1].reg.enum in [R_DI,R_EDI]) and
  1063. not(RegUsedAfterInstruction(r,hp1,tmpUsedRegs)) Then
  1064. { mov mem1, %edi
  1065. mov %edi, mem2
  1066. mov mem2, reg2
  1067. to:
  1068. mov mem1, reg2
  1069. mov reg2, mem2}
  1070. Begin
  1071. AllocRegBetween(asmL,reg32(Taicpu(hp2).oper[1].reg),p,hp2);
  1072. Taicpu(p).Loadoper(1,Taicpu(hp2).oper[1]);
  1073. Taicpu(hp1).loadoper(0,Taicpu(hp2).oper[1]);
  1074. asml.Remove(hp2);
  1075. hp2.free;
  1076. End
  1077. Else
  1078. If (Taicpu(p).oper[1].reg.enum <> Taicpu(hp2).oper[1].reg.enum) And
  1079. not(RegInRef(Taicpu(p).oper[1].reg,Taicpu(p).oper[0].ref^)) And
  1080. not(RegInRef(Taicpu(hp2).oper[1].reg,Taicpu(hp2).oper[0].ref^))
  1081. Then
  1082. { mov mem1, reg1 mov mem1, reg1
  1083. mov reg1, mem2 mov reg1, mem2
  1084. mov mem2, reg2 mov mem2, reg1
  1085. to: to:
  1086. mov mem1, reg1 mov mem1, reg1
  1087. mov mem1, reg2 mov reg1, mem2
  1088. mov reg1, mem2
  1089. or (if mem1 depends on reg1
  1090. and/or if mem2 depends on reg2)
  1091. to:
  1092. mov mem1, reg1
  1093. mov reg1, mem2
  1094. mov reg1, reg2
  1095. }
  1096. Begin
  1097. Taicpu(hp1).LoadRef(0,Taicpu(p).oper[0].ref^);
  1098. Taicpu(hp1).LoadReg(1,Taicpu(hp2).oper[1].reg);
  1099. Taicpu(hp2).LoadRef(1,Taicpu(hp2).oper[0].ref^);
  1100. Taicpu(hp2).LoadReg(0,Taicpu(p).oper[1].reg);
  1101. allocRegBetween(asmL,Taicpu(p).oper[1].reg,p,hp2);
  1102. { if (Taicpu(p).oper[0].ref^.base.enum in (rg.usableregsint+[R_EDI])) then
  1103. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.base,p,hp2);
  1104. if (Taicpu(p).oper[0].ref^.index.enum in (rg.usableregsint+[R_EDI])) then
  1105. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.index,p,hp2);}
  1106. if (Taicpu(p).oper[0].ref^.base.enum in [R_EDI]) then
  1107. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.base,p,hp2);
  1108. if (Taicpu(p).oper[0].ref^.index.enum in [R_EDI]) then
  1109. allocRegBetween(asmL,Taicpu(p).oper[0].ref^.index,p,hp2);
  1110. End
  1111. Else
  1112. If (Taicpu(hp1).Oper[0].reg.enum <> Taicpu(hp2).Oper[1].reg.enum) Then
  1113. begin
  1114. Taicpu(hp2).LoadReg(0,Taicpu(hp1).Oper[0].reg);
  1115. allocRegBetween(asmL,Taicpu(p).oper[1].reg,p,hp2);
  1116. end
  1117. else
  1118. begin
  1119. asml.Remove(hp2);
  1120. hp2.free;
  1121. end
  1122. End;
  1123. End
  1124. Else
  1125. (* {movl [mem1],reg1
  1126. movl [mem1],reg2
  1127. to:
  1128. movl [mem1],reg1
  1129. movl reg1,reg2 }
  1130. If (Taicpu(p).oper[0].typ = top_ref) and
  1131. (Taicpu(p).oper[1].typ = top_reg) and
  1132. (Taicpu(hp1).oper[0].typ = top_ref) and
  1133. (Taicpu(hp1).oper[1].typ = top_reg) and
  1134. (Taicpu(p).opsize = Taicpu(hp1).opsize) and
  1135. RefsEqual(TReference(Taicpu(p).oper[0]^),Taicpu(hp1).oper[0]^.ref^) and
  1136. (Taicpu(p).oper[1].reg<>Taicpu(hp1).oper[0]^.ref^.base) and
  1137. (Taicpu(p).oper[1].reg<>Taicpu(hp1).oper[0]^.ref^.index) then
  1138. Taicpu(hp1).LoadReg(0,Taicpu(p).oper[1].reg)
  1139. Else*)
  1140. { movl const1,[mem1]
  1141. movl [mem1],reg1
  1142. to:
  1143. movl const1,reg1
  1144. movl reg1,[mem1] }
  1145. If (Taicpu(p).oper[0].typ = top_const) and
  1146. (Taicpu(p).oper[1].typ = top_ref) and
  1147. (Taicpu(hp1).oper[0].typ = top_ref) and
  1148. (Taicpu(hp1).oper[1].typ = top_reg) and
  1149. (Taicpu(p).opsize = Taicpu(hp1).opsize) and
  1150. RefsEqual(Taicpu(hp1).oper[0].ref^,Taicpu(p).oper[1].ref^) then
  1151. Begin
  1152. allocregbetween(asml,Taicpu(hp1).oper[1].reg,p,hp1);
  1153. { allocregbetween doesn't insert this because at }
  1154. { this time, no regalloc info is available in }
  1155. { the optinfo field, so do it manually (JM) }
  1156. hp2 := tai_regalloc.Alloc(Taicpu(hp1).oper[1].reg);
  1157. insertllitem(asml,p.previous,p,hp2);
  1158. Taicpu(hp1).LoadReg(0,Taicpu(hp1).oper[1].reg);
  1159. Taicpu(hp1).LoadRef(1,Taicpu(p).oper[1].ref^);
  1160. Taicpu(p).LoadReg(1,Taicpu(hp1).oper[0].reg);
  1161. End
  1162. End;
  1163. End;
  1164. A_MOVZX:
  1165. Begin
  1166. {removes superfluous And's after movzx's}
  1167. If (Taicpu(p).oper[1].typ = top_reg) And
  1168. GetNextInstruction(p, hp1) And
  1169. (Tai(hp1).typ = ait_instruction) And
  1170. (Taicpu(hp1).opcode = A_AND) And
  1171. (Taicpu(hp1).oper[0].typ = top_const) And
  1172. (Taicpu(hp1).oper[1].typ = top_reg) And
  1173. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1174. Then
  1175. Case Taicpu(p).opsize Of
  1176. S_BL, S_BW:
  1177. If (Taicpu(hp1).oper[0].val = $ff) Then
  1178. Begin
  1179. asml.Remove(hp1);
  1180. hp1.free;
  1181. End;
  1182. S_WL:
  1183. If (Taicpu(hp1).oper[0].val = $ffff) Then
  1184. Begin
  1185. asml.Remove(hp1);
  1186. hp1.free;
  1187. End;
  1188. End;
  1189. {changes some movzx constructs to faster synonims (all examples
  1190. are given with eax/ax, but are also valid for other registers)}
  1191. If (Taicpu(p).oper[1].typ = top_reg) Then
  1192. If (Taicpu(p).oper[0].typ = top_reg) Then
  1193. Case Taicpu(p).opsize of
  1194. S_BW:
  1195. Begin
  1196. If (rg.makeregsize(Taicpu(p).oper[0].reg,OS_16).enum=Taicpu(p).oper[1].reg.enum) And
  1197. Not(CS_LittleSize In aktglobalswitches)
  1198. Then
  1199. {Change "movzbw %al, %ax" to "andw $0x0ffh, %ax"}
  1200. Begin
  1201. Taicpu(p).opcode := A_AND;
  1202. Taicpu(p).changeopsize(S_W);
  1203. Taicpu(p).LoadConst(0,$ff);
  1204. End
  1205. Else
  1206. If GetNextInstruction(p, hp1) And
  1207. (Tai(hp1).typ = ait_instruction) And
  1208. (Taicpu(hp1).opcode = A_AND) And
  1209. (Taicpu(hp1).oper[0].typ = top_const) And
  1210. (Taicpu(hp1).oper[1].typ = top_reg) And
  1211. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1212. Then
  1213. {Change "movzbw %reg1, %reg2; andw $const, %reg2"
  1214. to "movw %reg1, reg2; andw $(const1 and $ff), %reg2"}
  1215. Begin
  1216. Taicpu(p).opcode := A_MOV;
  1217. Taicpu(p).changeopsize(S_W);
  1218. Taicpu(p).LoadReg(0,rg.makeregsize(Taicpu(p).oper[0].reg,OS_16));
  1219. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1220. End;
  1221. End;
  1222. S_BL:
  1223. Begin
  1224. If (rg.makeregsize(Taicpu(p).oper[0].reg,OS_32).enum=Taicpu(p).oper[1].reg.enum) And
  1225. Not(CS_LittleSize in aktglobalswitches)
  1226. Then
  1227. {Change "movzbl %al, %eax" to "andl $0x0ffh, %eax"}
  1228. Begin
  1229. Taicpu(p).opcode := A_AND;
  1230. Taicpu(p).changeopsize(S_L);
  1231. Taicpu(p).loadconst(0,$ff)
  1232. End
  1233. Else
  1234. If GetNextInstruction(p, hp1) And
  1235. (Tai(hp1).typ = ait_instruction) And
  1236. (Taicpu(hp1).opcode = A_AND) And
  1237. (Taicpu(hp1).oper[0].typ = top_const) And
  1238. (Taicpu(hp1).oper[1].typ = top_reg) And
  1239. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1240. Then
  1241. {Change "movzbl %reg1, %reg2; andl $const, %reg2"
  1242. to "movl %reg1, reg2; andl $(const1 and $ff), %reg2"}
  1243. Begin
  1244. Taicpu(p).opcode := A_MOV;
  1245. Taicpu(p).changeopsize(S_L);
  1246. Taicpu(p).LoadReg(0,rg.makeregsize(Taicpu(p).oper[0].reg,OS_32));
  1247. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1248. End
  1249. End;
  1250. S_WL:
  1251. Begin
  1252. If (rg.makeregsize(Taicpu(p).oper[0].reg,OS_32).enum=Taicpu(p).oper[1].reg.enum) And
  1253. Not(CS_LittleSize In aktglobalswitches)
  1254. Then
  1255. {Change "movzwl %ax, %eax" to "andl $0x0ffffh, %eax"}
  1256. Begin
  1257. Taicpu(p).opcode := A_AND;
  1258. Taicpu(p).changeopsize(S_L);
  1259. Taicpu(p).LoadConst(0,$ffff);
  1260. End
  1261. Else
  1262. If GetNextInstruction(p, hp1) And
  1263. (Tai(hp1).typ = ait_instruction) And
  1264. (Taicpu(hp1).opcode = A_AND) And
  1265. (Taicpu(hp1).oper[0].typ = top_const) And
  1266. (Taicpu(hp1).oper[1].typ = top_reg) And
  1267. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum)
  1268. Then
  1269. {Change "movzwl %reg1, %reg2; andl $const, %reg2"
  1270. to "movl %reg1, reg2; andl $(const1 and $ffff), %reg2"}
  1271. Begin
  1272. Taicpu(p).opcode := A_MOV;
  1273. Taicpu(p).changeopsize(S_L);
  1274. Taicpu(p).LoadReg(0,rg.makeregsize(Taicpu(p).oper[0].reg,OS_32));
  1275. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ffff);
  1276. End;
  1277. End;
  1278. End
  1279. Else
  1280. If (Taicpu(p).oper[0].typ = top_ref) Then
  1281. Begin
  1282. If GetNextInstruction(p, hp1) And
  1283. (Tai(hp1).typ = ait_instruction) And
  1284. (Taicpu(hp1).opcode = A_AND) And
  1285. (Taicpu(hp1).oper[0].typ = Top_Const) And
  1286. (Taicpu(hp1).oper[1].typ = Top_Reg) And
  1287. (Taicpu(hp1).oper[1].reg.enum = Taicpu(p).oper[1].reg.enum) Then
  1288. Begin
  1289. Taicpu(p).opcode := A_MOV;
  1290. Case Taicpu(p).opsize Of
  1291. S_BL:
  1292. Begin
  1293. Taicpu(p).changeopsize(S_L);
  1294. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1295. End;
  1296. S_WL:
  1297. Begin
  1298. Taicpu(p).changeopsize(S_L);
  1299. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ffff);
  1300. End;
  1301. S_BW:
  1302. Begin
  1303. Taicpu(p).changeopsize(S_W);
  1304. Taicpu(hp1).LoadConst(0,Taicpu(hp1).oper[0].val And $ff);
  1305. End;
  1306. End;
  1307. End;
  1308. End;
  1309. End;
  1310. A_POP:
  1311. Begin
  1312. if target_info.system=system_i386_go32v2 then
  1313. begin
  1314. { Transform a series of pop/pop/pop/push/push/push to }
  1315. { 'movl x(%esp),%reg' for go32v2 (not for the rest, }
  1316. { because I'm not sure whether they can cope with }
  1317. { 'movl x(%esp),%reg' with x > 0, I believe we had }
  1318. { such a problem when using esp as frame pointer (JM) }
  1319. if (Taicpu(p).oper[0].typ = top_reg) then
  1320. begin
  1321. hp1 := p;
  1322. hp2 := p;
  1323. l := 0;
  1324. while getNextInstruction(hp1,hp1) and
  1325. (hp1.typ = ait_instruction) and
  1326. (Taicpu(hp1).opcode = A_POP) and
  1327. (Taicpu(hp1).oper[0].typ = top_reg) do
  1328. begin
  1329. hp2 := hp1;
  1330. inc(l,4);
  1331. end;
  1332. getLastInstruction(p,hp3);
  1333. l1 := 0;
  1334. while (hp2 <> hp3) and
  1335. assigned(hp1) and
  1336. (hp1.typ = ait_instruction) and
  1337. (Taicpu(hp1).opcode = A_PUSH) and
  1338. (Taicpu(hp1).oper[0].typ = top_reg) and
  1339. (Taicpu(hp1).oper[0].reg.enum = Taicpu(hp2).oper[0].reg.enum) do
  1340. begin
  1341. { change it to a two op operation }
  1342. Taicpu(hp2).oper[1].typ:=top_none;
  1343. Taicpu(hp2).ops:=2;
  1344. Taicpu(hp2).opcode := A_MOV;
  1345. Taicpu(hp2).Loadoper(1,Taicpu(hp1).oper[0]);
  1346. reference_reset_old(tmpref);
  1347. tmpRef.base .enum:= STACK_POINTER_REG;
  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 >= current_procinfo.Return_Offset) 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,rg.makeregsize(Taicpu(hp1).oper[0].reg,OS_32));
  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_regalloc 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,rg.makeregsize(Taicpu(p).oper[1].reg,OS_8));
  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,rg.makeregsize(Taicpu(p).oper[1].reg,OS_8));
  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.43 2003-04-27 11:21:35 peter
  2017. * aktprocdef renamed to current_procdef
  2018. * procinfo renamed to current_procinfo
  2019. * procinfo will now be stored in current_module so it can be
  2020. cleaned up properly
  2021. * gen_main_procsym changed to create_main_proc and release_main_proc
  2022. to also generate a tprocinfo structure
  2023. * fixed unit implicit initfinal
  2024. Revision 1.42 2003/03/28 19:16:57 peter
  2025. * generic constructor working for i386
  2026. * remove fixed self register
  2027. * esi added as address register for i386
  2028. Revision 1.41 2003/02/26 13:24:59 daniel
  2029. * Disabled mov reg,0 -> xor reg,reg optimization
  2030. Revision 1.40 2003/02/25 07:41:54 daniel
  2031. * Properly fixed reversed operands bug
  2032. Revision 1.39 2003/02/24 21:27:01 daniel
  2033. * Reversed operand order in an optimization in postpeepholeopt
  2034. Revision 1.38 2003/02/19 22:39:56 daniel
  2035. * Fixed a few issues
  2036. Revision 1.37 2003/02/19 22:00:16 daniel
  2037. * Code generator converted to new register notation
  2038. - Horribily outdated todo.txt removed
  2039. Revision 1.36 2003/01/08 18:43:57 daniel
  2040. * Tregister changed into a record
  2041. Revision 1.35 2002/11/15 16:30:54 peter
  2042. * made tasmsymbol.refs private (merged)
  2043. Revision 1.34 2002/08/18 20:06:30 peter
  2044. * inlining is now also allowed in interface
  2045. * renamed write/load to ppuwrite/ppuload
  2046. * tnode storing in ppu
  2047. * nld,ncon,nbas are already updated for storing in ppu
  2048. Revision 1.33 2002/08/17 09:23:46 florian
  2049. * first part of procinfo rewrite
  2050. Revision 1.32 2002/08/11 14:32:30 peter
  2051. * renamed current_library to objectlibrary
  2052. Revision 1.31 2002/08/11 13:24:17 peter
  2053. * saving of asmsymbols in ppu supported
  2054. * asmsymbollist global is removed and moved into a new class
  2055. tasmlibrarydata that will hold the info of a .a file which
  2056. corresponds with a single module. Added librarydata to tmodule
  2057. to keep the library info stored for the module. In the future the
  2058. objectfiles will also be stored to the tasmlibrarydata class
  2059. * all getlabel/newasmsymbol and friends are moved to the new class
  2060. Revision 1.30 2002/07/26 21:15:43 florian
  2061. * rewrote the system handling
  2062. Revision 1.29 2002/07/01 18:46:34 peter
  2063. * internal linker
  2064. * reorganized aasm layer
  2065. Revision 1.28 2002/06/09 12:55:23 jonas
  2066. * fixed detection of register usage
  2067. Revision 1.27 2002/05/18 13:34:25 peter
  2068. * readded missing revisions
  2069. Revision 1.26 2002/05/16 19:46:52 carl
  2070. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  2071. + try to fix temp allocation (still in ifdef)
  2072. + generic constructor calls
  2073. + start of tassembler / tmodulebase class cleanup
  2074. Revision 1.24 2002/05/12 16:53:18 peter
  2075. * moved entry and exitcode to ncgutil and cgobj
  2076. * foreach gets extra argument for passing local data to the
  2077. iterator function
  2078. * -CR checks also class typecasts at runtime by changing them
  2079. into as
  2080. * fixed compiler to cycle with the -CR option
  2081. * fixed stabs with elf writer, finally the global variables can
  2082. be watched
  2083. * removed a lot of routines from cga unit and replaced them by
  2084. calls to cgobj
  2085. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  2086. u32bit then the other is typecasted also to u32bit without giving
  2087. a rangecheck warning/error.
  2088. * fixed pascal calling method with reversing also the high tree in
  2089. the parast, detected by tcalcst3 test
  2090. Revision 1.23 2002/04/21 15:40:49 carl
  2091. * changeregsize -> rg.makeregsize
  2092. Revision 1.22 2002/04/20 21:37:07 carl
  2093. + generic FPC_CHECKPOINTER
  2094. + first parameter offset in stack now portable
  2095. * rename some constants
  2096. + move some cpu stuff to other units
  2097. - remove unused constents
  2098. * fix stacksize for some targets
  2099. * fix generic size problems which depend now on EXTEND_SIZE constant
  2100. * removing frame pointer in routines is only available for : i386,m68k and vis targets
  2101. Revision 1.21 2002/04/15 19:44:21 peter
  2102. * fixed stackcheck that would be called recursively when a stack
  2103. error was found
  2104. * generic rg.makeregsize(reg,size) for i386 register resizing
  2105. * removed some more routines from cga unit
  2106. * fixed returnvalue handling
  2107. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  2108. Revision 1.20 2002/04/02 20:30:16 jonas
  2109. + support for folding inc/dec in shl/add/sub sequences toa single lea
  2110. instruction
  2111. Revision 1.19 2002/04/02 13:01:58 jonas
  2112. * fixed nasty bug in "and" peepholeoptimization that caused wrong
  2113. optimizations after Peter's big location patch
  2114. Revision 1.18 2002/03/31 20:26:40 jonas
  2115. + a_loadfpu_* and a_loadmm_* methods in tcg
  2116. * register allocation is now handled by a class and is mostly processor
  2117. independent (+rgobj.pas and i386/rgcpu.pas)
  2118. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  2119. * some small improvements and fixes to the optimizer
  2120. * some register allocation fixes
  2121. * some fpuvaroffset fixes in the unary minus node
  2122. * push/popusedregisters is now called rg.save/restoreusedregisters and
  2123. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  2124. also better optimizable)
  2125. * fixed and optimized register saving/restoring for new/dispose nodes
  2126. * LOC_FPU locations now also require their "register" field to be set to
  2127. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  2128. - list field removed of the tnode class because it's not used currently
  2129. and can cause hard-to-find bugs
  2130. }