aoptarm.pas 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519
  1. {
  2. Copyright (c) 1998-2020 by Jonas Maebe and Florian Klaempfl, members of the Free Pascal
  3. Development Team
  4. This unit implements an ARM optimizer object used commonly for ARM and AAarch64
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit aoptarm;
  19. {$i fpcdefs.inc}
  20. { $define DEBUG_PREREGSCHEDULER}
  21. {$ifdef EXTDEBUG}
  22. {$define DEBUG_AOPTCPU}
  23. {$endif EXTDEBUG}
  24. Interface
  25. uses
  26. cgbase, cgutils, cpubase, aasmtai, aasmcpu,aopt, aoptobj;
  27. Type
  28. { while ARM and AAarch64 look not very similar at a first glance,
  29. several optimizations can be shared between both }
  30. TARMAsmOptimizer = class(TAsmOptimizer)
  31. procedure DebugMsg(const s : string; p : tai);
  32. function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
  33. function RedundantMovProcess(var p: tai; var hp1: tai): boolean;
  34. function GetNextInstructionUsingReg(Current: tai; out Next: tai; const reg: TRegister): Boolean;
  35. function OptPass1UXTB(var p: tai): Boolean;
  36. function OptPass1UXTH(var p: tai): Boolean;
  37. function OptPass1SXTB(var p: tai): Boolean;
  38. function OptPass1SXTH(var p: tai): Boolean;
  39. function OptPass1LDR(var p: tai): Boolean; virtual;
  40. function OptPass1STR(var p: tai): Boolean; virtual;
  41. function OptPass1And(var p: tai): Boolean; virtual;
  42. End;
  43. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  44. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  45. {$ifdef AARCH64}
  46. function MatchInstruction(const instr: tai; const ops : array of TAsmOp; const postfix: TOpPostfixes): boolean;
  47. {$endif AARCH64}
  48. function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
  49. function RefsEqual(const r1, r2: treference): boolean;
  50. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  51. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  52. Implementation
  53. uses
  54. cutils,verbose,globtype,globals,
  55. systems,
  56. cpuinfo,
  57. cgobj,procinfo,
  58. aasmbase,aasmdata,itcpugas;
  59. {$ifdef DEBUG_AOPTCPU}
  60. const
  61. SPeepholeOptimization: shortstring = 'Peephole Optimization: ';
  62. procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);
  63. begin
  64. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  65. end;
  66. {$else DEBUG_AOPTCPU}
  67. { Empty strings help the optimizer to remove string concatenations that won't
  68. ever appear to the user on release builds. [Kit] }
  69. const
  70. SPeepholeOptimization = '';
  71. procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  72. begin
  73. end;
  74. {$endif DEBUG_AOPTCPU}
  75. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  76. begin
  77. result :=
  78. (instr.typ = ait_instruction) and
  79. ((op = []) or ((taicpu(instr).opcode<=LastCommonAsmOp) and (taicpu(instr).opcode in op))) and
  80. ((cond = []) or (taicpu(instr).condition in cond)) and
  81. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  82. end;
  83. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  84. begin
  85. result :=
  86. (instr.typ = ait_instruction) and
  87. (taicpu(instr).opcode = op) and
  88. ((cond = []) or (taicpu(instr).condition in cond)) and
  89. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  90. end;
  91. {$ifdef AARCH64}
  92. function MatchInstruction(const instr: tai; const ops : array of TAsmOp; const postfix: TOpPostfixes): boolean;
  93. var
  94. op : TAsmOp;
  95. begin
  96. result:=false;
  97. if instr.typ <> ait_instruction then
  98. exit;
  99. for op in ops do
  100. begin
  101. if (taicpu(instr).opcode = op) and
  102. ((postfix = []) or (taicpu(instr).oppostfix in postfix)) then
  103. begin
  104. result:=true;
  105. exit;
  106. end;
  107. end;
  108. end;
  109. {$endif AARCH64}
  110. function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
  111. begin
  112. result :=
  113. (instr.typ = ait_instruction) and
  114. (taicpu(instr).opcode = op) and
  115. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  116. end;
  117. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  118. begin
  119. result := (oper.typ = top_reg) and (oper.reg = reg);
  120. end;
  121. function RefsEqual(const r1, r2: treference): boolean;
  122. begin
  123. refsequal :=
  124. (r1.offset = r2.offset) and
  125. (r1.base = r2.base) and
  126. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  127. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  128. (r1.relsymbol = r2.relsymbol) and
  129. {$ifdef ARM}
  130. (r1.signindex = r2.signindex) and
  131. {$endif ARM}
  132. (r1.shiftimm = r2.shiftimm) and
  133. (r1.addressmode = r2.addressmode) and
  134. (r1.shiftmode = r2.shiftmode) and
  135. (r1.volatility=[]) and
  136. (r2.volatility=[]);
  137. end;
  138. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  139. begin
  140. result := oper1.typ = oper2.typ;
  141. if result then
  142. case oper1.typ of
  143. top_const:
  144. Result:=oper1.val = oper2.val;
  145. top_reg:
  146. Result:=oper1.reg = oper2.reg;
  147. top_conditioncode:
  148. Result:=oper1.cc = oper2.cc;
  149. top_realconst:
  150. Result:=oper1.val_real = oper2.val_real;
  151. top_ref:
  152. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  153. else Result:=false;
  154. end
  155. end;
  156. function TARMAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  157. Out Next: tai; const reg: TRegister): Boolean;
  158. var
  159. gniResult: Boolean;
  160. begin
  161. Next:=Current;
  162. Result := False;
  163. repeat
  164. gniResult:=GetNextInstruction(Next,Next);
  165. if gniResult and RegInInstruction(reg,Next) then
  166. { Found something }
  167. Exit(True);
  168. until not gniResult or
  169. not(cs_opt_level3 in current_settings.optimizerswitches) or
  170. (Next.typ<>ait_instruction) or
  171. is_calljmp(taicpu(Next).opcode)
  172. {$ifdef ARM}
  173. or RegModifiedByInstruction(NR_PC,Next)
  174. {$endif ARM}
  175. ;
  176. end;
  177. function TARMAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
  178. var
  179. alloc,
  180. dealloc : tai_regalloc;
  181. hp1 : tai;
  182. begin
  183. Result:=false;
  184. if MatchInstruction(movp, A_MOV, [taicpu(p).condition], [PF_None]) and
  185. { We can't optimize if there is a shiftop }
  186. (taicpu(movp).ops=2) and
  187. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  188. { don't mess with moves to fp }
  189. (taicpu(movp).oper[0]^.reg<>current_procinfo.framepointer) and
  190. { the destination register of the mov might not be used beween p and movp }
  191. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  192. {$ifdef ARM}
  193. { PC should be changed only by moves }
  194. (taicpu(movp).oper[0]^.reg<>NR_PC) and
  195. { cb[n]z are thumb instructions which require specific registers, with no wide forms }
  196. (taicpu(p).opcode<>A_CBZ) and
  197. (taicpu(p).opcode<>A_CBNZ) and
  198. { There is a special requirement for MUL and MLA, oper[0] and oper[1] are not allowed to be the same }
  199. not (
  200. (taicpu(p).opcode in [A_MLA, A_MUL]) and
  201. (taicpu(p).oper[1]^.reg = taicpu(movp).oper[0]^.reg) and
  202. (current_settings.cputype < cpu_armv6)
  203. ) and
  204. {$endif ARM}
  205. { Take care to only do this for instructions which REALLY load to the first register.
  206. Otherwise
  207. str reg0, [reg1]
  208. mov reg2, reg0
  209. will be optimized to
  210. str reg2, [reg1]
  211. }
  212. RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
  213. begin
  214. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  215. if assigned(dealloc) then
  216. begin
  217. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  218. result:=true;
  219. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  220. and remove it if possible }
  221. asml.Remove(dealloc);
  222. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
  223. if assigned(alloc) then
  224. begin
  225. asml.Remove(alloc);
  226. alloc.free;
  227. dealloc.free;
  228. end
  229. else
  230. asml.InsertAfter(dealloc,p);
  231. { try to move the allocation of the target register }
  232. GetLastInstruction(movp,hp1);
  233. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  234. if assigned(alloc) then
  235. begin
  236. asml.Remove(alloc);
  237. asml.InsertBefore(alloc,p);
  238. { adjust used regs }
  239. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  240. end;
  241. { finally get rid of the mov }
  242. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  243. { Remove preindexing and postindexing for LDR in some cases.
  244. For example:
  245. ldr reg2,[reg1, xxx]!
  246. mov reg1,reg2
  247. must be translated to:
  248. ldr reg1,[reg1, xxx]
  249. Preindexing must be removed there, since the same register is used as the base and as the target.
  250. Such case is not allowed for ARM CPU and produces crash. }
  251. if (taicpu(p).opcode = A_LDR) and (taicpu(p).oper[1]^.typ = top_ref)
  252. and (taicpu(movp).oper[0]^.reg = taicpu(p).oper[1]^.ref^.base)
  253. then
  254. taicpu(p).oper[1]^.ref^.addressmode:=AM_OFFSET;
  255. asml.remove(movp);
  256. movp.free;
  257. end;
  258. end;
  259. end;
  260. function TARMAsmOptimizer.RedundantMovProcess(var p: tai; var hp1: tai):boolean;
  261. var
  262. I: Integer;
  263. current_hp, next_hp: tai;
  264. LDRChange: Boolean;
  265. begin
  266. Result:=false;
  267. {
  268. change
  269. mov r1, r0
  270. add r1, r1, #1
  271. to
  272. add r1, r0, #1
  273. Todo: Make it work for mov+cmp too
  274. CAUTION! If this one is successful p might not be a mov instruction anymore!
  275. }
  276. if (taicpu(p).ops = 2) and
  277. (taicpu(p).oper[1]^.typ = top_reg) and
  278. (taicpu(p).oppostfix = PF_NONE) then
  279. begin
  280. if
  281. MatchInstruction(hp1, [A_ADD, A_ADC,
  282. {$ifdef ARM}
  283. A_RSB, A_RSC,
  284. {$endif ARM}
  285. A_SUB, A_SBC,
  286. A_AND, A_BIC, A_EOR, A_ORR, A_MOV, A_MVN],
  287. [taicpu(p).condition], []) and
  288. { MOV and MVN might only have 2 ops }
  289. (taicpu(hp1).ops >= 2) and
  290. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^.reg) and
  291. (taicpu(hp1).oper[1]^.typ = top_reg) and
  292. (
  293. (taicpu(hp1).ops = 2) or
  294. (taicpu(hp1).oper[2]^.typ in [top_reg, top_const, top_shifterop])
  295. ) and
  296. {$ifdef AARCH64}
  297. (taicpu(p).oper[1]^.reg<>NR_SP) and
  298. {$endif AARCH64}
  299. not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  300. begin
  301. { When we get here we still don't know if the registers match }
  302. for I:=1 to 2 do
  303. {
  304. If the first loop was successful p will be replaced with hp1.
  305. The checks will still be ok, because all required information
  306. will also be in hp1 then.
  307. }
  308. if (taicpu(hp1).ops > I) and
  309. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[I]^.reg)
  310. {$ifdef ARM}
  311. { prevent certain combinations on thumb(2), this is only a safe approximation }
  312. and (not(GenerateThumbCode or GenerateThumb2Code) or
  313. ((getsupreg(taicpu(p).oper[1]^.reg)<>RS_R13) and
  314. (getsupreg(taicpu(p).oper[1]^.reg)<>RS_R15)))
  315. {$endif ARM}
  316. then
  317. begin
  318. DebugMsg('Peephole RedundantMovProcess done', hp1);
  319. taicpu(hp1).oper[I]^.reg := taicpu(p).oper[1]^.reg;
  320. if p<>hp1 then
  321. begin
  322. asml.remove(p);
  323. p.free;
  324. p:=hp1;
  325. Result:=true;
  326. end;
  327. end;
  328. if Result then Exit;
  329. end
  330. { Change: Change:
  331. mov r1, r0 mov r1, r0
  332. ... ...
  333. ldr/str r2, [r1, etc.] mov r2, r1
  334. To: To:
  335. ldr/str r2, [r0, etc.] mov r2, r0
  336. }
  337. else if (taicpu(p).condition = C_None) and (taicpu(p).oper[1]^.typ = top_reg)
  338. {$ifdef ARM}
  339. and not (getsupreg(taicpu(p).oper[0]^.reg) in [RS_PC, RS_R14, RS_STACK_POINTER_REG])
  340. and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_PC)
  341. { Thumb does not support references with base and index one being SP }
  342. and (not(GenerateThumbCode) or (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG))
  343. {$endif ARM}
  344. {$ifdef AARCH64}
  345. and (getsupreg(taicpu(p).oper[0]^.reg) <> RS_STACK_POINTER_REG)
  346. {$endif AARCH64}
  347. then
  348. begin
  349. current_hp := p;
  350. TransferUsedRegs(TmpUsedRegs);
  351. { Search local instruction block }
  352. while GetNextInstruction(current_hp, next_hp) and (next_hp <> BlockEnd) and (next_hp.typ = ait_instruction) do
  353. begin
  354. UpdateUsedRegs(TmpUsedRegs, tai(current_hp.Next));
  355. LDRChange := False;
  356. if (taicpu(next_hp).opcode in [A_LDR,A_STR]) and (taicpu(next_hp).ops = 2)
  357. {$ifdef AARCH64}
  358. { If r0 is the zero register, then this sequence of instructions will cause
  359. an access violation, but that's better than an assembler error caused by
  360. changing r0 to xzr inside the reference (Where it's illegal). [Kit] }
  361. and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_XZR)
  362. {$endif AARCH64}
  363. then
  364. begin
  365. { Change the registers from r1 to r0 }
  366. if (taicpu(next_hp).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) and
  367. {$ifdef ARM}
  368. { This optimisation conflicts with something and raises
  369. an access violation - needs further investigation. [Kit] }
  370. (taicpu(next_hp).opcode <> A_LDR) and
  371. {$endif ARM}
  372. { Don't mess around with the base register if the
  373. reference is pre- or post-indexed }
  374. (taicpu(next_hp).oper[1]^.ref^.addressmode = AM_OFFSET) then
  375. begin
  376. taicpu(next_hp).oper[1]^.ref^.base := taicpu(p).oper[1]^.reg;
  377. LDRChange := True;
  378. end;
  379. if taicpu(next_hp).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
  380. begin
  381. taicpu(next_hp).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
  382. LDRChange := True;
  383. end;
  384. if LDRChange then
  385. DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 1)', next_hp);
  386. { Drop out if we're dealing with pre-indexed references }
  387. if (taicpu(next_hp).oper[1]^.ref^.addressmode = AM_PREINDEXED) and
  388. (
  389. RegInRef(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[1]^.ref^) or
  390. RegInRef(taicpu(p).oper[1]^.reg, taicpu(next_hp).oper[1]^.ref^)
  391. ) then
  392. begin
  393. { Remember to update register allocations }
  394. if LDRChange then
  395. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  396. Break;
  397. end;
  398. { The register being stored can be potentially changed (as long as it's not the stack pointer) }
  399. if (taicpu(next_hp).opcode = A_STR) and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
  400. MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
  401. begin
  402. DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 2)', next_hp);
  403. taicpu(next_hp).oper[0]^.reg := taicpu(p).oper[1]^.reg;
  404. LDRChange := True;
  405. end;
  406. if LDRChange and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) then
  407. begin
  408. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  409. if (taicpu(p).oppostfix = PF_None) and
  410. (
  411. (
  412. (taicpu(next_hp).opcode = A_LDR) and
  413. MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg)
  414. ) or
  415. not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, next_hp, TmpUsedRegs)
  416. ) and
  417. { Double-check to see if the old registers were actually
  418. changed (e.g. if the super registers matched, but not
  419. the sizes, they won't be changed). }
  420. (
  421. (taicpu(next_hp).opcode = A_LDR) or
  422. not RegInOp(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[0]^)
  423. ) and
  424. not RegInRef(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[1]^.ref^) then
  425. begin
  426. DebugMsg('Peephole Optimization: RedundantMovProcess 2a done', p);
  427. RemoveCurrentP(p);
  428. Result := True;
  429. Exit;
  430. end;
  431. end;
  432. end
  433. else if (taicpu(next_hp).opcode = A_MOV) and (taicpu(next_hp).oppostfix = PF_None) and
  434. (taicpu(next_hp).ops = 2) then
  435. begin
  436. if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
  437. begin
  438. { Found another mov that writes entirely to the register }
  439. if RegUsedBetween(taicpu(p).oper[0]^.reg, p, next_hp) then
  440. begin
  441. { Register was used beforehand }
  442. if MatchOperand(taicpu(next_hp).oper[1]^, taicpu(p).oper[1]^.reg) then
  443. begin
  444. { This MOV is exactly the same as the first one.
  445. Since none of the registers have changed value
  446. at this point, we can remove it. }
  447. DebugMsg('Peephole Optimization: RedundantMovProcess 3a done', next_hp);
  448. if (next_hp = hp1) then
  449. { Don't let hp1 become a dangling pointer }
  450. hp1 := nil;
  451. asml.Remove(next_hp);
  452. next_hp.Free;
  453. { We still have the original p, so we can continue optimising;
  454. if it was -O2 or below, this instruction appeared immediately
  455. after the first MOV, so we're technically not looking more
  456. than one instruction ahead after it's removed! [Kit] }
  457. Continue;
  458. end
  459. else
  460. { Register changes value - drop out }
  461. Break;
  462. end;
  463. { We can delete the first MOV (only if the second MOV is unconditional) }
  464. {$ifdef ARM}
  465. if (taicpu(p).oppostfix = PF_None) and
  466. (taicpu(next_hp).condition = C_None) then
  467. {$endif ARM}
  468. begin
  469. DebugMsg('Peephole Optimization: RedundantMovProcess 2b done', p);
  470. RemoveCurrentP(p);
  471. Result := True;
  472. end;
  473. Exit;
  474. end
  475. else if MatchOperand(taicpu(next_hp).oper[1]^, taicpu(p).oper[0]^.reg) then
  476. begin
  477. if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[1]^.reg)
  478. { Be careful - if the entire register is not used, removing this
  479. instruction will leave the unused part uninitialised }
  480. {$ifdef AARCH64}
  481. and (getsubreg(taicpu(p).oper[1]^.reg) = R_SUBQ)
  482. {$endif AARCH64}
  483. then
  484. begin
  485. { Instruction will become mov r1,r1 }
  486. DebugMsg('Peephole Optimization: Mov2None 2 done', next_hp);
  487. { Allocate r1 between the instructions; not doing
  488. so may cause problems when removing superfluous
  489. MOVs later (i38055) }
  490. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  491. if (next_hp = hp1) then
  492. { Don't let hp1 become a dangling pointer }
  493. hp1 := nil;
  494. asml.Remove(next_hp);
  495. next_hp.Free;
  496. Continue;
  497. end;
  498. { Change the old register (checking the first operand again
  499. forces it to be left alone if the full register is not
  500. used, lest mov w1,w1 gets optimised out by mistake. [Kit] }
  501. {$ifdef AARCH64}
  502. if not MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[1]^.reg) then
  503. {$endif AARCH64}
  504. begin
  505. DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovMov2Mov 2)', next_hp);
  506. taicpu(next_hp).oper[1]^.reg := taicpu(p).oper[1]^.reg;
  507. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  508. { If this was the only reference to the old register,
  509. then we can remove the original MOV now }
  510. if (taicpu(p).oppostfix = PF_None) and
  511. { A bit of a hack - sometimes registers aren't tracked properly, so do not
  512. remove if the register was apparently not allocated when its value is
  513. first set at the MOV command (this is especially true for the stack
  514. register). [Kit] }
  515. (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
  516. RegInUsedRegs(taicpu(p).oper[0]^.reg, UsedRegs) and
  517. not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, next_hp, TmpUsedRegs) then
  518. begin
  519. DebugMsg('Peephole Optimization: RedundantMovProcess 2c done', p);
  520. RemoveCurrentP(p);
  521. Result := True;
  522. Exit;
  523. end;
  524. end;
  525. end;
  526. end;
  527. { On low optimisation settions, don't search more than one instruction ahead }
  528. if not(cs_opt_level3 in current_settings.optimizerswitches) or
  529. { Stop at procedure calls and jumps }
  530. is_calljmp(taicpu(next_hp).opcode) or
  531. { If the read register has changed value, or the MOV
  532. destination register has been used, drop out }
  533. RegInInstruction(taicpu(p).oper[0]^.reg, next_hp) or
  534. RegModifiedByInstruction(taicpu(p).oper[1]^.reg, next_hp) then
  535. Break;
  536. current_hp := next_hp;
  537. end;
  538. end;
  539. end;
  540. end;
  541. function TARMAsmOptimizer.OptPass1UXTB(var p : tai) : Boolean;
  542. var
  543. hp1, hp2: tai;
  544. begin
  545. Result:=false;
  546. {
  547. change
  548. uxtb reg2,reg1
  549. strb reg2,[...]
  550. dealloc reg2
  551. to
  552. strb reg1,[...]
  553. }
  554. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  555. (taicpu(p).ops=2) and
  556. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  557. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  558. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  559. { the reference in strb might not use reg2 }
  560. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  561. { reg1 might not be modified inbetween }
  562. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  563. begin
  564. DebugMsg('Peephole UxtbStrb2Strb done', p);
  565. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  566. GetNextInstruction(p,hp2);
  567. asml.remove(p);
  568. p.free;
  569. p:=hp2;
  570. result:=true;
  571. end
  572. {
  573. change
  574. uxtb reg2,reg1
  575. uxth reg3,reg2
  576. dealloc reg2
  577. to
  578. uxtb reg3,reg1
  579. }
  580. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  581. (taicpu(p).ops=2) and
  582. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  583. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  584. (taicpu(hp1).ops = 2) and
  585. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  586. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  587. { reg1 might not be modified inbetween }
  588. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  589. begin
  590. DebugMsg('Peephole UxtbUxth2Uxtb done', p);
  591. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  592. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  593. asml.remove(hp1);
  594. hp1.free;
  595. result:=true;
  596. end
  597. {
  598. change
  599. uxtb reg2,reg1
  600. uxtb reg3,reg2
  601. dealloc reg2
  602. to
  603. uxtb reg3,reg1
  604. }
  605. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  606. (taicpu(p).ops=2) and
  607. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  608. MatchInstruction(hp1, A_UXTB, [C_None], [PF_None]) and
  609. (taicpu(hp1).ops = 2) and
  610. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  611. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  612. { reg1 might not be modified inbetween }
  613. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  614. begin
  615. DebugMsg('Peephole UxtbUxtb2Uxtb done', p);
  616. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  617. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  618. asml.remove(hp1);
  619. hp1.free;
  620. result:=true;
  621. end
  622. {
  623. change
  624. uxtb reg2,reg1
  625. and reg3,reg2,#0x*FF
  626. dealloc reg2
  627. to
  628. uxtb reg3,reg1
  629. }
  630. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  631. (taicpu(p).ops=2) and
  632. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  633. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  634. (taicpu(hp1).ops=3) and
  635. (taicpu(hp1).oper[2]^.typ=top_const) and
  636. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  637. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  638. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  639. { reg1 might not be modified inbetween }
  640. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  641. begin
  642. DebugMsg('Peephole UxtbAndImm2Uxtb done', p);
  643. taicpu(hp1).opcode:=A_UXTB;
  644. taicpu(hp1).ops:=2;
  645. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  646. GetNextInstruction(p,hp2);
  647. asml.remove(p);
  648. p.free;
  649. p:=hp2;
  650. result:=true;
  651. end
  652. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  653. RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then
  654. Result:=true;
  655. end;
  656. function TARMAsmOptimizer.OptPass1UXTH(var p : tai) : Boolean;
  657. var
  658. hp1: tai;
  659. begin
  660. Result:=false;
  661. {
  662. change
  663. uxth reg2,reg1
  664. strh reg2,[...]
  665. dealloc reg2
  666. to
  667. strh reg1,[...]
  668. }
  669. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  670. (taicpu(p).ops=2) and
  671. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  672. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  673. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  674. { the reference in strb might not use reg2 }
  675. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  676. { reg1 might not be modified inbetween }
  677. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  678. begin
  679. DebugMsg('Peephole UXTHStrh2Strh done', p);
  680. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  681. GetNextInstruction(p, hp1);
  682. asml.remove(p);
  683. p.free;
  684. p:=hp1;
  685. result:=true;
  686. end
  687. {
  688. change
  689. uxth reg2,reg1
  690. uxth reg3,reg2
  691. dealloc reg2
  692. to
  693. uxth reg3,reg1
  694. }
  695. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  696. (taicpu(p).ops=2) and
  697. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  698. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  699. (taicpu(hp1).ops=2) and
  700. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  701. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  702. { reg1 might not be modified inbetween }
  703. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  704. begin
  705. DebugMsg('Peephole UxthUxth2Uxth done', p);
  706. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  707. taicpu(hp1).opcode:=A_UXTH;
  708. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  709. GetNextInstruction(p, hp1);
  710. asml.remove(p);
  711. p.free;
  712. p:=hp1;
  713. result:=true;
  714. end
  715. {
  716. change
  717. uxth reg2,reg1
  718. and reg3,reg2,#65535
  719. dealloc reg2
  720. to
  721. uxth reg3,reg1
  722. }
  723. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  724. (taicpu(p).ops=2) and
  725. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  726. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  727. (taicpu(hp1).ops=3) and
  728. (taicpu(hp1).oper[2]^.typ=top_const) and
  729. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  730. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  731. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  732. { reg1 might not be modified inbetween }
  733. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  734. begin
  735. DebugMsg('Peephole UxthAndImm2Uxth done', p);
  736. taicpu(hp1).opcode:=A_UXTH;
  737. taicpu(hp1).ops:=2;
  738. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  739. GetNextInstruction(p, hp1);
  740. asml.remove(p);
  741. p.free;
  742. p:=hp1;
  743. result:=true;
  744. end
  745. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  746. RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then
  747. Result:=true;
  748. end;
  749. function TARMAsmOptimizer.OptPass1SXTB(var p : tai) : Boolean;
  750. var
  751. hp1, hp2: tai;
  752. begin
  753. Result:=false;
  754. {
  755. change
  756. sxtb reg2,reg1
  757. strb reg2,[...]
  758. dealloc reg2
  759. to
  760. strb reg1,[...]
  761. }
  762. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  763. (taicpu(p).ops=2) and
  764. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  765. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  766. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  767. { the reference in strb might not use reg2 }
  768. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  769. { reg1 might not be modified inbetween }
  770. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  771. begin
  772. DebugMsg('Peephole SxtbStrb2Strb done', p);
  773. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  774. GetNextInstruction(p,hp2);
  775. asml.remove(p);
  776. p.free;
  777. p:=hp2;
  778. result:=true;
  779. end
  780. {
  781. change
  782. sxtb reg2,reg1
  783. sxth reg3,reg2
  784. dealloc reg2
  785. to
  786. sxtb reg3,reg1
  787. }
  788. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  789. (taicpu(p).ops=2) and
  790. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  791. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  792. (taicpu(hp1).ops = 2) and
  793. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  794. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  795. { reg1 might not be modified inbetween }
  796. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  797. begin
  798. DebugMsg('Peephole SxtbSxth2Sxtb done', p);
  799. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  800. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  801. asml.remove(hp1);
  802. hp1.free;
  803. result:=true;
  804. end
  805. {
  806. change
  807. sxtb reg2,reg1
  808. sxtb reg3,reg2
  809. dealloc reg2
  810. to
  811. uxtb reg3,reg1
  812. }
  813. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  814. (taicpu(p).ops=2) and
  815. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  816. MatchInstruction(hp1, A_SXTB, [C_None], [PF_None]) and
  817. (taicpu(hp1).ops = 2) and
  818. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  819. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  820. { reg1 might not be modified inbetween }
  821. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  822. begin
  823. DebugMsg('Peephole SxtbSxtb2Sxtb done', p);
  824. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  825. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  826. asml.remove(hp1);
  827. hp1.free;
  828. result:=true;
  829. end
  830. {
  831. change
  832. sxtb reg2,reg1
  833. and reg3,reg2,#0x*FF
  834. dealloc reg2
  835. to
  836. uxtb reg3,reg1
  837. }
  838. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  839. (taicpu(p).ops=2) and
  840. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  841. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  842. (taicpu(hp1).ops=3) and
  843. (taicpu(hp1).oper[2]^.typ=top_const) and
  844. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  845. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  846. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  847. { reg1 might not be modified inbetween }
  848. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  849. begin
  850. DebugMsg('Peephole SxtbAndImm2Uxtb done', p);
  851. taicpu(hp1).opcode:=A_UXTB;
  852. taicpu(hp1).ops:=2;
  853. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  854. GetNextInstruction(p,hp2);
  855. asml.remove(p);
  856. p.free;
  857. p:=hp2;
  858. result:=true;
  859. end
  860. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  861. RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then
  862. Result:=true;
  863. end;
  864. function TARMAsmOptimizer.OptPass1SXTH(var p : tai) : Boolean;
  865. var
  866. hp1: tai;
  867. begin
  868. Result:=false;
  869. {
  870. change
  871. sxth reg2,reg1
  872. strh reg2,[...]
  873. dealloc reg2
  874. to
  875. strh reg1,[...]
  876. }
  877. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  878. (taicpu(p).ops=2) and
  879. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  880. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  881. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  882. { the reference in strb might not use reg2 }
  883. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  884. { reg1 might not be modified inbetween }
  885. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  886. begin
  887. DebugMsg('Peephole SXTHStrh2Strh done', p);
  888. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  889. GetNextInstruction(p, hp1);
  890. asml.remove(p);
  891. p.free;
  892. p:=hp1;
  893. result:=true;
  894. end
  895. {
  896. change
  897. sxth reg2,reg1
  898. sxth reg3,reg2
  899. dealloc reg2
  900. to
  901. sxth reg3,reg1
  902. }
  903. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  904. (taicpu(p).ops=2) and
  905. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  906. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  907. (taicpu(hp1).ops=2) and
  908. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  909. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  910. { reg1 might not be modified inbetween }
  911. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  912. begin
  913. DebugMsg('Peephole SxthSxth2Sxth done', p);
  914. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  915. taicpu(hp1).opcode:=A_SXTH;
  916. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  917. GetNextInstruction(p, hp1);
  918. asml.remove(p);
  919. p.free;
  920. p:=hp1;
  921. result:=true;
  922. end
  923. {
  924. change
  925. sxth reg2,reg1
  926. and reg3,reg2,#65535
  927. dealloc reg2
  928. to
  929. uxth reg3,reg1
  930. }
  931. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  932. (taicpu(p).ops=2) and
  933. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  934. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  935. (taicpu(hp1).ops=3) and
  936. (taicpu(hp1).oper[2]^.typ=top_const) and
  937. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  938. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  939. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  940. { reg1 might not be modified inbetween }
  941. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  942. begin
  943. DebugMsg('Peephole SxthAndImm2Uxth done', p);
  944. taicpu(hp1).opcode:=A_UXTH;
  945. taicpu(hp1).ops:=2;
  946. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  947. GetNextInstruction(p, hp1);
  948. asml.remove(p);
  949. p.free;
  950. p:=hp1;
  951. result:=true;
  952. end
  953. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  954. RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then
  955. Result:=true;
  956. end;
  957. function TARMAsmOptimizer.OptPass1LDR(var p : tai) : Boolean;
  958. var
  959. hp1: tai;
  960. Reference: TReference;
  961. NewOp: TAsmOp;
  962. begin
  963. Result := False;
  964. if (taicpu(p).ops <> 2) or (taicpu(p).condition <> C_None) then
  965. Exit;
  966. Reference := taicpu(p).oper[1]^.ref^;
  967. if (Reference.addressmode = AM_OFFSET) and
  968. not RegInRef(taicpu(p).oper[0]^.reg, Reference) and
  969. { Delay calling GetNextInstruction for as long as possible }
  970. GetNextInstruction(p, hp1) and
  971. (hp1.typ = ait_instruction) and
  972. (taicpu(hp1).condition = C_None) and
  973. (taicpu(hp1).oppostfix = taicpu(p).oppostfix) then
  974. begin
  975. if (taicpu(hp1).opcode = A_STR) and
  976. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) and
  977. (getregtype(taicpu(p).oper[0]^.reg) = getregtype(taicpu(hp1).oper[0]^.reg)) then
  978. begin
  979. { With:
  980. ldr reg1,[ref]
  981. str reg2,[ref]
  982. If reg1 = reg2, Remove str
  983. }
  984. if taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg then
  985. begin
  986. DebugMsg(SPeepholeOptimization + 'Removed redundant store instruction (load/store -> load/nop)', hp1);
  987. RemoveInstruction(hp1);
  988. Result := True;
  989. Exit;
  990. end;
  991. end
  992. else if (taicpu(hp1).opcode = A_LDR) and
  993. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) then
  994. begin
  995. { With:
  996. ldr reg1,[ref]
  997. ldr reg2,[ref]
  998. If reg1 = reg2, delete the second ldr
  999. If reg1 <> reg2, changing the 2nd ldr to a mov might introduce
  1000. a dependency, but it will likely open up new optimisations, so
  1001. do it for now and handle any new dependencies later.
  1002. }
  1003. if taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg then
  1004. begin
  1005. DebugMsg(SPeepholeOptimization + 'Removed duplicate load instruction (load/load -> load/nop)', hp1);
  1006. RemoveInstruction(hp1);
  1007. Result := True;
  1008. Exit;
  1009. end
  1010. else if
  1011. (getregtype(taicpu(p).oper[0]^.reg) = R_INTREGISTER) and
  1012. (getregtype(taicpu(hp1).oper[0]^.reg) = R_INTREGISTER) and
  1013. (getsubreg(taicpu(p).oper[0]^.reg) = getsubreg(taicpu(hp1).oper[0]^.reg)) then
  1014. begin
  1015. DebugMsg(SPeepholeOptimization + 'Changed second ldr' + oppostfix2str[taicpu(hp1).oppostfix] + ' to mov (load/load -> load/move)', hp1);
  1016. taicpu(hp1).opcode := A_MOV;
  1017. taicpu(hp1).oppostfix := PF_None;
  1018. taicpu(hp1).loadreg(1, taicpu(p).oper[0]^.reg);
  1019. AllocRegBetween(taicpu(p).oper[0]^.reg, p, hp1, UsedRegs);
  1020. Result := True;
  1021. Exit;
  1022. end;
  1023. end;
  1024. end;
  1025. end;
  1026. function TARMAsmOptimizer.OptPass1STR(var p : tai) : Boolean;
  1027. var
  1028. hp1: tai;
  1029. Reference: TReference;
  1030. SizeMismatch: Boolean;
  1031. SrcReg, DstReg: TRegister;
  1032. NewOp: TAsmOp;
  1033. begin
  1034. Result := False;
  1035. if (taicpu(p).ops <> 2) or (taicpu(p).condition <> C_None) then
  1036. Exit;
  1037. Reference := taicpu(p).oper[1]^.ref^;
  1038. if (Reference.addressmode = AM_OFFSET) and
  1039. not RegInRef(taicpu(p).oper[0]^.reg, Reference) and
  1040. { Delay calling GetNextInstruction for as long as possible }
  1041. GetNextInstruction(p, hp1) and
  1042. (hp1.typ = ait_instruction) and
  1043. (taicpu(hp1).condition = C_None) and
  1044. (taicpu(hp1).oppostfix = taicpu(p).oppostfix) then
  1045. begin
  1046. { Saves constant dereferencing and makes it easier to change the size if necessary }
  1047. SrcReg := taicpu(p).oper[0]^.reg;
  1048. DstReg := taicpu(hp1).oper[0]^.reg;
  1049. if (taicpu(hp1).opcode = A_LDR) and
  1050. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) and
  1051. (taicpu(hp1).oper[1]^.ref^.volatility=[]) and
  1052. (
  1053. (taicpu(hp1).oppostfix = taicpu(p).oppostfix) or
  1054. ((taicpu(p).oppostfix = PF_B) and (taicpu(hp1).oppostfix = PF_SB)) or
  1055. ((taicpu(p).oppostfix = PF_H) and (taicpu(hp1).oppostfix = PF_SH))
  1056. {$ifdef AARCH64}
  1057. or ((taicpu(p).oppostfix = PF_W) and (taicpu(hp1).oppostfix = PF_SW))
  1058. {$endif AARCH64}
  1059. ) then
  1060. begin
  1061. { With:
  1062. str reg1,[ref]
  1063. ldr reg2,[ref]
  1064. If reg1 = reg2, Remove ldr.
  1065. If reg1 <> reg2, replace ldr with "mov reg2,reg1"
  1066. }
  1067. if (SrcReg = DstReg) and
  1068. { e.g. the ldrb in strb/ldrb is not a null operation as it clears the upper 24 bits }
  1069. (taicpu(p).oppostfix=PF_None) then
  1070. begin
  1071. DebugMsg(SPeepholeOptimization + 'Removed redundant load instruction (store/load -> store/nop)', hp1);
  1072. RemoveInstruction(hp1);
  1073. Result := True;
  1074. Exit;
  1075. end
  1076. else if (getregtype(SrcReg) = R_INTREGISTER) and
  1077. (getregtype(DstReg) = R_INTREGISTER) and
  1078. (getsubreg(SrcReg) = getsubreg(DstReg)) then
  1079. begin
  1080. NewOp:=A_NONE;
  1081. if taicpu(hp1).oppostfix=PF_None then
  1082. NewOp:=A_MOV
  1083. else
  1084. {$ifdef ARM}
  1085. if (current_settings.cputype < cpu_armv6) then
  1086. begin
  1087. { The zero- and sign-extension operations were only
  1088. introduced under ARMv6 }
  1089. case taicpu(hp1).oppostfix of
  1090. PF_B:
  1091. begin
  1092. { The if-block afterwards will set the middle operand to the correct register }
  1093. taicpu(hp1).allocate_oper(3);
  1094. taicpu(hp1).ops := 3;
  1095. taicpu(hp1).loadconst(2, $FF);
  1096. NewOp := A_AND;
  1097. end;
  1098. PF_H:
  1099. { ARMv5 and under doesn't have a concise way of storing the immediate $FFFF, so leave alone };
  1100. PF_SB,
  1101. PF_SH:
  1102. { Do nothing - can't easily encode sign-extensions };
  1103. else
  1104. InternalError(2021043002);
  1105. end;
  1106. end
  1107. else
  1108. {$endif ARM}
  1109. case taicpu(hp1).oppostfix of
  1110. PF_B:
  1111. NewOp := A_UXTB;
  1112. PF_SB:
  1113. NewOp := A_SXTB;
  1114. PF_H:
  1115. NewOp := A_UXTH;
  1116. PF_SH:
  1117. NewOp := A_SXTH;
  1118. {$ifdef AARCH64}
  1119. PF_SW:
  1120. NewOp := A_SXTW;
  1121. PF_W:
  1122. NewOp := A_MOV;
  1123. {$endif AARCH64}
  1124. else
  1125. InternalError(2021043001);
  1126. end;
  1127. if (NewOp<>A_None) then
  1128. begin
  1129. DebugMsg(SPeepholeOptimization + 'Changed ldr' + oppostfix2str[taicpu(hp1).oppostfix] + ' to ' + gas_op2str[NewOp] + ' (store/load -> store/move)', hp1);
  1130. taicpu(hp1).oppostfix := PF_None;
  1131. taicpu(hp1).opcode := NewOp;
  1132. taicpu(hp1).loadreg(1, SrcReg);
  1133. AllocRegBetween(SrcReg, p, hp1, UsedRegs);
  1134. Result := True;
  1135. Exit;
  1136. end;
  1137. end
  1138. end
  1139. else if (taicpu(hp1).opcode = A_STR) and
  1140. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) then
  1141. begin
  1142. { With:
  1143. str reg1,[ref]
  1144. str reg2,[ref]
  1145. If reg1 <> reg2, delete the first str
  1146. IF reg1 = reg2, delete the second str
  1147. }
  1148. if (SrcReg = DstReg) and (taicpu(hp1).oper[1]^.ref^.volatility=[]) then
  1149. begin
  1150. DebugMsg(SPeepholeOptimization + 'Removed duplicate store instruction (store/store -> store/nop)', hp1);
  1151. RemoveInstruction(hp1);
  1152. Result := True;
  1153. Exit;
  1154. end
  1155. else if
  1156. { Registers same byte size? }
  1157. (tcgsize2size[reg_cgsize(SrcReg)] = tcgsize2size[reg_cgsize(DstReg)]) and
  1158. (taicpu(p).oper[1]^.ref^.volatility=[]) then
  1159. begin
  1160. DebugMsg(SPeepholeOptimization + 'Removed dominated store instruction (store/store -> nop/store)', p);
  1161. RemoveCurrentP(p, hp1);
  1162. Result := True;
  1163. Exit;
  1164. end;
  1165. end;
  1166. end;
  1167. end;
  1168. function TARMAsmOptimizer.OptPass1And(var p : tai) : Boolean;
  1169. var
  1170. hp1, hp2: tai;
  1171. i: longint;
  1172. begin
  1173. Result:=false;
  1174. {
  1175. optimize
  1176. and reg2,reg1,const1
  1177. ...
  1178. }
  1179. if (taicpu(p).ops>2) and
  1180. (taicpu(p).oper[1]^.typ = top_reg) and
  1181. (taicpu(p).oper[2]^.typ = top_const) then
  1182. begin
  1183. {
  1184. change
  1185. and reg2,reg1,const1
  1186. ...
  1187. and reg3,reg2,const2
  1188. to
  1189. and reg3,reg1,(const1 and const2)
  1190. }
  1191. if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1192. MatchInstruction(hp1, A_AND, [taicpu(p).condition], [PF_None]) and
  1193. RegEndOfLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  1194. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1195. (taicpu(hp1).oper[2]^.typ = top_const)
  1196. {$ifdef AARCH64}
  1197. and ((((getsubreg(taicpu(p).oper[0]^.reg)=R_SUBQ) and is_shifter_const(taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val,OS_64)) or
  1198. ((getsubreg(taicpu(p).oper[0]^.reg)=R_SUBL) and is_shifter_const(taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val,OS_32))
  1199. ) or
  1200. ((taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0))
  1201. {$endif AARCH64}
  1202. then
  1203. begin
  1204. if not(RegUsedBetween(taicpu(hp1).oper[0]^.reg,p,hp1)) then
  1205. begin
  1206. DebugMsg('Peephole AndAnd2And done', p);
  1207. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  1208. if (taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0 then
  1209. begin
  1210. DebugMsg('Peephole AndAnd2Mov0 1 done', p);
  1211. taicpu(p).opcode:=A_MOV;
  1212. taicpu(p).ops:=2;
  1213. taicpu(p).loadConst(1,0);
  1214. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  1215. end
  1216. else
  1217. begin
  1218. DebugMsg('Peephole AndAnd2And 1 done', p);
  1219. taicpu(p).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  1220. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  1221. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  1222. end;
  1223. asml.remove(hp1);
  1224. hp1.free;
  1225. Result:=true;
  1226. exit;
  1227. end
  1228. else if not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1229. begin
  1230. if (taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0 then
  1231. begin
  1232. DebugMsg('Peephole AndAnd2Mov0 2 done', hp1);
  1233. taicpu(hp1).opcode:=A_MOV;
  1234. taicpu(hp1).loadConst(1,0);
  1235. taicpu(hp1).ops:=2;
  1236. taicpu(hp1).oppostfix:=taicpu(p).oppostfix;
  1237. end
  1238. else
  1239. begin
  1240. DebugMsg('Peephole AndAnd2And 2 done', hp1);
  1241. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  1242. taicpu(hp1).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  1243. taicpu(hp1).oppostfix:=taicpu(p).oppostfix;
  1244. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  1245. end;
  1246. GetNextInstruction(p, hp1);
  1247. RemoveCurrentP(p);
  1248. p:=hp1;
  1249. Result:=true;
  1250. exit;
  1251. end;
  1252. end
  1253. {
  1254. change
  1255. and reg2,reg1,$xxxxxxFF
  1256. strb reg2,[...]
  1257. dealloc reg2
  1258. to
  1259. strb reg1,[...]
  1260. }
  1261. else if ((taicpu(p).oper[2]^.val and $FF) = $FF) and
  1262. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  1263. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1264. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  1265. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  1266. { the reference in strb might not use reg2 }
  1267. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  1268. { reg1 might not be modified inbetween }
  1269. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1270. begin
  1271. DebugMsg('Peephole AndStrb2Strb done', p);
  1272. {$ifdef AARCH64}
  1273. taicpu(hp1).loadReg(0,newreg(R_INTREGISTER,getsupreg(taicpu(p).oper[1]^.reg),R_SUBD));
  1274. {$else AARCH64}
  1275. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  1276. {$endif AARCH64}
  1277. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  1278. RemoveCurrentP(p);
  1279. result:=true;
  1280. exit;
  1281. end
  1282. {
  1283. change
  1284. and reg2,reg1,255
  1285. uxtb/uxth reg3,reg2
  1286. dealloc reg2
  1287. to
  1288. and reg3,reg1,x
  1289. }
  1290. else if MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  1291. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1292. ((((taicpu(p).oper[2]^.val and $ffffff00)=0) and MatchInstruction(hp1, A_UXTB, [C_None], [PF_None])) or
  1293. (((taicpu(p).oper[2]^.val and $ffff0000)=0) and MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]))) and
  1294. (taicpu(hp1).ops = 2) and
  1295. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  1296. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1297. { reg1 might not be modified inbetween }
  1298. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1299. begin
  1300. DebugMsg('Peephole AndUxt2And done', p);
  1301. taicpu(hp1).opcode:=A_AND;
  1302. taicpu(hp1).ops:=3;
  1303. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  1304. taicpu(hp1).loadconst(2,taicpu(p).oper[2]^.val);
  1305. GetNextInstruction(p,hp1);
  1306. asml.remove(p);
  1307. p.Free;
  1308. p:=hp1;
  1309. result:=true;
  1310. exit;
  1311. end
  1312. else if ((taicpu(p).oper[2]^.val and $ffffff80)=0) and
  1313. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  1314. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1315. MatchInstruction(hp1, [A_SXTB,A_SXTH], [C_None], [PF_None]) and
  1316. (taicpu(hp1).ops = 2) and
  1317. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  1318. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1319. { reg1 might not be modified inbetween }
  1320. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1321. begin
  1322. DebugMsg('Peephole AndSxt2And done', p);
  1323. taicpu(hp1).opcode:=A_AND;
  1324. taicpu(hp1).ops:=3;
  1325. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  1326. taicpu(hp1).loadconst(2,taicpu(p).oper[2]^.val);
  1327. GetNextInstruction(p,hp1);
  1328. asml.remove(p);
  1329. p.Free;
  1330. p:=hp1;
  1331. result:=true;
  1332. exit;
  1333. end
  1334. {
  1335. from
  1336. and reg1,reg0,2^n-1
  1337. mov reg2,reg1, lsl imm1
  1338. (mov reg3,reg2, lsr/asr imm1)
  1339. remove either the and or the lsl/xsr sequence if possible
  1340. }
  1341. else if (taicpu(p).oper[2]^.val < high(int64)) and
  1342. cutils.ispowerof2(taicpu(p).oper[2]^.val+1,i) and
  1343. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1344. MatchInstruction(hp1, A_MOV, [taicpu(p).condition], [PF_None]) and
  1345. (taicpu(hp1).ops=3) and
  1346. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1347. (taicpu(hp1).oper[2]^.typ = top_shifterop) and
  1348. {$ifdef ARM}
  1349. (taicpu(hp1).oper[2]^.shifterop^.rs = NR_NO) and
  1350. {$endif ARM}
  1351. (taicpu(hp1).oper[2]^.shifterop^.shiftmode=SM_LSL) and
  1352. RegEndOfLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) then
  1353. begin
  1354. {
  1355. and reg1,reg0,2^n-1
  1356. mov reg2,reg1, lsl imm1
  1357. mov reg3,reg2, lsr/asr imm1
  1358. =>
  1359. and reg1,reg0,2^n-1
  1360. if lsr and 2^n-1>=imm1 or asr and 2^n-1>imm1
  1361. }
  1362. if GetNextInstructionUsingReg(hp1,hp2,taicpu(p).oper[0]^.reg) and
  1363. MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
  1364. (taicpu(hp2).ops=3) and
  1365. MatchOperand(taicpu(hp2).oper[1]^, taicpu(hp1).oper[0]^.reg) and
  1366. (taicpu(hp2).oper[2]^.typ = top_shifterop) and
  1367. {$ifdef ARM}
  1368. (taicpu(hp2).oper[2]^.shifterop^.rs = NR_NO) and
  1369. {$endif ARM}
  1370. (taicpu(hp2).oper[2]^.shifterop^.shiftmode in [SM_ASR,SM_LSR]) and
  1371. (taicpu(hp1).oper[2]^.shifterop^.shiftimm=taicpu(hp2).oper[2]^.shifterop^.shiftimm) and
  1372. RegEndOfLife(taicpu(hp1).oper[0]^.reg,taicpu(hp2)) and
  1373. ((i<32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) or
  1374. ((i=32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
  1375. (taicpu(hp2).oper[2]^.shifterop^.shiftmode=SM_LSR))) then
  1376. begin
  1377. DebugMsg('Peephole AndLslXsr2And done', p);
  1378. taicpu(p).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  1379. asml.Remove(hp1);
  1380. asml.Remove(hp2);
  1381. hp1.free;
  1382. hp2.free;
  1383. result:=true;
  1384. exit;
  1385. end
  1386. {
  1387. and reg1,reg0,2^n-1
  1388. mov reg2,reg1, lsl imm1
  1389. =>
  1390. mov reg2,reg0, lsl imm1
  1391. if imm1>i
  1392. }
  1393. else if (i>32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
  1394. not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) then
  1395. begin
  1396. DebugMsg('Peephole AndLsl2Lsl done', p);
  1397. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  1398. GetNextInstruction(p, hp1);
  1399. asml.Remove(p);
  1400. p.free;
  1401. p:=hp1;
  1402. result:=true;
  1403. exit;
  1404. end
  1405. end;
  1406. end;
  1407. {
  1408. change
  1409. and reg1, ...
  1410. mov reg2, reg1
  1411. to
  1412. and reg2, ...
  1413. }
  1414. if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  1415. (taicpu(p).ops>=3) and
  1416. RemoveSuperfluousMove(p, hp1, 'DataMov2Data') then
  1417. Result:=true;
  1418. end;
  1419. end.