popt386.pas 114 KB

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