aoptarm.pas 24 KB

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