aoptarm.pas 37 KB

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