aoptarm.pas 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552
  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. { in this case you have to transform it to movk or the like }
  299. (getsupreg(taicpu(p).oper[1]^.reg)<>RS_XZR) and
  300. {$endif AARCH64}
  301. not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  302. begin
  303. { When we get here we still don't know if the registers match }
  304. for I:=1 to 2 do
  305. {
  306. If the first loop was successful p will be replaced with hp1.
  307. The checks will still be ok, because all required information
  308. will also be in hp1 then.
  309. }
  310. if (taicpu(hp1).ops > I) and
  311. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[I]^.reg)
  312. {$ifdef ARM}
  313. { prevent certain combinations on thumb(2), this is only a safe approximation }
  314. and (not(GenerateThumbCode or GenerateThumb2Code) or
  315. ((getsupreg(taicpu(p).oper[1]^.reg)<>RS_R13) and
  316. (getsupreg(taicpu(p).oper[1]^.reg)<>RS_R15)))
  317. {$endif ARM}
  318. then
  319. begin
  320. DebugMsg('Peephole RedundantMovProcess done', hp1);
  321. taicpu(hp1).oper[I]^.reg := taicpu(p).oper[1]^.reg;
  322. if p<>hp1 then
  323. begin
  324. asml.remove(p);
  325. p.free;
  326. p:=hp1;
  327. Result:=true;
  328. end;
  329. end;
  330. if Result then Exit;
  331. end
  332. { Change: Change:
  333. mov r1, r0 mov r1, r0
  334. ... ...
  335. ldr/str r2, [r1, etc.] mov r2, r1
  336. To: To:
  337. ldr/str r2, [r0, etc.] mov r2, r0
  338. }
  339. else if (taicpu(p).condition = C_None) and (taicpu(p).oper[1]^.typ = top_reg)
  340. {$ifdef ARM}
  341. and not (getsupreg(taicpu(p).oper[0]^.reg) in [RS_PC, RS_R14, RS_STACK_POINTER_REG])
  342. and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_PC)
  343. { Thumb does not support references with base and index one being SP }
  344. and (not(GenerateThumbCode) or (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG))
  345. {$endif ARM}
  346. {$ifdef AARCH64}
  347. and (getsupreg(taicpu(p).oper[0]^.reg) <> RS_STACK_POINTER_REG)
  348. {$endif AARCH64}
  349. then
  350. begin
  351. current_hp := p;
  352. TransferUsedRegs(TmpUsedRegs);
  353. { Search local instruction block }
  354. while GetNextInstruction(current_hp, next_hp) and (next_hp <> BlockEnd) and (next_hp.typ = ait_instruction) do
  355. begin
  356. UpdateUsedRegs(TmpUsedRegs, tai(current_hp.Next));
  357. LDRChange := False;
  358. if (taicpu(next_hp).opcode in [A_LDR,A_STR]) and (taicpu(next_hp).ops = 2)
  359. {$ifdef AARCH64}
  360. { If r0 is the zero register, then this sequence of instructions will cause
  361. an access violation, but that's better than an assembler error caused by
  362. changing r0 to xzr inside the reference (Where it's illegal). [Kit] }
  363. and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_XZR)
  364. {$endif AARCH64}
  365. then
  366. begin
  367. { Change the registers from r1 to r0 }
  368. if (taicpu(next_hp).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) and
  369. {$ifdef ARM}
  370. { This optimisation conflicts with something and raises
  371. an access violation - needs further investigation. [Kit] }
  372. (taicpu(next_hp).opcode <> A_LDR) and
  373. {$endif ARM}
  374. { Don't mess around with the base register if the
  375. reference is pre- or post-indexed }
  376. (taicpu(next_hp).oper[1]^.ref^.addressmode = AM_OFFSET) then
  377. begin
  378. taicpu(next_hp).oper[1]^.ref^.base := taicpu(p).oper[1]^.reg;
  379. LDRChange := True;
  380. end;
  381. if taicpu(next_hp).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
  382. begin
  383. taicpu(next_hp).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
  384. LDRChange := True;
  385. end;
  386. if LDRChange then
  387. DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 1)', next_hp);
  388. { Drop out if we're dealing with pre-indexed references }
  389. if (taicpu(next_hp).oper[1]^.ref^.addressmode = AM_PREINDEXED) and
  390. (
  391. RegInRef(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[1]^.ref^) or
  392. RegInRef(taicpu(p).oper[1]^.reg, taicpu(next_hp).oper[1]^.ref^)
  393. ) then
  394. begin
  395. { Remember to update register allocations }
  396. if LDRChange then
  397. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  398. Break;
  399. end;
  400. { The register being stored can be potentially changed (as long as it's not the stack pointer) }
  401. if (taicpu(next_hp).opcode = A_STR) and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
  402. MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
  403. begin
  404. DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 2)', next_hp);
  405. taicpu(next_hp).oper[0]^.reg := taicpu(p).oper[1]^.reg;
  406. LDRChange := True;
  407. end;
  408. if LDRChange and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) then
  409. begin
  410. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  411. if (taicpu(p).oppostfix = PF_None) and
  412. (
  413. (
  414. (taicpu(next_hp).opcode = A_LDR) and
  415. MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg)
  416. ) or
  417. not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, next_hp, TmpUsedRegs)
  418. ) and
  419. { Double-check to see if the old registers were actually
  420. changed (e.g. if the super registers matched, but not
  421. the sizes, they won't be changed). }
  422. (
  423. (taicpu(next_hp).opcode = A_LDR) or
  424. not RegInOp(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[0]^)
  425. ) and
  426. not RegInRef(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[1]^.ref^) then
  427. begin
  428. DebugMsg('Peephole Optimization: RedundantMovProcess 2a done', p);
  429. RemoveCurrentP(p);
  430. Result := True;
  431. Exit;
  432. end;
  433. end;
  434. end
  435. else if (taicpu(next_hp).opcode = A_MOV) and (taicpu(next_hp).oppostfix = PF_None) and
  436. (taicpu(next_hp).ops = 2) then
  437. begin
  438. if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
  439. begin
  440. { Found another mov that writes entirely to the register }
  441. if RegUsedBetween(taicpu(p).oper[0]^.reg, p, next_hp) then
  442. begin
  443. { Register was used beforehand }
  444. if MatchOperand(taicpu(next_hp).oper[1]^, taicpu(p).oper[1]^.reg) then
  445. begin
  446. { This MOV is exactly the same as the first one.
  447. Since none of the registers have changed value
  448. at this point, we can remove it. }
  449. DebugMsg('Peephole Optimization: RedundantMovProcess 3a done', next_hp);
  450. if (next_hp = hp1) then
  451. { Don't let hp1 become a dangling pointer }
  452. hp1 := nil;
  453. asml.Remove(next_hp);
  454. next_hp.Free;
  455. { We still have the original p, so we can continue optimising;
  456. if it was -O2 or below, this instruction appeared immediately
  457. after the first MOV, so we're technically not looking more
  458. than one instruction ahead after it's removed! [Kit] }
  459. Continue;
  460. end
  461. else
  462. { Register changes value - drop out }
  463. Break;
  464. end;
  465. { We can delete the first MOV (only if the second MOV is unconditional) }
  466. {$ifdef ARM}
  467. if (taicpu(p).oppostfix = PF_None) and
  468. (taicpu(next_hp).condition = C_None) then
  469. {$endif ARM}
  470. begin
  471. DebugMsg('Peephole Optimization: RedundantMovProcess 2b done', p);
  472. RemoveCurrentP(p);
  473. Result := True;
  474. end;
  475. Exit;
  476. end
  477. else if MatchOperand(taicpu(next_hp).oper[1]^, taicpu(p).oper[0]^.reg) then
  478. begin
  479. if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[1]^.reg)
  480. { Be careful - if the entire register is not used, removing this
  481. instruction will leave the unused part uninitialised }
  482. {$ifdef AARCH64}
  483. and (getsubreg(taicpu(p).oper[1]^.reg) = R_SUBQ)
  484. {$endif AARCH64}
  485. then
  486. begin
  487. { Instruction will become mov r1,r1 }
  488. DebugMsg('Peephole Optimization: Mov2None 2 done', next_hp);
  489. { Allocate r1 between the instructions; not doing
  490. so may cause problems when removing superfluous
  491. MOVs later (i38055) }
  492. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  493. if (next_hp = hp1) then
  494. { Don't let hp1 become a dangling pointer }
  495. hp1 := nil;
  496. asml.Remove(next_hp);
  497. next_hp.Free;
  498. Continue;
  499. end;
  500. { Change the old register (checking the first operand again
  501. forces it to be left alone if the full register is not
  502. used, lest mov w1,w1 gets optimised out by mistake. [Kit] }
  503. {$ifdef AARCH64}
  504. if not MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[1]^.reg) then
  505. {$endif AARCH64}
  506. begin
  507. DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovMov2Mov 2)', next_hp);
  508. taicpu(next_hp).oper[1]^.reg := taicpu(p).oper[1]^.reg;
  509. AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
  510. { If this was the only reference to the old register,
  511. then we can remove the original MOV now }
  512. if (taicpu(p).oppostfix = PF_None) and
  513. { A bit of a hack - sometimes registers aren't tracked properly, so do not
  514. remove if the register was apparently not allocated when its value is
  515. first set at the MOV command (this is especially true for the stack
  516. register). [Kit] }
  517. (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
  518. RegInUsedRegs(taicpu(p).oper[0]^.reg, UsedRegs) and
  519. not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, next_hp, TmpUsedRegs) then
  520. begin
  521. DebugMsg('Peephole Optimization: RedundantMovProcess 2c done', p);
  522. RemoveCurrentP(p);
  523. Result := True;
  524. Exit;
  525. end;
  526. end;
  527. end;
  528. end;
  529. { On low optimisation settions, don't search more than one instruction ahead }
  530. if not(cs_opt_level3 in current_settings.optimizerswitches) or
  531. { Stop at procedure calls and jumps }
  532. is_calljmp(taicpu(next_hp).opcode) or
  533. { If the read register has changed value, or the MOV
  534. destination register has been used, drop out }
  535. RegInInstruction(taicpu(p).oper[0]^.reg, next_hp) or
  536. RegModifiedByInstruction(taicpu(p).oper[1]^.reg, next_hp) then
  537. Break;
  538. current_hp := next_hp;
  539. end;
  540. end;
  541. end;
  542. end;
  543. function TARMAsmOptimizer.OptPass1UXTB(var p : tai) : Boolean;
  544. var
  545. hp1, hp2: tai;
  546. begin
  547. Result:=false;
  548. {
  549. change
  550. uxtb reg2,reg1
  551. strb reg2,[...]
  552. dealloc reg2
  553. to
  554. strb reg1,[...]
  555. }
  556. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  557. (taicpu(p).ops=2) and
  558. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  559. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  560. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  561. { the reference in strb might not use reg2 }
  562. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  563. { reg1 might not be modified inbetween }
  564. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  565. begin
  566. DebugMsg('Peephole UxtbStrb2Strb done', p);
  567. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  568. GetNextInstruction(p,hp2);
  569. asml.remove(p);
  570. p.free;
  571. p:=hp2;
  572. result:=true;
  573. end
  574. {
  575. change
  576. uxtb reg2,reg1
  577. uxth reg3,reg2
  578. dealloc reg2
  579. to
  580. uxtb reg3,reg1
  581. }
  582. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  583. (taicpu(p).ops=2) and
  584. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  585. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  586. (taicpu(hp1).ops = 2) and
  587. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  588. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  589. { reg1 might not be modified inbetween }
  590. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  591. begin
  592. DebugMsg('Peephole UxtbUxth2Uxtb done', p);
  593. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  594. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  595. asml.remove(hp1);
  596. hp1.free;
  597. result:=true;
  598. end
  599. {
  600. change
  601. uxtb reg2,reg1
  602. uxtb reg3,reg2
  603. dealloc reg2
  604. to
  605. uxtb reg3,reg1
  606. }
  607. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  608. (taicpu(p).ops=2) and
  609. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  610. MatchInstruction(hp1, A_UXTB, [C_None], [PF_None]) and
  611. (taicpu(hp1).ops = 2) and
  612. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  613. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  614. { reg1 might not be modified inbetween }
  615. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  616. begin
  617. DebugMsg('Peephole UxtbUxtb2Uxtb done', p);
  618. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  619. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  620. asml.remove(hp1);
  621. hp1.free;
  622. result:=true;
  623. end
  624. {
  625. change
  626. uxtb reg2,reg1
  627. and reg3,reg2,#0x*FF
  628. dealloc reg2
  629. to
  630. uxtb reg3,reg1
  631. }
  632. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  633. (taicpu(p).ops=2) and
  634. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  635. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  636. (taicpu(hp1).ops=3) and
  637. (taicpu(hp1).oper[2]^.typ=top_const) and
  638. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  639. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  640. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  641. { reg1 might not be modified inbetween }
  642. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  643. begin
  644. DebugMsg('Peephole UxtbAndImm2Uxtb done', p);
  645. taicpu(hp1).opcode:=A_UXTB;
  646. taicpu(hp1).ops:=2;
  647. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  648. GetNextInstruction(p,hp2);
  649. asml.remove(p);
  650. p.free;
  651. p:=hp2;
  652. result:=true;
  653. end
  654. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  655. RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then
  656. Result:=true;
  657. end;
  658. function TARMAsmOptimizer.OptPass1UXTH(var p : tai) : Boolean;
  659. var
  660. hp1: tai;
  661. begin
  662. Result:=false;
  663. {
  664. change
  665. uxth reg2,reg1
  666. strh reg2,[...]
  667. dealloc reg2
  668. to
  669. strh reg1,[...]
  670. }
  671. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  672. (taicpu(p).ops=2) and
  673. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  674. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  675. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  676. { the reference in strb might not use reg2 }
  677. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  678. { reg1 might not be modified inbetween }
  679. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  680. begin
  681. DebugMsg('Peephole UXTHStrh2Strh done', p);
  682. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  683. GetNextInstruction(p, hp1);
  684. asml.remove(p);
  685. p.free;
  686. p:=hp1;
  687. result:=true;
  688. end
  689. {
  690. change
  691. uxth reg2,reg1
  692. uxth reg3,reg2
  693. dealloc reg2
  694. to
  695. uxth reg3,reg1
  696. }
  697. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  698. (taicpu(p).ops=2) and
  699. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  700. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  701. (taicpu(hp1).ops=2) and
  702. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  703. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  704. { reg1 might not be modified inbetween }
  705. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  706. begin
  707. DebugMsg('Peephole UxthUxth2Uxth done', p);
  708. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  709. taicpu(hp1).opcode:=A_UXTH;
  710. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  711. GetNextInstruction(p, hp1);
  712. asml.remove(p);
  713. p.free;
  714. p:=hp1;
  715. result:=true;
  716. end
  717. {
  718. change
  719. uxth reg2,reg1
  720. and reg3,reg2,#65535
  721. dealloc reg2
  722. to
  723. uxth reg3,reg1
  724. }
  725. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  726. (taicpu(p).ops=2) and
  727. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  728. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  729. (taicpu(hp1).ops=3) and
  730. (taicpu(hp1).oper[2]^.typ=top_const) and
  731. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  732. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  733. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  734. { reg1 might not be modified inbetween }
  735. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  736. begin
  737. DebugMsg('Peephole UxthAndImm2Uxth done', p);
  738. taicpu(hp1).opcode:=A_UXTH;
  739. taicpu(hp1).ops:=2;
  740. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  741. GetNextInstruction(p, hp1);
  742. asml.remove(p);
  743. p.free;
  744. p:=hp1;
  745. result:=true;
  746. end
  747. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  748. RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then
  749. Result:=true;
  750. end;
  751. function TARMAsmOptimizer.OptPass1SXTB(var p : tai) : Boolean;
  752. var
  753. hp1, hp2: tai;
  754. begin
  755. Result:=false;
  756. {
  757. change
  758. sxtb reg2,reg1
  759. strb reg2,[...]
  760. dealloc reg2
  761. to
  762. strb reg1,[...]
  763. }
  764. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  765. (taicpu(p).ops=2) and
  766. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  767. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  768. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  769. { the reference in strb might not use reg2 }
  770. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  771. { reg1 might not be modified inbetween }
  772. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  773. begin
  774. DebugMsg('Peephole SxtbStrb2Strb done', p);
  775. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  776. GetNextInstruction(p,hp2);
  777. asml.remove(p);
  778. p.free;
  779. p:=hp2;
  780. result:=true;
  781. end
  782. {
  783. change
  784. sxtb reg2,reg1
  785. sxth reg3,reg2
  786. dealloc reg2
  787. to
  788. sxtb reg3,reg1
  789. }
  790. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  791. (taicpu(p).ops=2) and
  792. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  793. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  794. (taicpu(hp1).ops = 2) and
  795. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  796. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  797. { reg1 might not be modified inbetween }
  798. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  799. begin
  800. DebugMsg('Peephole SxtbSxth2Sxtb done', p);
  801. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  802. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  803. asml.remove(hp1);
  804. hp1.free;
  805. result:=true;
  806. end
  807. {
  808. change
  809. sxtb reg2,reg1
  810. sxtb reg3,reg2
  811. dealloc reg2
  812. to
  813. uxtb reg3,reg1
  814. }
  815. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  816. (taicpu(p).ops=2) and
  817. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  818. MatchInstruction(hp1, A_SXTB, [C_None], [PF_None]) and
  819. (taicpu(hp1).ops = 2) and
  820. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  821. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  822. { reg1 might not be modified inbetween }
  823. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  824. begin
  825. DebugMsg('Peephole SxtbSxtb2Sxtb done', p);
  826. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  827. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  828. asml.remove(hp1);
  829. hp1.free;
  830. result:=true;
  831. end
  832. {
  833. change
  834. sxtb reg2,reg1
  835. and reg3,reg2,#0x*FF
  836. dealloc reg2
  837. to
  838. uxtb reg3,reg1
  839. }
  840. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  841. (taicpu(p).ops=2) and
  842. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  843. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  844. (taicpu(hp1).ops=3) and
  845. (taicpu(hp1).oper[2]^.typ=top_const) and
  846. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  847. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  848. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  849. { reg1 might not be modified inbetween }
  850. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  851. begin
  852. DebugMsg('Peephole SxtbAndImm2Uxtb done', p);
  853. taicpu(hp1).opcode:=A_UXTB;
  854. taicpu(hp1).ops:=2;
  855. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  856. GetNextInstruction(p,hp2);
  857. asml.remove(p);
  858. p.free;
  859. p:=hp2;
  860. result:=true;
  861. end
  862. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  863. RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then
  864. Result:=true;
  865. end;
  866. function TARMAsmOptimizer.OptPass1SXTH(var p : tai) : Boolean;
  867. var
  868. hp1: tai;
  869. begin
  870. Result:=false;
  871. {
  872. change
  873. sxth reg2,reg1
  874. strh reg2,[...]
  875. dealloc reg2
  876. to
  877. strh reg1,[...]
  878. }
  879. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  880. (taicpu(p).ops=2) and
  881. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  882. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  883. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  884. { the reference in strb might not use reg2 }
  885. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  886. { reg1 might not be modified inbetween }
  887. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  888. begin
  889. DebugMsg('Peephole SXTHStrh2Strh done', p);
  890. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  891. GetNextInstruction(p, hp1);
  892. asml.remove(p);
  893. p.free;
  894. p:=hp1;
  895. result:=true;
  896. end
  897. {
  898. change
  899. sxth reg2,reg1
  900. sxth reg3,reg2
  901. dealloc reg2
  902. to
  903. sxth reg3,reg1
  904. }
  905. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  906. (taicpu(p).ops=2) and
  907. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  908. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  909. (taicpu(hp1).ops=2) and
  910. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  911. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  912. { reg1 might not be modified inbetween }
  913. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  914. begin
  915. DebugMsg('Peephole SxthSxth2Sxth done', p);
  916. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  917. taicpu(hp1).opcode:=A_SXTH;
  918. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  919. GetNextInstruction(p, hp1);
  920. asml.remove(p);
  921. p.free;
  922. p:=hp1;
  923. result:=true;
  924. end
  925. {$ifdef AARCH64}
  926. {
  927. change
  928. sxth reg2,reg1
  929. sxtw reg3,reg2
  930. dealloc reg2
  931. to
  932. sxth reg3,reg1
  933. }
  934. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  935. (taicpu(p).ops=2) and
  936. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  937. MatchInstruction(hp1, A_SXTW, [C_None], [PF_None]) and
  938. (taicpu(hp1).ops=2) and
  939. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  940. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  941. { reg1 might not be modified inbetween }
  942. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  943. begin
  944. DebugMsg('Peephole SxthSxtw2Sxth done', p);
  945. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  946. taicpu(hp1).opcode:=A_SXTH;
  947. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  948. GetNextInstruction(p, hp1);
  949. asml.remove(p);
  950. p.free;
  951. p:=hp1;
  952. result:=true;
  953. end
  954. {$endif AARCH64}
  955. {
  956. change
  957. sxth reg2,reg1
  958. and reg3,reg2,#65535
  959. dealloc reg2
  960. to
  961. uxth reg3,reg1
  962. }
  963. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  964. (taicpu(p).ops=2) and
  965. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  966. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  967. (taicpu(hp1).ops=3) and
  968. (taicpu(hp1).oper[2]^.typ=top_const) and
  969. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  970. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  971. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  972. { reg1 might not be modified inbetween }
  973. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  974. begin
  975. DebugMsg('Peephole SxthAndImm2Uxth done', p);
  976. taicpu(hp1).opcode:=A_UXTH;
  977. taicpu(hp1).ops:=2;
  978. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  979. GetNextInstruction(p, hp1);
  980. asml.remove(p);
  981. p.free;
  982. p:=hp1;
  983. result:=true;
  984. end
  985. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  986. RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then
  987. Result:=true;
  988. end;
  989. function TARMAsmOptimizer.OptPass1LDR(var p : tai) : Boolean;
  990. var
  991. hp1: tai;
  992. Reference: TReference;
  993. NewOp: TAsmOp;
  994. begin
  995. Result := False;
  996. if (taicpu(p).ops <> 2) or (taicpu(p).condition <> C_None) then
  997. Exit;
  998. Reference := taicpu(p).oper[1]^.ref^;
  999. if (Reference.addressmode = AM_OFFSET) and
  1000. not RegInRef(taicpu(p).oper[0]^.reg, Reference) and
  1001. { Delay calling GetNextInstruction for as long as possible }
  1002. GetNextInstruction(p, hp1) and
  1003. (hp1.typ = ait_instruction) and
  1004. (taicpu(hp1).condition = C_None) and
  1005. (taicpu(hp1).oppostfix = taicpu(p).oppostfix) then
  1006. begin
  1007. if (taicpu(hp1).opcode = A_STR) and
  1008. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) and
  1009. (getregtype(taicpu(p).oper[0]^.reg) = getregtype(taicpu(hp1).oper[0]^.reg)) then
  1010. begin
  1011. { With:
  1012. ldr reg1,[ref]
  1013. str reg2,[ref]
  1014. If reg1 = reg2, Remove str
  1015. }
  1016. if taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg then
  1017. begin
  1018. DebugMsg(SPeepholeOptimization + 'Removed redundant store instruction (load/store -> load/nop)', hp1);
  1019. RemoveInstruction(hp1);
  1020. Result := True;
  1021. Exit;
  1022. end;
  1023. end
  1024. else if (taicpu(hp1).opcode = A_LDR) and
  1025. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) then
  1026. begin
  1027. { With:
  1028. ldr reg1,[ref]
  1029. ldr reg2,[ref]
  1030. If reg1 = reg2, delete the second ldr
  1031. If reg1 <> reg2, changing the 2nd ldr to a mov might introduce
  1032. a dependency, but it will likely open up new optimisations, so
  1033. do it for now and handle any new dependencies later.
  1034. }
  1035. if taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg then
  1036. begin
  1037. DebugMsg(SPeepholeOptimization + 'Removed duplicate load instruction (load/load -> load/nop)', hp1);
  1038. RemoveInstruction(hp1);
  1039. Result := True;
  1040. Exit;
  1041. end
  1042. else if
  1043. (getregtype(taicpu(p).oper[0]^.reg) = R_INTREGISTER) and
  1044. (getregtype(taicpu(hp1).oper[0]^.reg) = R_INTREGISTER) and
  1045. (getsubreg(taicpu(p).oper[0]^.reg) = getsubreg(taicpu(hp1).oper[0]^.reg)) then
  1046. begin
  1047. DebugMsg(SPeepholeOptimization + 'Changed second ldr' + oppostfix2str[taicpu(hp1).oppostfix] + ' to mov (load/load -> load/move)', hp1);
  1048. taicpu(hp1).opcode := A_MOV;
  1049. taicpu(hp1).oppostfix := PF_None;
  1050. taicpu(hp1).loadreg(1, taicpu(p).oper[0]^.reg);
  1051. AllocRegBetween(taicpu(p).oper[0]^.reg, p, hp1, UsedRegs);
  1052. Result := True;
  1053. Exit;
  1054. end;
  1055. end;
  1056. end;
  1057. end;
  1058. function TARMAsmOptimizer.OptPass1STR(var p : tai) : Boolean;
  1059. var
  1060. hp1: tai;
  1061. Reference: TReference;
  1062. SizeMismatch: Boolean;
  1063. SrcReg, DstReg: TRegister;
  1064. NewOp: TAsmOp;
  1065. begin
  1066. Result := False;
  1067. if (taicpu(p).ops <> 2) or (taicpu(p).condition <> C_None) then
  1068. Exit;
  1069. Reference := taicpu(p).oper[1]^.ref^;
  1070. if (Reference.addressmode = AM_OFFSET) and
  1071. not RegInRef(taicpu(p).oper[0]^.reg, Reference) and
  1072. { Delay calling GetNextInstruction for as long as possible }
  1073. GetNextInstruction(p, hp1) and
  1074. (hp1.typ = ait_instruction) and
  1075. (taicpu(hp1).condition = C_None) and
  1076. (taicpu(hp1).oppostfix = taicpu(p).oppostfix) and
  1077. (taicpu(hp1).ops>0) and (taicpu(hp1).oper[0]^.typ=top_reg) then
  1078. begin
  1079. { Saves constant dereferencing and makes it easier to change the size if necessary }
  1080. SrcReg := taicpu(p).oper[0]^.reg;
  1081. DstReg := taicpu(hp1).oper[0]^.reg;
  1082. if (taicpu(hp1).opcode = A_LDR) and
  1083. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) and
  1084. (taicpu(hp1).oper[1]^.ref^.volatility=[]) and
  1085. (
  1086. (taicpu(hp1).oppostfix = taicpu(p).oppostfix) or
  1087. ((taicpu(p).oppostfix = PF_B) and (taicpu(hp1).oppostfix = PF_SB)) or
  1088. ((taicpu(p).oppostfix = PF_H) and (taicpu(hp1).oppostfix = PF_SH))
  1089. {$ifdef AARCH64}
  1090. or ((taicpu(p).oppostfix = PF_W) and (taicpu(hp1).oppostfix = PF_SW))
  1091. {$endif AARCH64}
  1092. ) then
  1093. begin
  1094. { With:
  1095. str reg1,[ref]
  1096. ldr reg2,[ref]
  1097. If reg1 = reg2, Remove ldr.
  1098. If reg1 <> reg2, replace ldr with "mov reg2,reg1"
  1099. }
  1100. if (SrcReg = DstReg) and
  1101. { e.g. the ldrb in strb/ldrb is not a null operation as it clears the upper 24 bits }
  1102. (taicpu(p).oppostfix=PF_None) then
  1103. begin
  1104. DebugMsg(SPeepholeOptimization + 'Removed redundant load instruction (store/load -> store/nop)', hp1);
  1105. RemoveInstruction(hp1);
  1106. Result := True;
  1107. Exit;
  1108. end
  1109. else if (getregtype(SrcReg) = R_INTREGISTER) and
  1110. (getregtype(DstReg) = R_INTREGISTER) and
  1111. (getsubreg(SrcReg) = getsubreg(DstReg)) then
  1112. begin
  1113. NewOp:=A_NONE;
  1114. if taicpu(hp1).oppostfix=PF_None then
  1115. NewOp:=A_MOV
  1116. else
  1117. {$ifdef ARM}
  1118. if (current_settings.cputype < cpu_armv6) then
  1119. begin
  1120. { The zero- and sign-extension operations were only
  1121. introduced under ARMv6 }
  1122. case taicpu(hp1).oppostfix of
  1123. PF_B:
  1124. begin
  1125. { The if-block afterwards will set the middle operand to the correct register }
  1126. taicpu(hp1).allocate_oper(3);
  1127. taicpu(hp1).ops := 3;
  1128. taicpu(hp1).loadconst(2, $FF);
  1129. NewOp := A_AND;
  1130. end;
  1131. PF_H:
  1132. { ARMv5 and under doesn't have a concise way of storing the immediate $FFFF, so leave alone };
  1133. PF_SB,
  1134. PF_SH:
  1135. { Do nothing - can't easily encode sign-extensions };
  1136. else
  1137. InternalError(2021043002);
  1138. end;
  1139. end
  1140. else
  1141. {$endif ARM}
  1142. case taicpu(hp1).oppostfix of
  1143. PF_B:
  1144. NewOp := A_UXTB;
  1145. PF_SB:
  1146. NewOp := A_SXTB;
  1147. PF_H:
  1148. NewOp := A_UXTH;
  1149. PF_SH:
  1150. NewOp := A_SXTH;
  1151. {$ifdef AARCH64}
  1152. PF_SW:
  1153. NewOp := A_SXTW;
  1154. PF_W:
  1155. NewOp := A_MOV;
  1156. {$endif AARCH64}
  1157. else
  1158. InternalError(2021043001);
  1159. end;
  1160. if (NewOp<>A_None) then
  1161. begin
  1162. DebugMsg(SPeepholeOptimization + 'Changed ldr' + oppostfix2str[taicpu(hp1).oppostfix] + ' to ' + gas_op2str[NewOp] + ' (store/load -> store/move)', hp1);
  1163. taicpu(hp1).oppostfix := PF_None;
  1164. taicpu(hp1).opcode := NewOp;
  1165. taicpu(hp1).loadreg(1, SrcReg);
  1166. AllocRegBetween(SrcReg, p, hp1, UsedRegs);
  1167. Result := True;
  1168. Exit;
  1169. end;
  1170. end
  1171. end
  1172. else if (taicpu(hp1).opcode = A_STR) and
  1173. RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) then
  1174. begin
  1175. { With:
  1176. str reg1,[ref]
  1177. str reg2,[ref]
  1178. If reg1 <> reg2, delete the first str
  1179. IF reg1 = reg2, delete the second str
  1180. }
  1181. if (SrcReg = DstReg) and (taicpu(hp1).oper[1]^.ref^.volatility=[]) then
  1182. begin
  1183. DebugMsg(SPeepholeOptimization + 'Removed duplicate store instruction (store/store -> store/nop)', hp1);
  1184. RemoveInstruction(hp1);
  1185. Result := True;
  1186. Exit;
  1187. end
  1188. else if
  1189. { Registers same byte size? }
  1190. (tcgsize2size[reg_cgsize(SrcReg)] = tcgsize2size[reg_cgsize(DstReg)]) and
  1191. (taicpu(p).oper[1]^.ref^.volatility=[]) then
  1192. begin
  1193. DebugMsg(SPeepholeOptimization + 'Removed dominated store instruction (store/store -> nop/store)', p);
  1194. RemoveCurrentP(p, hp1);
  1195. Result := True;
  1196. Exit;
  1197. end;
  1198. end;
  1199. end;
  1200. end;
  1201. function TARMAsmOptimizer.OptPass1And(var p : tai) : Boolean;
  1202. var
  1203. hp1, hp2: tai;
  1204. i: longint;
  1205. begin
  1206. Result:=false;
  1207. {
  1208. optimize
  1209. and reg2,reg1,const1
  1210. ...
  1211. }
  1212. if (taicpu(p).ops>2) and
  1213. (taicpu(p).oper[1]^.typ = top_reg) and
  1214. (taicpu(p).oper[2]^.typ = top_const) then
  1215. begin
  1216. {
  1217. change
  1218. and reg2,reg1,const1
  1219. ...
  1220. and reg3,reg2,const2
  1221. to
  1222. and reg3,reg1,(const1 and const2)
  1223. }
  1224. if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1225. MatchInstruction(hp1, A_AND, [taicpu(p).condition], [PF_None]) and
  1226. RegEndOfLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  1227. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1228. (taicpu(hp1).oper[2]^.typ = top_const)
  1229. {$ifdef AARCH64}
  1230. 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
  1231. ((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))
  1232. ) or
  1233. ((taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0))
  1234. {$endif AARCH64}
  1235. then
  1236. begin
  1237. if not(RegUsedBetween(taicpu(hp1).oper[0]^.reg,p,hp1)) then
  1238. begin
  1239. DebugMsg('Peephole AndAnd2And done', p);
  1240. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  1241. if (taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0 then
  1242. begin
  1243. DebugMsg('Peephole AndAnd2Mov0 1 done', p);
  1244. taicpu(p).opcode:=A_MOV;
  1245. taicpu(p).ops:=2;
  1246. taicpu(p).loadConst(1,0);
  1247. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  1248. end
  1249. else
  1250. begin
  1251. DebugMsg('Peephole AndAnd2And 1 done', p);
  1252. taicpu(p).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  1253. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  1254. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  1255. end;
  1256. asml.remove(hp1);
  1257. hp1.free;
  1258. Result:=true;
  1259. exit;
  1260. end
  1261. else if not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1262. begin
  1263. if (taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val)=0 then
  1264. begin
  1265. DebugMsg('Peephole AndAnd2Mov0 2 done', hp1);
  1266. taicpu(hp1).opcode:=A_MOV;
  1267. taicpu(hp1).loadConst(1,0);
  1268. taicpu(hp1).ops:=2;
  1269. taicpu(hp1).oppostfix:=taicpu(p).oppostfix;
  1270. end
  1271. else
  1272. begin
  1273. DebugMsg('Peephole AndAnd2And 2 done', hp1);
  1274. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  1275. taicpu(hp1).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  1276. taicpu(hp1).oppostfix:=taicpu(p).oppostfix;
  1277. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  1278. end;
  1279. GetNextInstruction(p, hp1);
  1280. RemoveCurrentP(p);
  1281. p:=hp1;
  1282. Result:=true;
  1283. exit;
  1284. end;
  1285. end
  1286. {
  1287. change
  1288. and reg2,reg1,$xxxxxxFF
  1289. strb reg2,[...]
  1290. dealloc reg2
  1291. to
  1292. strb reg1,[...]
  1293. }
  1294. else if ((taicpu(p).oper[2]^.val and $FF) = $FF) and
  1295. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  1296. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1297. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  1298. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  1299. { the reference in strb might not use reg2 }
  1300. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  1301. { reg1 might not be modified inbetween }
  1302. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1303. begin
  1304. DebugMsg('Peephole AndStrb2Strb done', p);
  1305. {$ifdef AARCH64}
  1306. taicpu(hp1).loadReg(0,newreg(R_INTREGISTER,getsupreg(taicpu(p).oper[1]^.reg),R_SUBD));
  1307. {$else AARCH64}
  1308. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  1309. {$endif AARCH64}
  1310. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  1311. RemoveCurrentP(p);
  1312. result:=true;
  1313. exit;
  1314. end
  1315. {
  1316. change
  1317. and reg2,reg1,255
  1318. uxtb/uxth reg3,reg2
  1319. dealloc reg2
  1320. to
  1321. and reg3,reg1,x
  1322. }
  1323. else if MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  1324. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1325. ((((taicpu(p).oper[2]^.val and $ffffff00)=0) and MatchInstruction(hp1, A_UXTB, [C_None], [PF_None])) or
  1326. (((taicpu(p).oper[2]^.val and $ffff0000)=0) and MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]))) and
  1327. (taicpu(hp1).ops = 2) and
  1328. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  1329. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1330. { reg1 might not be modified inbetween }
  1331. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1332. begin
  1333. DebugMsg('Peephole AndUxt2And done', p);
  1334. taicpu(hp1).opcode:=A_AND;
  1335. taicpu(hp1).ops:=3;
  1336. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  1337. taicpu(hp1).loadconst(2,taicpu(p).oper[2]^.val);
  1338. GetNextInstruction(p,hp1);
  1339. asml.remove(p);
  1340. p.Free;
  1341. p:=hp1;
  1342. result:=true;
  1343. exit;
  1344. end
  1345. else if ((taicpu(p).oper[2]^.val and $ffffff80)=0) and
  1346. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  1347. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1348. MatchInstruction(hp1, [A_SXTB,A_SXTH], [C_None], [PF_None]) and
  1349. (taicpu(hp1).ops = 2) and
  1350. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  1351. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1352. { reg1 might not be modified inbetween }
  1353. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1354. begin
  1355. DebugMsg('Peephole AndSxt2And done', p);
  1356. taicpu(hp1).opcode:=A_AND;
  1357. taicpu(hp1).ops:=3;
  1358. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  1359. taicpu(hp1).loadconst(2,taicpu(p).oper[2]^.val);
  1360. GetNextInstruction(p,hp1);
  1361. asml.remove(p);
  1362. p.Free;
  1363. p:=hp1;
  1364. result:=true;
  1365. exit;
  1366. end
  1367. {
  1368. from
  1369. and reg1,reg0,2^n-1
  1370. mov reg2,reg1, lsl imm1
  1371. (mov reg3,reg2, lsr/asr imm1)
  1372. remove either the and or the lsl/xsr sequence if possible
  1373. }
  1374. else if (taicpu(p).oper[2]^.val < high(int64)) and
  1375. cutils.ispowerof2(taicpu(p).oper[2]^.val+1,i) and
  1376. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  1377. MatchInstruction(hp1, A_MOV, [taicpu(p).condition], [PF_None]) and
  1378. (taicpu(hp1).ops=3) and
  1379. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  1380. (taicpu(hp1).oper[2]^.typ = top_shifterop) and
  1381. {$ifdef ARM}
  1382. (taicpu(hp1).oper[2]^.shifterop^.rs = NR_NO) and
  1383. {$endif ARM}
  1384. (taicpu(hp1).oper[2]^.shifterop^.shiftmode=SM_LSL) and
  1385. RegEndOfLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) then
  1386. begin
  1387. {
  1388. and reg1,reg0,2^n-1
  1389. mov reg2,reg1, lsl imm1
  1390. mov reg3,reg2, lsr/asr imm1
  1391. =>
  1392. and reg1,reg0,2^n-1
  1393. if lsr and 2^n-1>=imm1 or asr and 2^n-1>imm1
  1394. }
  1395. if GetNextInstructionUsingReg(hp1,hp2,taicpu(p).oper[0]^.reg) and
  1396. MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
  1397. (taicpu(hp2).ops=3) and
  1398. MatchOperand(taicpu(hp2).oper[1]^, taicpu(hp1).oper[0]^.reg) and
  1399. (taicpu(hp2).oper[2]^.typ = top_shifterop) and
  1400. {$ifdef ARM}
  1401. (taicpu(hp2).oper[2]^.shifterop^.rs = NR_NO) and
  1402. {$endif ARM}
  1403. (taicpu(hp2).oper[2]^.shifterop^.shiftmode in [SM_ASR,SM_LSR]) and
  1404. (taicpu(hp1).oper[2]^.shifterop^.shiftimm=taicpu(hp2).oper[2]^.shifterop^.shiftimm) and
  1405. RegEndOfLife(taicpu(hp1).oper[0]^.reg,taicpu(hp2)) and
  1406. ((i<32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) or
  1407. ((i=32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
  1408. (taicpu(hp2).oper[2]^.shifterop^.shiftmode=SM_LSR))) then
  1409. begin
  1410. DebugMsg('Peephole AndLslXsr2And done', p);
  1411. taicpu(p).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  1412. asml.Remove(hp1);
  1413. asml.Remove(hp2);
  1414. hp1.free;
  1415. hp2.free;
  1416. result:=true;
  1417. exit;
  1418. end
  1419. {
  1420. and reg1,reg0,2^n-1
  1421. mov reg2,reg1, lsl imm1
  1422. =>
  1423. mov reg2,reg0, lsl imm1
  1424. if imm1>i
  1425. }
  1426. else if (i>32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
  1427. not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) then
  1428. begin
  1429. DebugMsg('Peephole AndLsl2Lsl done', p);
  1430. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  1431. GetNextInstruction(p, hp1);
  1432. asml.Remove(p);
  1433. p.free;
  1434. p:=hp1;
  1435. result:=true;
  1436. exit;
  1437. end
  1438. end;
  1439. end;
  1440. {
  1441. change
  1442. and reg1, ...
  1443. mov reg2, reg1
  1444. to
  1445. and reg2, ...
  1446. }
  1447. if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  1448. (taicpu(p).ops>=3) and
  1449. RemoveSuperfluousMove(p, hp1, 'DataMov2Data') then
  1450. Result:=true;
  1451. end;
  1452. end.