aoptarm.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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. End;
  38. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  39. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  40. {$ifdef AARCH64}
  41. function MatchInstruction(const instr: tai; const op: TAsmOps; const postfix: TOpPostfixes): boolean;
  42. {$endif AARCH64}
  43. function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
  44. function RefsEqual(const r1, r2: treference): boolean;
  45. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  46. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  47. Implementation
  48. uses
  49. cutils,verbose,globtype,globals,
  50. systems,
  51. cpuinfo,
  52. cgobj,procinfo,
  53. aasmbase,aasmdata;
  54. {$ifdef DEBUG_AOPTCPU}
  55. procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);
  56. begin
  57. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  58. end;
  59. {$else DEBUG_AOPTCPU}
  60. procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  61. begin
  62. end;
  63. {$endif DEBUG_AOPTCPU}
  64. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  65. begin
  66. result :=
  67. (instr.typ = ait_instruction) and
  68. ((op = []) or ((ord(taicpu(instr).opcode)<256) and (taicpu(instr).opcode in op))) and
  69. ((cond = []) or (taicpu(instr).condition in cond)) and
  70. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  71. end;
  72. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  73. begin
  74. result :=
  75. (instr.typ = ait_instruction) and
  76. (taicpu(instr).opcode = op) and
  77. ((cond = []) or (taicpu(instr).condition in cond)) and
  78. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  79. end;
  80. {$ifdef AARCH64}
  81. function MatchInstruction(const instr: tai; const op: TAsmOps; const postfix: TOpPostfixes): boolean;
  82. begin
  83. result :=
  84. (instr.typ = ait_instruction) and
  85. ((op = []) or (taicpu(instr).opcode in op)) and
  86. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  87. end;
  88. {$endif AARCH64}
  89. function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
  90. begin
  91. result :=
  92. (instr.typ = ait_instruction) and
  93. (taicpu(instr).opcode = op) and
  94. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  95. end;
  96. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  97. begin
  98. result := (oper.typ = top_reg) and (oper.reg = reg);
  99. end;
  100. function RefsEqual(const r1, r2: treference): boolean;
  101. begin
  102. refsequal :=
  103. (r1.offset = r2.offset) and
  104. (r1.base = r2.base) and
  105. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  106. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  107. (r1.relsymbol = r2.relsymbol) and
  108. {$ifdef ARM}
  109. (r1.signindex = r2.signindex) and
  110. {$endif ARM}
  111. (r1.shiftimm = r2.shiftimm) and
  112. (r1.addressmode = r2.addressmode) and
  113. (r1.shiftmode = r2.shiftmode) and
  114. (r1.volatility=[]) and
  115. (r2.volatility=[]);
  116. end;
  117. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  118. begin
  119. result := oper1.typ = oper2.typ;
  120. if result then
  121. case oper1.typ of
  122. top_const:
  123. Result:=oper1.val = oper2.val;
  124. top_reg:
  125. Result:=oper1.reg = oper2.reg;
  126. top_conditioncode:
  127. Result:=oper1.cc = oper2.cc;
  128. top_realconst:
  129. Result:=oper1.val_real = oper2.val_real;
  130. top_ref:
  131. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  132. else Result:=false;
  133. end
  134. end;
  135. function TARMAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  136. Out Next: tai; reg: TRegister): Boolean;
  137. begin
  138. Next:=Current;
  139. repeat
  140. Result:=GetNextInstruction(Next,Next);
  141. until not (Result) or
  142. not(cs_opt_level3 in current_settings.optimizerswitches) or
  143. (Next.typ<>ait_instruction) or
  144. RegInInstruction(reg,Next) or
  145. is_calljmp(taicpu(Next).opcode)
  146. {$ifdef ARM}
  147. or RegModifiedByInstruction(NR_PC,Next);
  148. {$endif ARM}
  149. end;
  150. function TARMAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
  151. var
  152. alloc,
  153. dealloc : tai_regalloc;
  154. hp1 : tai;
  155. begin
  156. Result:=false;
  157. if MatchInstruction(movp, A_MOV, [taicpu(p).condition], [PF_None]) and
  158. { We can't optimize if there is a shiftop }
  159. (taicpu(movp).ops=2) and
  160. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  161. { don't mess with moves to fp }
  162. (taicpu(movp).oper[0]^.reg<>current_procinfo.framepointer) and
  163. { the destination register of the mov might not be used beween p and movp }
  164. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  165. {$ifdef ARM}
  166. { cb[n]z are thumb instructions which require specific registers, with no wide forms }
  167. (taicpu(p).opcode<>A_CBZ) and
  168. (taicpu(p).opcode<>A_CBNZ) and
  169. {There is a special requirement for MUL and MLA, oper[0] and oper[1] are not allowed to be the same}
  170. not (
  171. (taicpu(p).opcode in [A_MLA, A_MUL]) and
  172. (taicpu(p).oper[1]^.reg = taicpu(movp).oper[0]^.reg) and
  173. (current_settings.cputype < cpu_armv6)
  174. ) and
  175. {$endif ARM}
  176. { Take care to only do this for instructions which REALLY load to the first register.
  177. Otherwise
  178. str reg0, [reg1]
  179. mov reg2, reg0
  180. will be optimized to
  181. str reg2, [reg1]
  182. }
  183. RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
  184. begin
  185. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  186. if assigned(dealloc) then
  187. begin
  188. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  189. result:=true;
  190. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  191. and remove it if possible }
  192. asml.Remove(dealloc);
  193. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
  194. if assigned(alloc) then
  195. begin
  196. asml.Remove(alloc);
  197. alloc.free;
  198. dealloc.free;
  199. end
  200. else
  201. asml.InsertAfter(dealloc,p);
  202. { try to move the allocation of the target register }
  203. GetLastInstruction(movp,hp1);
  204. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  205. if assigned(alloc) then
  206. begin
  207. asml.Remove(alloc);
  208. asml.InsertBefore(alloc,p);
  209. { adjust used regs }
  210. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  211. end;
  212. { finally get rid of the mov }
  213. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  214. { Remove preindexing and postindexing for LDR in some cases.
  215. For example:
  216. ldr reg2,[reg1, xxx]!
  217. mov reg1,reg2
  218. must be translated to:
  219. ldr reg1,[reg1, xxx]
  220. Preindexing must be removed there, since the same register is used as the base and as the target.
  221. Such case is not allowed for ARM CPU and produces crash. }
  222. if (taicpu(p).opcode = A_LDR) and (taicpu(p).oper[1]^.typ = top_ref)
  223. and (taicpu(movp).oper[0]^.reg = taicpu(p).oper[1]^.ref^.base)
  224. then
  225. taicpu(p).oper[1]^.ref^.addressmode:=AM_OFFSET;
  226. asml.remove(movp);
  227. movp.free;
  228. end;
  229. end;
  230. end;
  231. function TARMAsmOptimizer.RedundantMovProcess(var p: tai;hp1: tai):boolean;
  232. var
  233. I: Integer;
  234. begin
  235. Result:=false;
  236. {
  237. change
  238. mov r1, r0
  239. add r1, r1, #1
  240. to
  241. add r1, r0, #1
  242. Todo: Make it work for mov+cmp too
  243. CAUTION! If this one is successful p might not be a mov instruction anymore!
  244. }
  245. if (taicpu(p).ops = 2) and
  246. (taicpu(p).oper[1]^.typ = top_reg) and
  247. (taicpu(p).oppostfix = PF_NONE) and
  248. MatchInstruction(hp1, [A_ADD, A_ADC,
  249. {$ifdef ARM}
  250. A_RSB, A_RSC,
  251. {$endif ARM}
  252. A_SUB, A_SBC,
  253. A_AND, A_BIC, A_EOR, A_ORR, A_MOV, A_MVN],
  254. [taicpu(p).condition], []) and
  255. { MOV and MVN might only have 2 ops }
  256. (taicpu(hp1).ops >= 2) and
  257. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^.reg) and
  258. (taicpu(hp1).oper[1]^.typ = top_reg) and
  259. (
  260. (taicpu(hp1).ops = 2) or
  261. (taicpu(hp1).oper[2]^.typ in [top_reg, top_const, top_shifterop])
  262. ) and
  263. {$ifdef AARCH64}
  264. (taicpu(p).oper[1]^.reg<>NR_SP) and
  265. {$endif AARCH64}
  266. not(RegUsedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  267. begin
  268. { When we get here we still don't know if the registers match }
  269. for I:=1 to 2 do
  270. {
  271. If the first loop was successful p will be replaced with hp1.
  272. The checks will still be ok, because all required information
  273. will also be in hp1 then.
  274. }
  275. if (taicpu(hp1).ops > I) and
  276. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[I]^.reg)
  277. {$ifdef ARM}
  278. { prevent certain combinations on thumb(2), this is only a safe approximation }
  279. and (not(GenerateThumbCode or GenerateThumb2Code) or
  280. ((getsupreg(taicpu(p).oper[1]^.reg)<>RS_R13) and
  281. (getsupreg(taicpu(p).oper[1]^.reg)<>RS_R15)))
  282. {$endif ARM}
  283. then
  284. begin
  285. DebugMsg('Peephole RedundantMovProcess done', hp1);
  286. taicpu(hp1).oper[I]^.reg := taicpu(p).oper[1]^.reg;
  287. if p<>hp1 then
  288. begin
  289. asml.remove(p);
  290. p.free;
  291. p:=hp1;
  292. Result:=true;
  293. end;
  294. end;
  295. end;
  296. end;
  297. function TARMAsmOptimizer.OptPass1UXTB(var p : tai) : Boolean;
  298. var
  299. hp1, hp2: tai;
  300. begin
  301. Result:=false;
  302. {
  303. change
  304. uxtb reg2,reg1
  305. strb reg2,[...]
  306. dealloc reg2
  307. to
  308. strb reg1,[...]
  309. }
  310. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  311. (taicpu(p).ops=2) and
  312. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  313. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  314. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  315. { the reference in strb might not use reg2 }
  316. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  317. { reg1 might not be modified inbetween }
  318. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  319. begin
  320. DebugMsg('Peephole UxtbStrb2Strb done', p);
  321. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  322. GetNextInstruction(p,hp2);
  323. asml.remove(p);
  324. p.free;
  325. p:=hp2;
  326. result:=true;
  327. end
  328. {
  329. change
  330. uxtb reg2,reg1
  331. uxth reg3,reg2
  332. dealloc reg2
  333. to
  334. uxtb reg3,reg1
  335. }
  336. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  337. (taicpu(p).ops=2) and
  338. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  339. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  340. (taicpu(hp1).ops = 2) and
  341. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  342. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  343. { reg1 might not be modified inbetween }
  344. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  345. begin
  346. DebugMsg('Peephole UxtbUxth2Uxtb done', p);
  347. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  348. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  349. asml.remove(hp1);
  350. hp1.free;
  351. result:=true;
  352. end
  353. {
  354. change
  355. uxtb reg2,reg1
  356. uxtb reg3,reg2
  357. dealloc reg2
  358. to
  359. uxtb reg3,reg1
  360. }
  361. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  362. (taicpu(p).ops=2) and
  363. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  364. MatchInstruction(hp1, A_UXTB, [C_None], [PF_None]) and
  365. (taicpu(hp1).ops = 2) and
  366. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  367. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  368. { reg1 might not be modified inbetween }
  369. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  370. begin
  371. DebugMsg('Peephole UxtbUxtb2Uxtb done', p);
  372. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  373. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  374. asml.remove(hp1);
  375. hp1.free;
  376. result:=true;
  377. end
  378. {
  379. change
  380. uxtb reg2,reg1
  381. and reg3,reg2,#0x*FF
  382. dealloc reg2
  383. to
  384. uxtb reg3,reg1
  385. }
  386. else if MatchInstruction(p, A_UXTB, [C_None], [PF_None]) and
  387. (taicpu(p).ops=2) and
  388. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  389. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  390. (taicpu(hp1).ops=3) and
  391. (taicpu(hp1).oper[2]^.typ=top_const) and
  392. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  393. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  394. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  395. { reg1 might not be modified inbetween }
  396. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  397. begin
  398. DebugMsg('Peephole UxtbAndImm2Uxtb done', p);
  399. taicpu(hp1).opcode:=A_UXTB;
  400. taicpu(hp1).ops:=2;
  401. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  402. GetNextInstruction(p,hp2);
  403. asml.remove(p);
  404. p.free;
  405. p:=hp2;
  406. result:=true;
  407. end
  408. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  409. RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then
  410. Result:=true;
  411. end;
  412. function TARMAsmOptimizer.OptPass1UXTH(var p : tai) : Boolean;
  413. var
  414. hp1: tai;
  415. begin
  416. Result:=false;
  417. {
  418. change
  419. uxth reg2,reg1
  420. strh reg2,[...]
  421. dealloc reg2
  422. to
  423. strh reg1,[...]
  424. }
  425. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  426. (taicpu(p).ops=2) and
  427. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  428. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  429. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  430. { the reference in strb might not use reg2 }
  431. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  432. { reg1 might not be modified inbetween }
  433. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  434. begin
  435. DebugMsg('Peephole UXTHStrh2Strh done', p);
  436. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  437. GetNextInstruction(p, hp1);
  438. asml.remove(p);
  439. p.free;
  440. p:=hp1;
  441. result:=true;
  442. end
  443. {
  444. change
  445. uxth reg2,reg1
  446. uxth reg3,reg2
  447. dealloc reg2
  448. to
  449. uxth reg3,reg1
  450. }
  451. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  452. (taicpu(p).ops=2) and
  453. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  454. MatchInstruction(hp1, A_UXTH, [C_None], [PF_None]) and
  455. (taicpu(hp1).ops=2) and
  456. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  457. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  458. { reg1 might not be modified inbetween }
  459. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  460. begin
  461. DebugMsg('Peephole UxthUxth2Uxth done', p);
  462. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  463. taicpu(hp1).opcode:=A_UXTH;
  464. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  465. GetNextInstruction(p, hp1);
  466. asml.remove(p);
  467. p.free;
  468. p:=hp1;
  469. result:=true;
  470. end
  471. {
  472. change
  473. uxth reg2,reg1
  474. and reg3,reg2,#65535
  475. dealloc reg2
  476. to
  477. uxth reg3,reg1
  478. }
  479. else if MatchInstruction(p, A_UXTH, [C_None], [PF_None]) and
  480. (taicpu(p).ops=2) and
  481. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  482. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  483. (taicpu(hp1).ops=3) and
  484. (taicpu(hp1).oper[2]^.typ=top_const) and
  485. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  486. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  487. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  488. { reg1 might not be modified inbetween }
  489. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  490. begin
  491. DebugMsg('Peephole UxthAndImm2Uxth done', p);
  492. taicpu(hp1).opcode:=A_UXTH;
  493. taicpu(hp1).ops:=2;
  494. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  495. GetNextInstruction(p, hp1);
  496. asml.remove(p);
  497. p.free;
  498. p:=hp1;
  499. result:=true;
  500. end
  501. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  502. RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then
  503. Result:=true;
  504. end;
  505. function TARMAsmOptimizer.OptPass1SXTB(var p : tai) : Boolean;
  506. var
  507. hp1, hp2: tai;
  508. begin
  509. Result:=false;
  510. {
  511. change
  512. sxtb reg2,reg1
  513. strb reg2,[...]
  514. dealloc reg2
  515. to
  516. strb reg1,[...]
  517. }
  518. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  519. (taicpu(p).ops=2) and
  520. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  521. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  522. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  523. { the reference in strb might not use reg2 }
  524. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  525. { reg1 might not be modified inbetween }
  526. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  527. begin
  528. DebugMsg('Peephole SxtbStrb2Strb done', p);
  529. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  530. GetNextInstruction(p,hp2);
  531. asml.remove(p);
  532. p.free;
  533. p:=hp2;
  534. result:=true;
  535. end
  536. {
  537. change
  538. sxtb reg2,reg1
  539. sxth reg3,reg2
  540. dealloc reg2
  541. to
  542. sxtb reg3,reg1
  543. }
  544. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  545. (taicpu(p).ops=2) and
  546. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  547. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  548. (taicpu(hp1).ops = 2) and
  549. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  550. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  551. { reg1 might not be modified inbetween }
  552. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  553. begin
  554. DebugMsg('Peephole SxtbSxth2Sxtb done', p);
  555. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  556. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  557. asml.remove(hp1);
  558. hp1.free;
  559. result:=true;
  560. end
  561. {
  562. change
  563. sxtb reg2,reg1
  564. sxtb reg3,reg2
  565. dealloc reg2
  566. to
  567. uxtb reg3,reg1
  568. }
  569. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  570. (taicpu(p).ops=2) and
  571. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  572. MatchInstruction(hp1, A_SXTB, [C_None], [PF_None]) and
  573. (taicpu(hp1).ops = 2) and
  574. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  575. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  576. { reg1 might not be modified inbetween }
  577. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  578. begin
  579. DebugMsg('Peephole SxtbSxtb2Sxtb done', p);
  580. AllocRegBetween(taicpu(hp1).oper[0]^.reg,p,hp1,UsedRegs);
  581. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  582. asml.remove(hp1);
  583. hp1.free;
  584. result:=true;
  585. end
  586. {
  587. change
  588. sxtb reg2,reg1
  589. and reg3,reg2,#0x*FF
  590. dealloc reg2
  591. to
  592. uxtb reg3,reg1
  593. }
  594. else if MatchInstruction(p, A_SXTB, [C_None], [PF_None]) and
  595. (taicpu(p).ops=2) and
  596. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  597. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  598. (taicpu(hp1).ops=3) and
  599. (taicpu(hp1).oper[2]^.typ=top_const) and
  600. ((taicpu(hp1).oper[2]^.val and $FF)=$FF) and
  601. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  602. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  603. { reg1 might not be modified inbetween }
  604. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  605. begin
  606. DebugMsg('Peephole SxtbAndImm2Sxtb done', p);
  607. taicpu(hp1).opcode:=A_SXTB;
  608. taicpu(hp1).ops:=2;
  609. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  610. GetNextInstruction(p,hp2);
  611. asml.remove(p);
  612. p.free;
  613. p:=hp2;
  614. result:=true;
  615. end
  616. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  617. RemoveSuperfluousMove(p, hp1, 'SxtbMov2Data') then
  618. Result:=true;
  619. end;
  620. function TARMAsmOptimizer.OptPass1SXTH(var p : tai) : Boolean;
  621. var
  622. hp1: tai;
  623. begin
  624. Result:=false;
  625. {
  626. change
  627. sxth reg2,reg1
  628. strh reg2,[...]
  629. dealloc reg2
  630. to
  631. strh reg1,[...]
  632. }
  633. if MatchInstruction(p, taicpu(p).opcode, [C_None], [PF_None]) and
  634. (taicpu(p).ops=2) and
  635. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  636. MatchInstruction(hp1, A_STR, [C_None], [PF_H]) and
  637. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  638. { the reference in strb might not use reg2 }
  639. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  640. { reg1 might not be modified inbetween }
  641. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  642. begin
  643. DebugMsg('Peephole SXTHStrh2Strh done', p);
  644. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  645. GetNextInstruction(p, hp1);
  646. asml.remove(p);
  647. p.free;
  648. p:=hp1;
  649. result:=true;
  650. end
  651. {
  652. change
  653. sxth reg2,reg1
  654. sxth reg3,reg2
  655. dealloc reg2
  656. to
  657. sxth reg3,reg1
  658. }
  659. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  660. (taicpu(p).ops=2) and
  661. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  662. MatchInstruction(hp1, A_SXTH, [C_None], [PF_None]) and
  663. (taicpu(hp1).ops=2) and
  664. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  665. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  666. { reg1 might not be modified inbetween }
  667. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  668. begin
  669. DebugMsg('Peephole SxthSxth2Sxth done', p);
  670. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,UsedRegs);
  671. taicpu(hp1).opcode:=A_SXTH;
  672. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  673. GetNextInstruction(p, hp1);
  674. asml.remove(p);
  675. p.free;
  676. p:=hp1;
  677. result:=true;
  678. end
  679. {
  680. change
  681. sxth reg2,reg1
  682. and reg3,reg2,#65535
  683. dealloc reg2
  684. to
  685. sxth reg3,reg1
  686. }
  687. else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and
  688. (taicpu(p).ops=2) and
  689. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  690. MatchInstruction(hp1, A_AND, [C_None], [PF_None]) and
  691. (taicpu(hp1).ops=3) and
  692. (taicpu(hp1).oper[2]^.typ=top_const) and
  693. ((taicpu(hp1).oper[2]^.val and $FFFF)=$FFFF) and
  694. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  695. RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
  696. { reg1 might not be modified inbetween }
  697. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  698. begin
  699. DebugMsg('Peephole SxthAndImm2Sxth done', p);
  700. taicpu(hp1).opcode:=A_SXTH;
  701. taicpu(hp1).ops:=2;
  702. taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg);
  703. GetNextInstruction(p, hp1);
  704. asml.remove(p);
  705. p.free;
  706. p:=hp1;
  707. result:=true;
  708. end
  709. else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  710. RemoveSuperfluousMove(p, hp1, 'SxthMov2Data') then
  711. Result:=true;
  712. end;
  713. end.