popt386.pas 125 KB

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