popt386.pas 107 KB

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