aoptarm.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  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. { $define DEBUG_AOPTCPU}
  22. Interface
  23. uses
  24. cgbase, cgutils, cpubase, aasmtai, aasmcpu,aopt, aoptobj;
  25. Type
  26. { while ARM and AAarch64 look not very similar at a first glance,
  27. several optimizations can be shared between both }
  28. TARMAsmOptimizer = class(TAsmOptimizer)
  29. procedure DebugMsg(const s : string; p : tai);
  30. function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
  31. function RedundantMovProcess(var p: tai; hp1: tai): boolean;
  32. function GetNextInstructionUsingReg(Current: tai; out Next: tai; reg: TRegister): Boolean;
  33. function OptPass1UXTB(var p: tai): Boolean;
  34. function OptPass1UXTH(var p: tai): Boolean;
  35. function OptPass1SXTB(var p: tai): Boolean;
  36. function OptPass1SXTH(var p: tai): Boolean;
  37. function OptPass1And(var p: tai): Boolean; virtual;
  38. End;
  39. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  40. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  41. {$ifdef AARCH64}
  42. function MatchInstruction(const instr: tai; const ops : array of TAsmOp; const postfix: TOpPostfixes): boolean;
  43. {$endif AARCH64}
  44. function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
  45. function RefsEqual(const r1, r2: treference): boolean;
  46. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  47. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  48. Implementation
  49. uses
  50. cutils,verbose,globtype,globals,
  51. systems,
  52. cpuinfo,
  53. cgobj,procinfo,
  54. aasmbase,aasmdata;
  55. {$ifdef DEBUG_AOPTCPU}
  56. procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);
  57. begin
  58. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  59. end;
  60. {$else DEBUG_AOPTCPU}
  61. procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  62. begin
  63. end;
  64. {$endif DEBUG_AOPTCPU}
  65. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  66. begin
  67. result :=
  68. (instr.typ = ait_instruction) and
  69. ((op = []) or ((taicpu(instr).opcode<=LastCommonAsmOp) and (taicpu(instr).opcode in op))) and
  70. ((cond = []) or (taicpu(instr).condition in cond)) and
  71. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  72. end;
  73. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  74. begin
  75. result :=
  76. (instr.typ = ait_instruction) and
  77. (taicpu(instr).opcode = op) and
  78. ((cond = []) or (taicpu(instr).condition in cond)) and
  79. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  80. end;
  81. {$ifdef AARCH64}
  82. function MatchInstruction(const instr: tai; const ops : array of TAsmOp; const postfix: TOpPostfixes): boolean;
  83. var
  84. op : TAsmOp;
  85. begin
  86. result:=false;
  87. if instr.typ <> ait_instruction then
  88. exit;
  89. for op in ops do
  90. begin
  91. if (taicpu(instr).opcode = op) and
  92. ((postfix = []) or (taicpu(instr).oppostfix in postfix)) then
  93. begin
  94. result:=true;
  95. exit;
  96. end;
  97. end;
  98. end;
  99. {$endif AARCH64}
  100. function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
  101. begin
  102. result :=
  103. (instr.typ = ait_instruction) and
  104. (taicpu(instr).opcode = op) and
  105. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  106. end;
  107. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  108. begin
  109. result := (oper.typ = top_reg) and (oper.reg = reg);
  110. end;
  111. function RefsEqual(const r1, r2: treference): boolean;
  112. begin
  113. refsequal :=
  114. (r1.offset = r2.offset) and
  115. (r1.base = r2.base) and
  116. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  117. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  118. (r1.relsymbol = r2.relsymbol) and
  119. {$ifdef ARM}
  120. (r1.signindex = r2.signindex) and
  121. {$endif ARM}
  122. (r1.shiftimm = r2.shiftimm) and
  123. (r1.addressmode = r2.addressmode) and
  124. (r1.shiftmode = r2.shiftmode) and
  125. (r1.volatility=[]) and
  126. (r2.volatility=[]);
  127. end;
  128. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  129. begin
  130. result := oper1.typ = oper2.typ;
  131. if result then
  132. case oper1.typ of
  133. top_const:
  134. Result:=oper1.val = oper2.val;
  135. top_reg:
  136. Result:=oper1.reg = oper2.reg;
  137. top_conditioncode:
  138. Result:=oper1.cc = oper2.cc;
  139. top_realconst:
  140. Result:=oper1.val_real = oper2.val_real;
  141. top_ref:
  142. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  143. else Result:=false;
  144. end
  145. end;
  146. function TARMAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  147. Out Next: tai; reg: TRegister): Boolean;
  148. var
  149. gniResult: Boolean;
  150. begin
  151. Next:=Current;
  152. Result := False;
  153. repeat
  154. gniResult:=GetNextInstruction(Next,Next);
  155. if gniResult and RegInInstruction(reg,Next) then
  156. { Found something }
  157. Exit(True);
  158. until not gniResult or
  159. not(cs_opt_level3 in current_settings.optimizerswitches) or
  160. (Next.typ<>ait_instruction) or
  161. is_calljmp(taicpu(Next).opcode)
  162. {$ifdef ARM}
  163. or RegModifiedByInstruction(NR_PC,Next)
  164. {$endif ARM}
  165. ;
  166. end;
  167. function TARMAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
  168. var
  169. alloc,
  170. dealloc : tai_regalloc;
  171. hp1 : tai;
  172. begin
  173. Result:=false;
  174. if MatchInstruction(movp, A_MOV, [taicpu(p).condition], [PF_None]) and
  175. { We can't optimize if there is a shiftop }
  176. (taicpu(movp).ops=2) and
  177. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  178. { don't mess with moves to fp }
  179. (taicpu(movp).oper[0]^.reg<>current_procinfo.framepointer) and
  180. { the destination register of the mov might not be used beween p and movp }
  181. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  182. {$ifdef ARM}
  183. { PC should be changed only by moves }
  184. (taicpu(movp).oper[0]^.reg<>NR_PC) and
  185. { cb[n]z are thumb instructions which require specific registers, with no wide forms }
  186. (taicpu(p).opcode<>A_CBZ) and
  187. (taicpu(p).opcode<>A_CBNZ) and
  188. { There is a special requirement for MUL and MLA, oper[0] and oper[1] are not allowed to be the same }
  189. not (
  190. (taicpu(p).opcode in [A_MLA, A_MUL]) and
  191. (taicpu(p).oper[1]^.reg = taicpu(movp).oper[0]^.reg) and
  192. (current_settings.cputype < cpu_armv6)
  193. ) and
  194. {$endif ARM}
  195. { Take care to only do this for instructions which REALLY load to the first register.
  196. Otherwise
  197. str reg0, [reg1]
  198. mov reg2, reg0
  199. will be optimized to
  200. str reg2, [reg1]
  201. }
  202. RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
  203. begin
  204. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  205. if assigned(dealloc) then
  206. begin
  207. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  208. result:=true;
  209. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  210. and remove it if possible }
  211. asml.Remove(dealloc);
  212. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
  213. if assigned(alloc) then
  214. begin
  215. asml.Remove(alloc);
  216. alloc.free;
  217. dealloc.free;
  218. end
  219. else
  220. asml.InsertAfter(dealloc,p);
  221. { try to move the allocation of the target register }
  222. GetLastInstruction(movp,hp1);
  223. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  224. if assigned(alloc) then
  225. begin
  226. asml.Remove(alloc);
  227. asml.InsertBefore(alloc,p);
  228. { adjust used regs }
  229. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  230. end;
  231. { finally get rid of the mov }
  232. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  233. { Remove preindexing and postindexing for LDR in some cases.
  234. For example:
  235. ldr reg2,[reg1, xxx]!
  236. mov reg1,reg2
  237. must be translated to:
  238. ldr reg1,[reg1, xxx]
  239. Preindexing must be removed there, since the same register is used as the base and as the target.
  240. Such case is not allowed for ARM CPU and produces crash. }
  241. if (taicpu(p).opcode = A_LDR) and (taicpu(p).oper[1]^.typ = top_ref)
  242. and (taicpu(movp).oper[0]^.reg = taicpu(p).oper[1]^.ref^.base)
  243. then
  244. taicpu(p).oper[1]^.ref^.addressmode:=AM_OFFSET;
  245. asml.remove(movp);
  246. movp.free;
  247. end;
  248. end;
  249. end;
  250. function TARMAsmOptimizer.RedundantMovProcess(var p: tai;hp1: tai):boolean;
  251. var
  252. I: Integer;
  253. begin
  254. Result:=false;
  255. {
  256. change
  257. mov r1, r0
  258. add r1, r1, #1
  259. to
  260. add r1, r0, #1
  261. Todo: Make it work for mov+cmp too
  262. CAUTION! If this one is successful p might not be a mov instruction anymore!
  263. }
  264. if (taicpu(p).ops = 2) and
  265. (taicpu(p).oper[1]^.typ = top_reg) and
  266. (taicpu(p).oppostfix = PF_NONE) and
  267. MatchInstruction(hp1, [A_ADD, A_ADC,
  268. {$ifdef ARM}
  269. A_RSB, A_RSC,
  270. {$endif ARM}
  271. A_SUB, A_SBC,
  272. A_AND, A_BIC, A_EOR, A_ORR, A_MOV, A_MVN],
  273. [taicpu(p).condition], []) and
  274. { MOV and MVN might only have 2 ops }
  275. (taicpu(hp1).ops >= 2) and
  276. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^.reg) and
  277. (taicpu(hp1).oper[1]^.typ = top_reg) and
  278. (
  279. (taicpu(hp1).ops = 2) or
  280. (taicpu(hp1).oper[2]^.typ in [top_reg, top_const, top_shifterop])
  281. ) and
  282. {$ifdef AARCH64}
  283. (taicpu(p).oper[1]^.reg<>NR_SP) and
  284. {$endif AARCH64}
  285. not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  286. begin
  287. { When we get here we still don't know if the registers match }
  288. for I:=1 to 2 do
  289. {
  290. If the first loop was successful p will be replaced with hp1.
  291. The checks will still be ok, because all required information
  292. will also be in hp1 then.
  293. }
  294. if (taicpu(hp1).ops > I) and
  295. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[I]^.reg)
  296. {$ifdef ARM}
  297. { prevent certain combinations on thumb(2), this is only a safe approximation }
  298. and (not(GenerateThumbCode or GenerateThumb2Code) or
  299. ((getsupreg(taicpu(p).oper[1]^.reg)<>RS_R13) and
  300. (getsupreg(taicpu(p).oper[1]^.reg)<>RS_R15)))
  301. {$endif ARM}
  302. then
  303. begin
  304. DebugMsg('Peephole RedundantMovProcess done', hp1);
  305. taicpu(hp1).oper[I]^.reg := taicpu(p).oper[1]^.reg;
  306. if p<>hp1 then
  307. begin
  308. asml.remove(p);
  309. p.free;
  310. p:=hp1;
  311. Result:=true;
  312. end;
  313. end;
  314. end;
  315. end;
  316. function TARMAsmOptimizer.OptPass1UXTB(var p : tai) : Boolean;
  317. var
  318. hp1, hp2: tai;
  319. begin
  320. Result:=false;
  321. {
  322. change
  323. uxtb reg2,reg1
  324. strb reg2,[...]
  325. dealloc reg2
  326. to
  327. strb reg1,[...]
  328. }
  329. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  330. (taicpu(p).ops=2) and
  331. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  332. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  333. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  334. { the reference in strb might not use reg2 }
  335. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  336. { reg1 might not be modified inbetween }
  337. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  338. begin
  339. DebugMsg('Peephole UxtbStrb2Strb done', p);
  340. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  341. GetNextInstruction(p,hp2);
  342. asml.remove(p);
  343. p.free;
  344. p:=hp2;
  345. result:=true;
  346. end
  347. {
  348. change
  349. uxtb reg2,reg1
  350. uxth reg3,reg2
  351. dealloc reg2
  352. to
  353. uxtb reg3,reg1
  354. }
  355. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  356. (taicpu(p).ops=2) and
  357. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  358. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  359. (taicpu(hp1).ops = 2) and
  360. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  361. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  362. { reg1 might not be modified inbetween }
  363. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  364. begin
  365. DebugMsg('Peephole UxtbUxth2Uxtb done', p);
  366. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  367. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  368. asml.remove(hp1);
  369. hp1.free;
  370. result:=true;
  371. end
  372. {
  373. change
  374. uxtb reg2,reg1
  375. uxtb reg3,reg2
  376. dealloc reg2
  377. to
  378. uxtb reg3,reg1
  379. }
  380. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  381. (taicpu(p).ops=2) and
  382. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  383. MatchInstruction(hp1, A_UXTB, [C_None], [PF_None]) and
  384. (taicpu(hp1).ops = 2) and
  385. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  386. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  387. { reg1 might not be modified inbetween }
  388. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  389. begin
  390. DebugMsg('Peephole UxtbUxtb2Uxtb done', p);
  391. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  392. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  393. asml.remove(hp1);
  394. hp1.free;
  395. result:=true;
  396. end
  397. {
  398. change
  399. uxtb reg2,reg1
  400. and reg3,reg2,#0x*FF
  401. dealloc reg2
  402. to
  403. uxtb reg3,reg1
  404. }
  405. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  406. (taicpu(p).ops=2) and
  407. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  408. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  409. (taicpu(hp1).ops=3) and
  410. (taicpu(hp1).oper[2]^.typ=top_const) and
  411. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  412. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  413. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  414. { reg1 might not be modified inbetween }
  415. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  416. begin
  417. DebugMsg('Peephole UxtbAndImm2Uxtb done', p);
  418. taicpu(hp1).opcode:=A_UXTB;
  419. taicpu(hp1).ops:=2;
  420. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  421. GetNextInstruction(p,hp2);
  422. asml.remove(p);
  423. p.free;
  424. p:=hp2;
  425. result:=true;
  426. end
  427. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  428. RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then
  429. Result:=true;
  430. end;
  431. function TARMAsmOptimizer.OptPass1UXTH(var p : tai) : Boolean;
  432. var
  433. hp1: tai;
  434. begin
  435. Result:=false;
  436. {
  437. change
  438. uxth reg2,reg1
  439. strh reg2,[...]
  440. dealloc reg2
  441. to
  442. strh reg1,[...]
  443. }
  444. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  445. (taicpu(p).ops=2) and
  446. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  447. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  448. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  449. { the reference in strb might not use reg2 }
  450. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  451. { reg1 might not be modified inbetween }
  452. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  453. begin
  454. DebugMsg('Peephole UXTHStrh2Strh done', p);
  455. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  456. GetNextInstruction(p, hp1);
  457. asml.remove(p);
  458. p.free;
  459. p:=hp1;
  460. result:=true;
  461. end
  462. {
  463. change
  464. uxth reg2,reg1
  465. uxth reg3,reg2
  466. dealloc reg2
  467. to
  468. uxth reg3,reg1
  469. }
  470. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  471. (taicpu(p).ops=2) and
  472. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  473. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  474. (taicpu(hp1).ops=2) and
  475. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  476. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  477. { reg1 might not be modified inbetween }
  478. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  479. begin
  480. DebugMsg('Peephole UxthUxth2Uxth done', p);
  481. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  482. taicpu(hp1).opcode:=A_UXTH;
  483. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  484. GetNextInstruction(p, hp1);
  485. asml.remove(p);
  486. p.free;
  487. p:=hp1;
  488. result:=true;
  489. end
  490. {
  491. change
  492. uxth reg2,reg1
  493. and reg3,reg2,#65535
  494. dealloc reg2
  495. to
  496. uxth reg3,reg1
  497. }
  498. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  499. (taicpu(p).ops=2) and
  500. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  501. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  502. (taicpu(hp1).ops=3) and
  503. (taicpu(hp1).oper[2]^.typ=top_const) and
  504. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  505. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  506. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  507. { reg1 might not be modified inbetween }
  508. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  509. begin
  510. DebugMsg('Peephole UxthAndImm2Uxth done', p);
  511. taicpu(hp1).opcode:=A_UXTH;
  512. taicpu(hp1).ops:=2;
  513. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  514. GetNextInstruction(p, hp1);
  515. asml.remove(p);
  516. p.free;
  517. p:=hp1;
  518. result:=true;
  519. end
  520. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  521. RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then
  522. Result:=true;
  523. end;
  524. function TARMAsmOptimizer.OptPass1SXTB(var p : tai) : Boolean;
  525. var
  526. hp1, hp2: tai;
  527. begin
  528. Result:=false;
  529. {
  530. change
  531. sxtb reg2,reg1
  532. strb reg2,[...]
  533. dealloc reg2
  534. to
  535. strb reg1,[...]
  536. }
  537. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  538. (taicpu(p).ops=2) and
  539. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  540. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  541. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  542. { the reference in strb might not use reg2 }
  543. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  544. { reg1 might not be modified inbetween }
  545. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  546. begin
  547. DebugMsg('Peephole SxtbStrb2Strb done', p);
  548. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  549. GetNextInstruction(p,hp2);
  550. asml.remove(p);
  551. p.free;
  552. p:=hp2;
  553. result:=true;
  554. end
  555. {
  556. change
  557. sxtb reg2,reg1
  558. sxth reg3,reg2
  559. dealloc reg2
  560. to
  561. sxtb reg3,reg1
  562. }
  563. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  564. (taicpu(p).ops=2) and
  565. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  566. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  567. (taicpu(hp1).ops = 2) and
  568. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  569. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  570. { reg1 might not be modified inbetween }
  571. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  572. begin
  573. DebugMsg('Peephole SxtbSxth2Sxtb done', p);
  574. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  575. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  576. asml.remove(hp1);
  577. hp1.free;
  578. result:=true;
  579. end
  580. {
  581. change
  582. sxtb reg2,reg1
  583. sxtb reg3,reg2
  584. dealloc reg2
  585. to
  586. uxtb reg3,reg1
  587. }
  588. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  589. (taicpu(p).ops=2) and
  590. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  591. MatchInstruction(hp1, A_SXTB, [C_None], [PF_None]) and
  592. (taicpu(hp1).ops = 2) and
  593. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  594. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  595. { reg1 might not be modified inbetween }
  596. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  597. begin
  598. DebugMsg('Peephole SxtbSxtb2Sxtb done', p);
  599. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  600. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  601. asml.remove(hp1);
  602. hp1.free;
  603. result:=true;
  604. end
  605. {
  606. change
  607. sxtb reg2,reg1
  608. and reg3,reg2,#0x*FF
  609. dealloc reg2
  610. to
  611. uxtb reg3,reg1
  612. }
  613. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  614. (taicpu(p).ops=2) and
  615. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  616. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  617. (taicpu(hp1).ops=3) and
  618. (taicpu(hp1).oper[2]^.typ=top_const) and
  619. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  620. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  621. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  622. { reg1 might not be modified inbetween }
  623. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  624. begin
  625. DebugMsg('Peephole SxtbAndImm2Sxtb done', p);
  626. taicpu(hp1).opcode:=A_SXTB;
  627. taicpu(hp1).ops:=2;
  628. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  629. GetNextInstruction(p,hp2);
  630. asml.remove(p);
  631. p.free;
  632. p:=hp2;
  633. result:=true;
  634. end
  635. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  636. RemoveSuperfluousMove(p, hp1, 'SxtbMov2Data') then
  637. Result:=true;
  638. end;
  639. function TARMAsmOptimizer.OptPass1SXTH(var p : tai) : Boolean;
  640. var
  641. hp1: tai;
  642. begin
  643. Result:=false;
  644. {
  645. change
  646. sxth reg2,reg1
  647. strh reg2,[...]
  648. dealloc reg2
  649. to
  650. strh reg1,[...]
  651. }
  652. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  653. (taicpu(p).ops=2) and
  654. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  655. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  656. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  657. { the reference in strb might not use reg2 }
  658. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  659. { reg1 might not be modified inbetween }
  660. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  661. begin
  662. DebugMsg('Peephole SXTHStrh2Strh done', p);
  663. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  664. GetNextInstruction(p, hp1);
  665. asml.remove(p);
  666. p.free;
  667. p:=hp1;
  668. result:=true;
  669. end
  670. {
  671. change
  672. sxth reg2,reg1
  673. sxth reg3,reg2
  674. dealloc reg2
  675. to
  676. sxth reg3,reg1
  677. }
  678. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  679. (taicpu(p).ops=2) and
  680. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  681. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  682. (taicpu(hp1).ops=2) and
  683. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  684. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  685. { reg1 might not be modified inbetween }
  686. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  687. begin
  688. DebugMsg('Peephole SxthSxth2Sxth done', p);
  689. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  690. taicpu(hp1).opcode:=A_SXTH;
  691. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  692. GetNextInstruction(p, hp1);
  693. asml.remove(p);
  694. p.free;
  695. p:=hp1;
  696. result:=true;
  697. end
  698. {
  699. change
  700. sxth reg2,reg1
  701. and reg3,reg2,#65535
  702. dealloc reg2
  703. to
  704. sxth reg3,reg1
  705. }
  706. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  707. (taicpu(p).ops=2) and
  708. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  709. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  710. (taicpu(hp1).ops=3) and
  711. (taicpu(hp1).oper[2]^.typ=top_const) and
  712. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  713. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  714. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  715. { reg1 might not be modified inbetween }
  716. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  717. begin
  718. DebugMsg('Peephole SxthAndImm2Sxth done', p);
  719. taicpu(hp1).opcode:=A_SXTH;
  720. taicpu(hp1).ops:=2;
  721. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  722. GetNextInstruction(p, hp1);
  723. asml.remove(p);
  724. p.free;
  725. p:=hp1;
  726. result:=true;
  727. end
  728. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  729. RemoveSuperfluousMove(p, hp1, 'SxthMov2Data') then
  730. Result:=true;
  731. end;
  732. function TARMAsmOptimizer.OptPass1And(var p : tai) : Boolean;
  733. var
  734. hp1, hp2: tai;
  735. i: longint;
  736. begin
  737. Result:=false;
  738. {
  739. optimize
  740. and reg2,reg1,const1
  741. ...
  742. }
  743. if (taicpu(p).ops>2) and
  744. (taicpu(p).oper[1]^.typ = top_reg) and
  745. (taicpu(p).oper[2]^.typ = top_const) then
  746. begin
  747. {
  748. change
  749. and reg2,reg1,const1
  750. ...
  751. and reg3,reg2,const2
  752. to
  753. and reg3,reg1,(const1 and const2)
  754. }
  755. if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  756. MatchInstruction(hp1, A_AND, [taicpu(p).condition], [PF_None]) and
  757. RegEndOfLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  758. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  759. (taicpu(hp1).oper[2]^.typ = top_const)
  760. {$ifdef AARCH64}
  761. 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
  762. ((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))
  763. ) or
  764. ((taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0))
  765. {$endif AARCH64}
  766. then
  767. begin
  768. if not(RegUsedBetween(taicpu(hp1).oper[0]^.reg,p,hp1)) then
  769. begin
  770. DebugMsg('Peephole AndAnd2And done', p);
  771. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  772. if (taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0 then
  773. begin
  774. DebugMsg('Peephole AndAnd2Mov0 1 done', p);
  775. taicpu(p).opcode:=A_MOV;
  776. taicpu(p).ops:=2;
  777. taicpu(p).loadConst(1,0);
  778. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  779. end
  780. else
  781. begin
  782. DebugMsg('Peephole AndAnd2And 1 done', p);
  783. taicpu(p).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  784. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  785. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  786. end;
  787. asml.remove(hp1);
  788. hp1.free;
  789. Result:=true;
  790. exit;
  791. end
  792. else if not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  793. begin
  794. if (taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0 then
  795. begin
  796. DebugMsg('Peephole AndAnd2Mov0 2 done', hp1);
  797. taicpu(hp1).opcode:=A_MOV;
  798. taicpu(hp1).loadConst(1,0);
  799. taicpu(hp1).ops:=2;
  800. taicpu(hp1).oppostfix:=taicpu(p).oppostfix;
  801. end
  802. else
  803. begin
  804. DebugMsg('Peephole AndAnd2And 2 done', hp1);
  805. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  806. taicpu(hp1).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  807. taicpu(hp1).oppostfix:=taicpu(p).oppostfix;
  808. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  809. end;
  810. GetNextInstruction(p, hp1);
  811. RemoveCurrentP(p);
  812. p:=hp1;
  813. Result:=true;
  814. exit;
  815. end;
  816. end
  817. {
  818. change
  819. and reg2,reg1,$xxxxxxFF
  820. strb reg2,[...]
  821. dealloc reg2
  822. to
  823. strb reg1,[...]
  824. }
  825. else if ((taicpu(p).oper[2]^.val and $FF) = $FF) and
  826. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  827. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  828. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  829. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  830. { the reference in strb might not use reg2 }
  831. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  832. { reg1 might not be modified inbetween }
  833. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  834. begin
  835. DebugMsg('Peephole AndStrb2Strb done', p);
  836. {$ifdef AARCH64}
  837. taicpu(hp1).loadReg(0,newreg(R_INTREGISTER,getsupreg(taicpu(p).oper[1]^.reg),R_SUBD));
  838. {$else AARCH64}
  839. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  840. {$endif AARCH64}
  841. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  842. RemoveCurrentP(p);
  843. result:=true;
  844. exit;
  845. end
  846. {
  847. change
  848. and reg2,reg1,255
  849. uxtb/uxth reg3,reg2
  850. dealloc reg2
  851. to
  852. and reg3,reg1,x
  853. }
  854. else if ((taicpu(p).oper[2]^.val and $ffffff00)=0) and
  855. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  856. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  857. MatchInstruction(hp1, [A_UXTB,A_UXTH], [C_None], [PF_None]) and
  858. (taicpu(hp1).ops = 2) and
  859. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  860. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  861. { reg1 might not be modified inbetween }
  862. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  863. begin
  864. DebugMsg('Peephole AndUxt2And done', p);
  865. taicpu(hp1).opcode:=A_AND;
  866. taicpu(hp1).ops:=3;
  867. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  868. taicpu(hp1).loadconst(2,taicpu(p).oper[2]^.val);
  869. GetNextInstruction(p,hp1);
  870. asml.remove(p);
  871. p.Free;
  872. p:=hp1;
  873. result:=true;
  874. exit;
  875. end
  876. else if ((taicpu(p).oper[2]^.val and $ffffff80)=0) and
  877. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  878. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  879. MatchInstruction(hp1, [A_SXTB,A_SXTH], [C_None], [PF_None]) and
  880. (taicpu(hp1).ops = 2) and
  881. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  882. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  883. { reg1 might not be modified inbetween }
  884. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  885. begin
  886. DebugMsg('Peephole AndSxt2And done', p);
  887. taicpu(hp1).opcode:=A_AND;
  888. taicpu(hp1).ops:=3;
  889. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  890. taicpu(hp1).loadconst(2,taicpu(p).oper[2]^.val);
  891. GetNextInstruction(p,hp1);
  892. asml.remove(p);
  893. p.Free;
  894. p:=hp1;
  895. result:=true;
  896. exit;
  897. end
  898. {
  899. from
  900. and reg1,reg0,2^n-1
  901. mov reg2,reg1, lsl imm1
  902. (mov reg3,reg2, lsr/asr imm1)
  903. remove either the and or the lsl/xsr sequence if possible
  904. }
  905. else if (taicpu(p).oper[2]^.val < high(int64)) and
  906. cutils.ispowerof2(taicpu(p).oper[2]^.val+1,i) and
  907. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  908. MatchInstruction(hp1, A_MOV, [taicpu(p).condition], [PF_None]) and
  909. (taicpu(hp1).ops=3) and
  910. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  911. (taicpu(hp1).oper[2]^.typ = top_shifterop) and
  912. {$ifdef ARM}
  913. (taicpu(hp1).oper[2]^.shifterop^.rs = NR_NO) and
  914. {$endif ARM}
  915. (taicpu(hp1).oper[2]^.shifterop^.shiftmode=SM_LSL) and
  916. RegEndOfLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) then
  917. begin
  918. {
  919. and reg1,reg0,2^n-1
  920. mov reg2,reg1, lsl imm1
  921. mov reg3,reg2, lsr/asr imm1
  922. =>
  923. and reg1,reg0,2^n-1
  924. if lsr and 2^n-1>=imm1 or asr and 2^n-1>imm1
  925. }
  926. if GetNextInstructionUsingReg(hp1,hp2,taicpu(p).oper[0]^.reg) and
  927. MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
  928. (taicpu(hp2).ops=3) and
  929. MatchOperand(taicpu(hp2).oper[1]^, taicpu(hp1).oper[0]^.reg) and
  930. (taicpu(hp2).oper[2]^.typ = top_shifterop) and
  931. {$ifdef ARM}
  932. (taicpu(hp2).oper[2]^.shifterop^.rs = NR_NO) and
  933. {$endif ARM}
  934. (taicpu(hp2).oper[2]^.shifterop^.shiftmode in [SM_ASR,SM_LSR]) and
  935. (taicpu(hp1).oper[2]^.shifterop^.shiftimm=taicpu(hp2).oper[2]^.shifterop^.shiftimm) and
  936. RegEndOfLife(taicpu(hp1).oper[0]^.reg,taicpu(hp2)) and
  937. ((i<32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) or
  938. ((i=32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
  939. (taicpu(hp2).oper[2]^.shifterop^.shiftmode=SM_LSR))) then
  940. begin
  941. DebugMsg('Peephole AndLslXsr2And done', p);
  942. taicpu(p).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  943. asml.Remove(hp1);
  944. asml.Remove(hp2);
  945. hp1.free;
  946. hp2.free;
  947. result:=true;
  948. exit;
  949. end
  950. {
  951. and reg1,reg0,2^n-1
  952. mov reg2,reg1, lsl imm1
  953. =>
  954. mov reg2,reg0, lsl imm1
  955. if imm1>i
  956. }
  957. else if (i>32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
  958. not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) then
  959. begin
  960. DebugMsg('Peephole AndLsl2Lsl done', p);
  961. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  962. GetNextInstruction(p, hp1);
  963. asml.Remove(p);
  964. p.free;
  965. p:=hp1;
  966. result:=true;
  967. exit;
  968. end
  969. end;
  970. end;
  971. {
  972. change
  973. and reg1, ...
  974. mov reg2, reg1
  975. to
  976. and reg2, ...
  977. }
  978. if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  979. (taicpu(p).ops>=3) and
  980. RemoveSuperfluousMove(p, hp1, 'DataMov2Data') then
  981. Result:=true;
  982. end;
  983. end.