aoptcpu.pas 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit implements the ARM optimizer object
  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 aoptcpu;
  19. {$i fpcdefs.inc}
  20. { $define DEBUG_AOPTCPU}
  21. Interface
  22. uses cpubase,cgbase,aasmtai,aopt,AoptObj,aoptcpub;
  23. Type
  24. TCpuAsmOptimizer = class(TAsmOptimizer)
  25. { outputs a debug message into the assembler file }
  26. procedure DebugMsg(const s: string; p: tai);
  27. Function GetNextInstructionUsingReg(Current: tai; Var Next: tai;reg : TRegister): Boolean;
  28. function RegInInstruction(Reg: TRegister; p1: tai): Boolean; override;
  29. function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
  30. function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
  31. function InvertSkipInstruction(var p: tai): boolean;
  32. { uses the same constructor as TAopObj }
  33. function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
  34. procedure PeepHoleOptPass2;override;
  35. End;
  36. Implementation
  37. uses
  38. cutils,
  39. verbose,
  40. cpuinfo,
  41. aasmbase,aasmcpu,aasmdata,
  42. aoptutils,
  43. globals,globtype,
  44. cgutils;
  45. type
  46. TAsmOpSet = set of TAsmOp;
  47. function CanBeCond(p : tai) : boolean;
  48. begin
  49. result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
  50. end;
  51. function RefsEqual(const r1, r2: treference): boolean;
  52. begin
  53. refsequal :=
  54. (r1.offset = r2.offset) and
  55. (r1.base = r2.base) and
  56. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  57. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  58. (r1.relsymbol = r2.relsymbol) and
  59. (r1.addressmode = r2.addressmode) and
  60. (r1.volatility=[]) and
  61. (r2.volatility=[]);
  62. end;
  63. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  64. begin
  65. result:=oper1.typ=oper2.typ;
  66. if result then
  67. case oper1.typ of
  68. top_const:
  69. Result:=oper1.val = oper2.val;
  70. top_reg:
  71. Result:=oper1.reg = oper2.reg;
  72. top_ref:
  73. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  74. else Result:=false;
  75. end
  76. end;
  77. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  78. begin
  79. result := (oper.typ = top_reg) and (oper.reg = reg);
  80. end;
  81. function MatchInstruction(const instr: tai; const op: TAsmOp): boolean;
  82. begin
  83. result :=
  84. (instr.typ = ait_instruction) and
  85. (taicpu(instr).opcode = op);
  86. end;
  87. function MatchInstruction(const instr: tai; const ops: TAsmOpSet): boolean;
  88. begin
  89. result :=
  90. (instr.typ = ait_instruction) and
  91. (taicpu(instr).opcode in ops);
  92. end;
  93. function MatchInstruction(const instr: tai; const ops: TAsmOpSet;opcount : byte): boolean;
  94. begin
  95. result :=
  96. (instr.typ = ait_instruction) and
  97. (taicpu(instr).opcode in ops) and
  98. (taicpu(instr).ops=opcount);
  99. end;
  100. {$ifdef DEBUG_AOPTCPU}
  101. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
  102. begin
  103. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  104. end;
  105. {$else DEBUG_AOPTCPU}
  106. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  107. begin
  108. end;
  109. {$endif DEBUG_AOPTCPU}
  110. function TCpuAsmOptimizer.RegInInstruction(Reg: TRegister; p1: tai): Boolean;
  111. begin
  112. If (p1.typ = ait_instruction) and (taicpu(p1).opcode in [A_MUL,A_MULS,A_FMUL,A_FMULS,A_FMULSU]) and
  113. ((getsupreg(reg)=RS_R0) or (getsupreg(reg)=RS_R1)) then
  114. Result:=true
  115. else if (p1.typ = ait_instruction) and (taicpu(p1).opcode=A_MOVW) and
  116. ((TRegister(ord(taicpu(p1).oper[0]^.reg)+1)=reg) or (TRegister(ord(taicpu(p1).oper[1]^.reg)+1)=reg) or
  117. (taicpu(p1).oper[0]^.reg=reg) or (taicpu(p1).oper[1]^.reg=reg)) then
  118. Result:=true
  119. else
  120. Result:=inherited RegInInstruction(Reg, p1);
  121. end;
  122. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  123. var Next: tai; reg: TRegister): Boolean;
  124. begin
  125. Next:=Current;
  126. repeat
  127. Result:=GetNextInstruction(Next,Next);
  128. until not(cs_opt_level3 in current_settings.optimizerswitches) or not(Result) or (Next.typ<>ait_instruction) or (RegInInstruction(reg,Next)) or
  129. (is_calljmp(taicpu(Next).opcode));
  130. end;
  131. function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  132. var
  133. p: taicpu;
  134. begin
  135. if not assigned(hp) or
  136. (hp.typ <> ait_instruction) then
  137. begin
  138. Result := false;
  139. exit;
  140. end;
  141. p := taicpu(hp);
  142. Result := ((p.opcode in [A_LDI,A_MOV,A_LDS]) and (reg=p.oper[0]^.reg) and ((p.oper[1]^.typ<>top_reg) or (reg<>p.oper[0]^.reg))) or
  143. ((p.opcode in [A_LD,A_LDD,A_LPM]) and (reg=p.oper[0]^.reg) and not(RegInRef(reg,p.oper[1]^.ref^))) or
  144. ((p.opcode in [A_MOVW]) and ((reg=p.oper[0]^.reg) or (TRegister(ord(reg)+1)=p.oper[0]^.reg)) and not(reg=p.oper[1]^.reg) and not(TRegister(ord(reg)+1)=p.oper[1]^.reg)) or
  145. ((p.opcode in [A_POP]) and (reg=p.oper[0]^.reg));
  146. end;
  147. function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  148. var
  149. p: taicpu;
  150. i: longint;
  151. begin
  152. Result := false;
  153. if not (assigned(hp) and (hp.typ = ait_instruction)) then
  154. exit;
  155. p:=taicpu(hp);
  156. i:=0;
  157. { we do not care about the stack pointer }
  158. if p.opcode in [A_POP] then
  159. exit;
  160. { first operand only written?
  161. then skip it }
  162. if p.opcode in [A_MOV,A_LD,A_LDD,A_LDS,A_LPM,A_LDI,A_MOVW] then
  163. i:=1;
  164. while i<p.ops do
  165. begin
  166. case p.oper[i]^.typ of
  167. top_reg:
  168. Result := (p.oper[i]^.reg = reg) or
  169. { MOVW }
  170. ((i=1) and (p.opcode=A_MOVW) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg)));
  171. top_ref:
  172. Result :=
  173. (p.oper[i]^.ref^.base = reg) or
  174. (p.oper[i]^.ref^.index = reg);
  175. end;
  176. { Bailout if we found something }
  177. if Result then
  178. exit;
  179. Inc(i);
  180. end;
  181. end;
  182. {
  183. Turns
  184. sbis ?
  185. jmp .Lx
  186. op
  187. .Lx:
  188. Into
  189. sbic ?
  190. op
  191. For all types of skip instructions
  192. }
  193. function TCpuAsmOptimizer.InvertSkipInstruction(var p: tai): boolean;
  194. function GetNextInstructionWithoutLabel(p: tai; var next: tai): boolean;
  195. begin
  196. repeat
  197. result:=GetNextInstruction(p,next);
  198. p:=next;
  199. until
  200. (not result) or
  201. (not assigned(next)) or
  202. (next.typ in [ait_instruction]);
  203. result:=assigned(next) and (next.typ in [ait_instruction]);
  204. end;
  205. var
  206. hp1, hp2, hp3: tai;
  207. s: string;
  208. begin
  209. result:=false;
  210. if GetNextInstruction(taicpu(p),hp1) and
  211. (hp1.typ=ait_instruction) and
  212. (taicpu(hp1).opcode in [A_RJMP,A_JMP]) and
  213. (taicpu(hp1).ops=1) and
  214. (taicpu(hp1).oper[0]^.typ=top_ref) and
  215. (taicpu(hp1).oper[0]^.ref^.offset=0) and
  216. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  217. GetNextInstructionWithoutLabel(hp1,hp2) and
  218. (hp2.typ=ait_instruction) and
  219. (not taicpu(hp2).is_jmp) and
  220. GetNextInstruction(hp2,hp3) and
  221. FindLabel(TAsmLabel(taicpu(hp1).oper[0]^.ref^.symbol),hp3) then
  222. begin
  223. DebugMsg('SkipJump2InvertedSkip', p);
  224. case taicpu(p).opcode of
  225. A_SBIS: taicpu(p).opcode:=A_SBIC;
  226. A_SBIC: taicpu(p).opcode:=A_SBIS;
  227. A_SBRS: taicpu(p).opcode:=A_SBRC;
  228. A_SBRC: taicpu(p).opcode:=A_SBRS;
  229. end;
  230. TAsmLabel(taicpu(hp1).oper[0]^.ref^.symbol).decrefs;
  231. asml.remove(hp1);
  232. hp1.free;
  233. end;
  234. end;
  235. function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  236. var
  237. hp1,hp2,hp3,hp4,hp5: tai;
  238. alloc, dealloc: tai_regalloc;
  239. i: integer;
  240. l: TAsmLabel;
  241. begin
  242. result := false;
  243. case p.typ of
  244. ait_instruction:
  245. begin
  246. {
  247. change
  248. <op> reg,x,y
  249. cp reg,r1
  250. into
  251. <op>s reg,x,y
  252. }
  253. { this optimization can applied only to the currently enabled operations because
  254. the other operations do not update all flags and FPC does not track flag usage }
  255. if MatchInstruction(p, [A_ADC,A_ADD,A_AND,A_ANDI,A_ASR,A_COM,A_DEC,A_EOR,
  256. A_INC,A_LSL,A_LSR,
  257. A_OR,A_ORI,A_ROL,A_ROR,A_SBC,A_SBCI,A_SUB,A_SUBI]) and
  258. GetNextInstruction(p, hp1) and
  259. ((MatchInstruction(hp1, A_CP) and
  260. (((taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg) and
  261. (taicpu(hp1).oper[1]^.reg = GetDefaultZeroReg)) or
  262. ((taicpu(p).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
  263. (taicpu(hp1).oper[0]^.reg = GetDefaultZeroReg) and
  264. (taicpu(p).opcode in [A_ADC,A_ADD,A_AND,A_ANDI,A_ASR,A_COM,A_EOR,
  265. A_LSL,A_LSR,
  266. A_OR,A_ORI,A_ROL,A_ROR,A_SUB,A_SBI])))) or
  267. (MatchInstruction(hp1, A_CPI) and
  268. (taicpu(p).opcode = A_ANDI) and
  269. (taicpu(p).oper[1]^.typ=top_const) and
  270. (taicpu(hp1).oper[1]^.typ=top_const) and
  271. (taicpu(p).oper[1]^.val=taicpu(hp1).oper[1]^.val))) and
  272. GetNextInstruction(hp1, hp2) and
  273. { be careful here, following instructions could use other flags
  274. however after a jump fpc never depends on the value of flags }
  275. { All above instructions set Z and N according to the following
  276. Z := result = 0;
  277. N := result[31];
  278. EQ = Z=1; NE = Z=0;
  279. MI = N=1; PL = N=0; }
  280. MatchInstruction(hp2, A_BRxx) and
  281. ((taicpu(hp2).condition in [C_EQ,C_NE,C_MI,C_PL]) or
  282. { sub/sbc set all flags }
  283. (taicpu(p).opcode in [A_SUB,A_SBI])){ and
  284. no flag allocation tracking implemented yet on avr
  285. assigned(FindRegDealloc(NR_DEFAULTFLAGS,tai(hp2.Next)))} then
  286. begin
  287. { move flag allocation if possible }
  288. { no flag allocation tracking implemented yet on avr
  289. GetLastInstruction(hp1, hp2);
  290. hp2:=FindRegAlloc(NR_DEFAULTFLAGS,tai(hp2.Next));
  291. if assigned(hp2) then
  292. begin
  293. asml.Remove(hp2);
  294. asml.insertbefore(hp2, p);
  295. end;
  296. }
  297. // If we compare to the same value we are masking then invert the comparison
  298. if (taicpu(hp1).opcode=A_CPI) or
  299. { sub/sbc with reverted? }
  300. ((taicpu(hp1).oper[0]^.reg = GetDefaultZeroReg) and (taicpu(p).opcode in [A_SUB,A_SBI])) then
  301. taicpu(hp2).condition:=inverse_cond(taicpu(hp2).condition);
  302. asml.InsertBefore(tai_regalloc.alloc(NR_DEFAULTFLAGS,p), p);
  303. asml.InsertAfter(tai_regalloc.dealloc(NR_DEFAULTFLAGS,hp2), hp2);
  304. IncludeRegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs);
  305. DebugMsg('Peephole OpCp2Op performed', p);
  306. asml.remove(hp1);
  307. hp1.free;
  308. Result:=true;
  309. end
  310. else
  311. case taicpu(p).opcode of
  312. A_LDI:
  313. begin
  314. { turn
  315. ldi reg0, imm
  316. <op> reg1, reg0
  317. dealloc reg0
  318. into
  319. <op>i reg1, imm
  320. }
  321. if MatchOpType(taicpu(p),top_reg,top_const) and
  322. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  323. MatchInstruction(hp1,[A_CP,A_MOV,A_AND,A_SUB],2) and
  324. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  325. MatchOpType(taicpu(hp1),top_reg,top_reg) and
  326. (getsupreg(taicpu(hp1).oper[0]^.reg) in [16..31]) and
  327. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  328. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) then
  329. begin
  330. TransferUsedRegs(TmpUsedRegs);
  331. UpdateUsedRegs(TmpUsedRegs,tai(p.next));
  332. UpdateUsedRegs(TmpUsedRegs,tai(hp1.next));
  333. if not(RegUsedAfterInstruction(taicpu(hp1).oper[1]^.reg, hp1, TmpUsedRegs)) then
  334. begin
  335. case taicpu(hp1).opcode of
  336. A_CP:
  337. taicpu(hp1).opcode:=A_CPI;
  338. A_MOV:
  339. taicpu(hp1).opcode:=A_LDI;
  340. A_AND:
  341. taicpu(hp1).opcode:=A_ANDI;
  342. A_SUB:
  343. taicpu(hp1).opcode:=A_SUBI;
  344. else
  345. internalerror(2016111901);
  346. end;
  347. taicpu(hp1).loadconst(1, taicpu(p).oper[1]^.val);
  348. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  349. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  350. if assigned(alloc) and assigned(dealloc) then
  351. begin
  352. asml.Remove(alloc);
  353. alloc.Free;
  354. asml.Remove(dealloc);
  355. dealloc.Free;
  356. end;
  357. DebugMsg('Peephole LdiOp2Opi performed', p);
  358. result:=RemoveCurrentP(p);
  359. end;
  360. end;
  361. end;
  362. A_STS:
  363. if (taicpu(p).oper[0]^.ref^.symbol=nil) and
  364. (taicpu(p).oper[0]^.ref^.relsymbol=nil) and
  365. (getsupreg(taicpu(p).oper[0]^.ref^.base)=RS_NO) and
  366. (getsupreg(taicpu(p).oper[0]^.ref^.index)=RS_NO) and
  367. (taicpu(p).oper[0]^.ref^.addressmode=AM_UNCHANGED) and
  368. (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  369. (taicpu(p).oper[0]^.ref^.offset>=0) and
  370. (taicpu(p).oper[0]^.ref^.offset<=63)) or
  371. (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  372. (taicpu(p).oper[0]^.ref^.offset>=32) and
  373. (taicpu(p).oper[0]^.ref^.offset<=95))) then
  374. begin
  375. DebugMsg('Peephole Sts2Out performed', p);
  376. taicpu(p).opcode:=A_OUT;
  377. if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
  378. taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset)
  379. else
  380. taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset-32);
  381. result:=true;
  382. end;
  383. A_LDS:
  384. if (taicpu(p).oper[1]^.ref^.symbol=nil) and
  385. (taicpu(p).oper[1]^.ref^.relsymbol=nil) and
  386. (getsupreg(taicpu(p).oper[1]^.ref^.base)=RS_NO) and
  387. (getsupreg(taicpu(p).oper[1]^.ref^.index)=RS_NO) and
  388. (taicpu(p).oper[1]^.ref^.addressmode=AM_UNCHANGED) and
  389. (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  390. (taicpu(p).oper[1]^.ref^.offset>=0) and
  391. (taicpu(p).oper[1]^.ref^.offset<=63)) or
  392. (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  393. (taicpu(p).oper[1]^.ref^.offset>=32) and
  394. (taicpu(p).oper[1]^.ref^.offset<=95))) then
  395. begin
  396. DebugMsg('Peephole Lds2In performed', p);
  397. taicpu(p).opcode:=A_IN;
  398. if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
  399. taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset)
  400. else
  401. taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset-32);
  402. result:=true;
  403. end;
  404. A_IN:
  405. if GetNextInstruction(p,hp1) then
  406. begin
  407. {
  408. in rX,Y
  409. ori rX,n
  410. out Y,rX
  411. into
  412. sbi rX,lg(n)
  413. }
  414. if (taicpu(p).oper[1]^.val<=31) and
  415. MatchInstruction(hp1,A_ORI) and
  416. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  417. (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
  418. GetNextInstruction(hp1,hp2) and
  419. MatchInstruction(hp2,A_OUT) and
  420. MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
  421. MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
  422. begin
  423. DebugMsg('Peephole InOriOut2Sbi performed', p);
  424. taicpu(p).opcode:=A_SBI;
  425. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  426. taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
  427. asml.Remove(hp1);
  428. hp1.Free;
  429. asml.Remove(hp2);
  430. hp2.Free;
  431. result:=true;
  432. end
  433. {
  434. in rX,Y
  435. andi rX,not(n)
  436. out Y,rX
  437. into
  438. cbi rX,lg(n)
  439. }
  440. else if (taicpu(p).oper[1]^.val<=31) and
  441. MatchInstruction(hp1,A_ANDI) and
  442. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  443. (PopCnt(byte(not(taicpu(hp1).oper[1]^.val)))=1) and
  444. GetNextInstruction(hp1,hp2) and
  445. MatchInstruction(hp2,A_OUT) and
  446. MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
  447. MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
  448. begin
  449. DebugMsg('Peephole InAndiOut2Cbi performed', p);
  450. taicpu(p).opcode:=A_CBI;
  451. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  452. taicpu(p).loadconst(1,BsrByte(not(taicpu(hp1).oper[1]^.val)));
  453. asml.Remove(hp1);
  454. hp1.Free;
  455. asml.Remove(hp2);
  456. hp2.Free;
  457. result:=true;
  458. end
  459. {
  460. in rX,Y
  461. andi rX,n
  462. breq/brne L1
  463. into
  464. sbis/sbic Y,lg(n)
  465. jmp L1
  466. .Ltemp:
  467. }
  468. else if (taicpu(p).oper[1]^.val<=31) and
  469. MatchInstruction(hp1,A_ANDI) and
  470. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  471. (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
  472. GetNextInstruction(hp1,hp2) and
  473. MatchInstruction(hp2,A_BRxx) and
  474. (taicpu(hp2).condition in [C_EQ,C_NE]) then
  475. begin
  476. if taicpu(hp2).condition=C_EQ then
  477. taicpu(p).opcode:=A_SBIS
  478. else
  479. taicpu(p).opcode:=A_SBIC;
  480. DebugMsg('Peephole InAndiBrx2SbixJmp performed', p);
  481. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  482. taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
  483. asml.Remove(hp1);
  484. hp1.Free;
  485. taicpu(hp2).condition:=C_None;
  486. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  487. taicpu(hp2).opcode:=A_JMP
  488. else
  489. taicpu(hp2).opcode:=A_RJMP;
  490. current_asmdata.getjumplabel(l);
  491. l.increfs;
  492. asml.InsertAfter(tai_label.create(l), hp2);
  493. result:=true;
  494. end;
  495. end;
  496. A_SBRS,
  497. A_SBRC:
  498. begin
  499. {
  500. Turn
  501. in rx, y
  502. sbr* rx, z
  503. Into
  504. sbi* y, z
  505. }
  506. if (taicpu(p).ops=2) and
  507. (taicpu(p).oper[0]^.typ=top_reg) and
  508. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  509. GetLastInstruction(p,hp1) and
  510. (hp1.typ=ait_instruction) and
  511. (taicpu(hp1).opcode=A_IN) and
  512. (taicpu(hp1).ops=2) and
  513. (taicpu(hp1).oper[1]^.typ=top_const) and
  514. (taicpu(hp1).oper[1]^.val in [0..31]) and
  515. MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^.reg) and
  516. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, hp1, p)) then
  517. begin
  518. if taicpu(p).opcode=A_SBRS then
  519. taicpu(p).opcode:=A_SBIS
  520. else
  521. taicpu(p).opcode:=A_SBIC;
  522. taicpu(p).loadconst(0, taicpu(hp1).oper[1]^.val);
  523. DebugMsg('Peephole InSbrx2Sbix performed', p);
  524. asml.Remove(hp1);
  525. hp1.free;
  526. result:=true;
  527. end;
  528. if InvertSkipInstruction(p) then
  529. result:=true;
  530. end;
  531. A_ANDI:
  532. begin
  533. {
  534. Turn
  535. andi rx, #pow2
  536. brne l
  537. <op>
  538. l:
  539. Into
  540. sbrs rx, #(1 shl imm)
  541. <op>
  542. l:
  543. }
  544. if (taicpu(p).ops=2) and
  545. (taicpu(p).oper[1]^.typ=top_const) and
  546. ispowerof2(taicpu(p).oper[1]^.val,i) and
  547. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  548. GetNextInstruction(p,hp1) and
  549. (hp1.typ=ait_instruction) and
  550. (taicpu(hp1).opcode=A_BRxx) and
  551. (taicpu(hp1).condition in [C_EQ,C_NE]) and
  552. (taicpu(hp1).ops>0) and
  553. (taicpu(hp1).oper[0]^.typ = top_ref) and
  554. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  555. GetNextInstruction(hp1,hp2) and
  556. (hp2.typ=ait_instruction) and
  557. GetNextInstruction(hp2,hp3) and
  558. (hp3.typ=ait_label) and
  559. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then
  560. begin
  561. DebugMsg('Peephole AndiBr2Sbr performed', p);
  562. taicpu(p).oper[1]^.val:=i;
  563. if taicpu(hp1).condition=C_NE then
  564. taicpu(p).opcode:=A_SBRS
  565. else
  566. taicpu(p).opcode:=A_SBRC;
  567. asml.Remove(hp1);
  568. hp1.free;
  569. result:=true;
  570. end
  571. {
  572. Remove
  573. andi rx, #y
  574. dealloc rx
  575. }
  576. else if (taicpu(p).ops=2) and
  577. (taicpu(p).oper[0]^.typ=top_reg) and
  578. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  579. (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or
  580. (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then
  581. begin
  582. DebugMsg('Redundant Andi removed', p);
  583. result:=RemoveCurrentP(p);
  584. end;
  585. end;
  586. A_ADD:
  587. begin
  588. if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
  589. GetNextInstruction(p, hp1) and
  590. MatchInstruction(hp1,A_ADC) then
  591. begin
  592. DebugMsg('Peephole AddAdc2Add performed', p);
  593. RemoveCurrentP(p, hp1);
  594. Result := True;
  595. end;
  596. end;
  597. A_SUB:
  598. begin
  599. if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
  600. GetNextInstruction(p, hp1) and
  601. MatchInstruction(hp1,A_SBC) then
  602. begin
  603. DebugMsg('Peephole SubSbc2Sub performed', p);
  604. taicpu(hp1).opcode:=A_SUB;
  605. RemoveCurrentP(p, hp1);
  606. Result := True;
  607. end;
  608. end;
  609. A_CLR:
  610. begin
  611. { turn the common
  612. clr rX
  613. mov/ld rX, rY
  614. into
  615. mov/ld rX, rY
  616. }
  617. if (taicpu(p).ops=1) and
  618. (taicpu(p).oper[0]^.typ=top_reg) and
  619. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  620. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  621. (hp1.typ=ait_instruction) and
  622. (taicpu(hp1).opcode in [A_MOV,A_LD]) and
  623. (taicpu(hp1).ops>0) and
  624. (taicpu(hp1).oper[0]^.typ=top_reg) and
  625. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
  626. begin
  627. DebugMsg('Peephole ClrMov2Mov performed', p);
  628. result:=RemoveCurrentP(p);
  629. end
  630. { turn
  631. clr rX
  632. ...
  633. adc rY, rX
  634. into
  635. ...
  636. adc rY, r1
  637. }
  638. else if (taicpu(p).ops=1) and
  639. (taicpu(p).oper[0]^.typ=top_reg) and
  640. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  641. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  642. (hp1.typ=ait_instruction) and
  643. (taicpu(hp1).opcode in [A_ADC,A_SBC]) and
  644. (taicpu(hp1).ops=2) and
  645. (taicpu(hp1).oper[1]^.typ=top_reg) and
  646. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  647. (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and
  648. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  649. begin
  650. DebugMsg('Peephole ClrAdc2Adc performed', p);
  651. taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg;
  652. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  653. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  654. if assigned(alloc) and assigned(dealloc) then
  655. begin
  656. asml.Remove(alloc);
  657. alloc.Free;
  658. asml.Remove(dealloc);
  659. dealloc.Free;
  660. end;
  661. result:=RemoveCurrentP(p);
  662. end;
  663. end;
  664. A_PUSH:
  665. begin
  666. { turn
  667. push reg0
  668. push reg1
  669. pop reg3
  670. pop reg2
  671. into
  672. movw reg2,reg0
  673. or
  674. mov reg3,reg1
  675. mov reg2,reg0
  676. }
  677. if GetNextInstruction(p,hp1) and
  678. MatchInstruction(hp1,A_PUSH) and
  679. GetNextInstruction(hp1,hp2) and
  680. MatchInstruction(hp2,A_POP) and
  681. GetNextInstruction(hp2,hp3) and
  682. MatchInstruction(hp3,A_POP) then
  683. begin
  684. if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  685. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  686. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  687. (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and
  688. ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then
  689. begin
  690. DebugMsg('Peephole PushPushPopPop2Movw performed', p);
  691. taicpu(hp3).ops:=2;
  692. taicpu(hp3).opcode:=A_MOVW;
  693. taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg);
  694. { We're removing 3 concurrent instructions. Remove hp1
  695. and hp2 manually instead of calling RemoveCurrentP
  696. as this means we won't be calling UpdateUsedRegs 3 times }
  697. asml.Remove(hp1);
  698. hp1.Free;
  699. asml.Remove(hp2);
  700. hp2.Free;
  701. { By removing p last, we've guaranteed that p.Next is
  702. valid (storing it prior to removing the instructions
  703. may result in a dangling pointer if hp1 immediately
  704. follows p), and because hp1, hp2 and hp3 came from
  705. sequential calls to GetNextInstruction, it is
  706. guaranteed that UpdateUsedRegs will stop at hp3. [Kit] }
  707. RemoveCurrentP(p, hp3);
  708. Result := True;
  709. end
  710. else
  711. begin
  712. DebugMsg('Peephole PushPushPopPop2MovMov performed', p);
  713. taicpu(p).ops:=2;
  714. taicpu(p).opcode:=A_MOV;
  715. taicpu(hp1).ops:=2;
  716. taicpu(hp1).opcode:=A_MOV;
  717. taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
  718. taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg);
  719. taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg);
  720. taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg);
  721. { life range of reg2 and reg3 is increased, fix register allocation entries }
  722. TransferUsedRegs(TmpUsedRegs);
  723. UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
  724. AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs);
  725. TransferUsedRegs(TmpUsedRegs);
  726. AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs);
  727. IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs);
  728. UpdateUsedRegs(tai(p.Next));
  729. asml.Remove(hp2);
  730. hp2.Free;
  731. asml.Remove(hp3);
  732. hp3.Free;
  733. result:=true;
  734. end
  735. end;
  736. end;
  737. A_CALL:
  738. if (cs_opt_level4 in current_settings.optimizerswitches) and
  739. GetNextInstruction(p,hp1) and
  740. MatchInstruction(hp1,A_RET) then
  741. begin
  742. DebugMsg('Peephole CallReg2Jmp performed', p);
  743. taicpu(p).opcode:=A_JMP;
  744. asml.Remove(hp1);
  745. hp1.Free;
  746. result:=true;
  747. end;
  748. A_RCALL:
  749. if (cs_opt_level4 in current_settings.optimizerswitches) and
  750. GetNextInstruction(p,hp1) and
  751. MatchInstruction(hp1,A_RET) then
  752. begin
  753. DebugMsg('Peephole RCallReg2RJmp performed', p);
  754. taicpu(p).opcode:=A_RJMP;
  755. asml.Remove(hp1);
  756. hp1.Free;
  757. result:=true;
  758. end;
  759. A_MOV:
  760. begin
  761. { change
  762. mov reg0, reg1
  763. dealloc reg0
  764. into
  765. dealloc reg0
  766. }
  767. if MatchOpType(taicpu(p),top_reg,top_reg) then
  768. begin
  769. TransferUsedRegs(TmpUsedRegs);
  770. UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
  771. if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and
  772. { reg. allocation information before calls is not perfect, so don't do this before
  773. calls/icalls }
  774. GetNextInstruction(p,hp1) and
  775. not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then
  776. begin
  777. DebugMsg('Peephole Mov2Nop performed', p);
  778. RemoveCurrentP(p, hp1);
  779. Result := True;
  780. exit;
  781. end;
  782. end;
  783. { turn
  784. mov reg0, reg1
  785. <op> reg2,reg0
  786. dealloc reg0
  787. into
  788. <op> reg2,reg1
  789. }
  790. if MatchOpType(taicpu(p),top_reg,top_reg) and
  791. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  792. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
  793. (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
  794. A_OUT,A_IN]) or
  795. { the reference register of ST/STD cannot be replaced }
  796. (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
  797. (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
  798. {(taicpu(hp1).ops=1) and
  799. (taicpu(hp1).oper[0]^.typ = top_reg) and
  800. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and }
  801. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  802. begin
  803. DebugMsg('Peephole MovOp2Op performed', p);
  804. for i := 0 to taicpu(hp1).ops-1 do
  805. if taicpu(hp1).oper[i]^.typ=top_reg then
  806. if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
  807. taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
  808. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  809. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  810. if assigned(alloc) and assigned(dealloc) then
  811. begin
  812. asml.Remove(alloc);
  813. alloc.Free;
  814. asml.Remove(dealloc);
  815. dealloc.Free;
  816. end;
  817. { life range of reg1 is increased }
  818. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
  819. { p will be removed, update used register as we continue
  820. with the next instruction after p }
  821. result:=RemoveCurrentP(p);
  822. end
  823. { remove
  824. mov reg0,reg0
  825. }
  826. else if (taicpu(p).ops=2) and
  827. (taicpu(p).oper[0]^.typ = top_reg) and
  828. (taicpu(p).oper[1]^.typ = top_reg) and
  829. (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
  830. begin
  831. DebugMsg('Peephole RedundantMov performed', p);
  832. result:=RemoveCurrentP(p);
  833. end
  834. {
  835. Turn
  836. mov rx,ry
  837. op rx,rz
  838. mov ry, rx
  839. Into
  840. op ry,rz
  841. }
  842. else if (taicpu(p).ops=2) and
  843. MatchOpType(taicpu(p),top_reg,top_reg) and
  844. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  845. (hp1.typ=ait_instruction) and
  846. (taicpu(hp1).ops >= 1) and
  847. (taicpu(hp1).oper[0]^.typ = top_reg) and
  848. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  849. MatchInstruction(hp2,A_MOV) and
  850. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  851. (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and
  852. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  853. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  854. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and
  855. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR,
  856. A_INC,A_DEC,
  857. A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and
  858. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  859. begin
  860. DebugMsg('Peephole MovOpMov2Op performed', p);
  861. if (taicpu(hp1).ops=2) and
  862. (taicpu(hp1).oper[1]^.typ=top_reg) and
  863. (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then
  864. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  865. taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg;
  866. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  867. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  868. if assigned(alloc) and assigned(dealloc) then
  869. begin
  870. asml.Remove(alloc);
  871. alloc.Free;
  872. asml.Remove(dealloc);
  873. dealloc.Free;
  874. end;
  875. asml.remove(hp2);
  876. hp2.free;
  877. result:=RemoveCurrentP(p);
  878. end
  879. {
  880. Turn
  881. mov rx,ry
  882. op rx,rw
  883. mov rw,rx
  884. Into
  885. op rw,ry
  886. }
  887. else if (taicpu(p).ops=2) and
  888. MatchOpType(taicpu(p),top_reg,top_reg) and
  889. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  890. (hp1.typ=ait_instruction) and
  891. (taicpu(hp1).ops = 2) and
  892. MatchOpType(taicpu(hp1),top_reg,top_reg) and
  893. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  894. (hp2.typ=ait_instruction) and
  895. (taicpu(hp2).opcode=A_MOV) and
  896. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  897. (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
  898. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  899. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  900. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and
  901. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and
  902. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  903. begin
  904. DebugMsg('Peephole MovOpMov2Op2 performed', p);
  905. taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  906. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  907. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  908. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  909. if assigned(alloc) and assigned(dealloc) then
  910. begin
  911. asml.Remove(alloc);
  912. alloc.Free;
  913. asml.Remove(dealloc);
  914. dealloc.Free;
  915. end;
  916. result:=RemoveCurrentP(p);
  917. asml.remove(hp2);
  918. hp2.free;
  919. end
  920. { fold
  921. mov reg2,reg0
  922. mov reg3,reg1
  923. to
  924. movw reg2,reg0
  925. }
  926. else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  927. (taicpu(p).ops=2) and
  928. (taicpu(p).oper[0]^.typ = top_reg) and
  929. (taicpu(p).oper[1]^.typ = top_reg) and
  930. getnextinstruction(p,hp1) and
  931. (hp1.typ = ait_instruction) and
  932. (taicpu(hp1).opcode = A_MOV) and
  933. (taicpu(hp1).ops=2) and
  934. (taicpu(hp1).oper[0]^.typ = top_reg) and
  935. (taicpu(hp1).oper[1]^.typ = top_reg) and
  936. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  937. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  938. ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
  939. (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
  940. begin
  941. DebugMsg('Peephole MovMov2Movw performed', p);
  942. alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
  943. if assigned(alloc) then
  944. begin
  945. asml.Remove(alloc);
  946. asml.InsertBefore(alloc,p);
  947. { proper book keeping of currently used registers }
  948. IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs);
  949. end;
  950. taicpu(p).opcode:=A_MOVW;
  951. asml.remove(hp1);
  952. hp1.free;
  953. result:=true;
  954. end
  955. {
  956. This removes the first mov from
  957. mov rX,...
  958. mov rX,...
  959. }
  960. else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and
  961. { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight }
  962. MatchInstruction(hp1,A_MOV) and
  963. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then
  964. while MatchInstruction(hp1,A_MOV) and
  965. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  966. { don't remove the first mov if the second is a mov rX,rX }
  967. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
  968. begin
  969. DebugMsg('Peephole MovMov2Mov 1 performed', p);
  970. RemoveCurrentP(p,hp1);
  971. Result := True;
  972. GetNextInstruction(hp1,hp1);
  973. if not assigned(hp1) then
  974. break;
  975. end
  976. {
  977. This removes the second mov from
  978. mov rX,rY
  979. ...
  980. mov rX,rY
  981. if rX and rY are not modified in-between
  982. }
  983. else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and
  984. MatchInstruction(hp1,A_MOV) and
  985. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  986. MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and
  987. not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then
  988. begin
  989. DebugMsg('Peephole MovMov2Mov 2 performed', p);
  990. AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs);
  991. RemoveInstruction(hp1);
  992. Result := True;
  993. end;
  994. end;
  995. A_SBIC,
  996. A_SBIS:
  997. begin
  998. {
  999. Turn
  1000. sbic/sbis X, y
  1001. jmp .L1
  1002. op
  1003. .L1:
  1004. into
  1005. sbis/sbic X,y
  1006. op
  1007. .L1:
  1008. }
  1009. if InvertSkipInstruction(p) then
  1010. result:=true
  1011. {
  1012. Turn
  1013. sbiX X, y
  1014. jmp .L1
  1015. jmp .L2
  1016. .L1:
  1017. op
  1018. .L2:
  1019. into
  1020. sbiX X,y
  1021. .L1:
  1022. op
  1023. .L2:
  1024. }
  1025. else if GetNextInstruction(p, hp1) and
  1026. (hp1.typ=ait_instruction) and
  1027. (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
  1028. (taicpu(hp1).ops>0) and
  1029. (taicpu(hp1).oper[0]^.typ = top_ref) and
  1030. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  1031. GetNextInstruction(hp1, hp2) and
  1032. (hp2.typ=ait_instruction) and
  1033. (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and
  1034. (taicpu(hp2).ops>0) and
  1035. (taicpu(hp2).oper[0]^.typ = top_ref) and
  1036. (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and
  1037. GetNextInstruction(hp2, hp3) and
  1038. (hp3.typ=ait_label) and
  1039. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and
  1040. GetNextInstruction(hp3, hp4) and
  1041. (hp4.typ=ait_instruction) and
  1042. GetNextInstruction(hp4, hp5) and
  1043. (hp3.typ=ait_label) and
  1044. (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then
  1045. begin
  1046. DebugMsg('Peephole SbiJmpJmp2Sbi performed',p);
  1047. tai_label(hp3).labsym.decrefs;
  1048. tai_label(hp5).labsym.decrefs;
  1049. AsmL.remove(hp1);
  1050. taicpu(hp1).Free;
  1051. AsmL.remove(hp2);
  1052. taicpu(hp2).Free;
  1053. result:=true;
  1054. end;
  1055. end;
  1056. end;
  1057. end;
  1058. end;
  1059. end;
  1060. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  1061. begin
  1062. end;
  1063. begin
  1064. casmoptimizer:=TCpuAsmOptimizer;
  1065. End.