popt386.pas 124 KB

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