aoptcpu.pas 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  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. 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. end;
  382. A_LDS:
  383. if (taicpu(p).oper[1]^.ref^.symbol=nil) and
  384. (taicpu(p).oper[1]^.ref^.relsymbol=nil) and
  385. (getsupreg(taicpu(p).oper[1]^.ref^.base)=RS_NO) and
  386. (getsupreg(taicpu(p).oper[1]^.ref^.index)=RS_NO) and
  387. (taicpu(p).oper[1]^.ref^.addressmode=AM_UNCHANGED) and
  388. (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  389. (taicpu(p).oper[1]^.ref^.offset>=0) and
  390. (taicpu(p).oper[1]^.ref^.offset<=63)) or
  391. (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  392. (taicpu(p).oper[1]^.ref^.offset>=32) and
  393. (taicpu(p).oper[1]^.ref^.offset<=95))) then
  394. begin
  395. DebugMsg('Peephole Lds2In performed', p);
  396. taicpu(p).opcode:=A_IN;
  397. if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
  398. taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset)
  399. else
  400. taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset-32);
  401. end;
  402. A_IN:
  403. if GetNextInstruction(p,hp1) then
  404. begin
  405. {
  406. in rX,Y
  407. ori rX,n
  408. out Y,rX
  409. into
  410. sbi rX,lg(n)
  411. }
  412. if (taicpu(p).oper[1]^.val<=31) and
  413. MatchInstruction(hp1,A_ORI) and
  414. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  415. (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
  416. GetNextInstruction(hp1,hp2) and
  417. MatchInstruction(hp2,A_OUT) and
  418. MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
  419. MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
  420. begin
  421. DebugMsg('Peephole InOriOut2Sbi performed', p);
  422. taicpu(p).opcode:=A_SBI;
  423. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  424. taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
  425. asml.Remove(hp1);
  426. hp1.Free;
  427. asml.Remove(hp2);
  428. hp2.Free;
  429. result:=true;
  430. end
  431. {
  432. in rX,Y
  433. andi rX,not(n)
  434. out Y,rX
  435. into
  436. cbi rX,lg(n)
  437. }
  438. else if (taicpu(p).oper[1]^.val<=31) and
  439. MatchInstruction(hp1,A_ANDI) and
  440. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  441. (PopCnt(byte(not(taicpu(hp1).oper[1]^.val)))=1) and
  442. GetNextInstruction(hp1,hp2) and
  443. MatchInstruction(hp2,A_OUT) and
  444. MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
  445. MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
  446. begin
  447. DebugMsg('Peephole InAndiOut2Cbi performed', p);
  448. taicpu(p).opcode:=A_CBI;
  449. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  450. taicpu(p).loadconst(1,BsrByte(not(taicpu(hp1).oper[1]^.val)));
  451. asml.Remove(hp1);
  452. hp1.Free;
  453. asml.Remove(hp2);
  454. hp2.Free;
  455. result:=true;
  456. end
  457. {
  458. in rX,Y
  459. andi rX,n
  460. breq/brne L1
  461. into
  462. sbis/sbic Y,lg(n)
  463. jmp L1
  464. .Ltemp:
  465. }
  466. else if (taicpu(p).oper[1]^.val<=31) and
  467. MatchInstruction(hp1,A_ANDI) and
  468. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  469. (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
  470. GetNextInstruction(hp1,hp2) and
  471. MatchInstruction(hp2,A_BRxx) and
  472. (taicpu(hp2).condition in [C_EQ,C_NE]) then
  473. begin
  474. if taicpu(hp2).condition=C_EQ then
  475. taicpu(p).opcode:=A_SBIS
  476. else
  477. taicpu(p).opcode:=A_SBIC;
  478. DebugMsg('Peephole InAndiBrx2SbixJmp performed', p);
  479. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  480. taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
  481. asml.Remove(hp1);
  482. hp1.Free;
  483. taicpu(hp2).condition:=C_None;
  484. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  485. taicpu(hp2).opcode:=A_JMP
  486. else
  487. taicpu(hp2).opcode:=A_RJMP;
  488. current_asmdata.getjumplabel(l);
  489. l.increfs;
  490. asml.InsertAfter(tai_label.create(l), hp2);
  491. result:=true;
  492. end;
  493. end;
  494. A_SBRS,
  495. A_SBRC:
  496. begin
  497. {
  498. Turn
  499. in rx, y
  500. sbr* rx, z
  501. Into
  502. sbi* y, z
  503. }
  504. if (taicpu(p).ops=2) and
  505. (taicpu(p).oper[0]^.typ=top_reg) and
  506. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  507. GetLastInstruction(p,hp1) and
  508. (hp1.typ=ait_instruction) and
  509. (taicpu(hp1).opcode=A_IN) and
  510. (taicpu(hp1).ops=2) and
  511. (taicpu(hp1).oper[1]^.typ=top_const) and
  512. (taicpu(hp1).oper[1]^.val in [0..31]) and
  513. MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^.reg) and
  514. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, hp1, p)) then
  515. begin
  516. if taicpu(p).opcode=A_SBRS then
  517. taicpu(p).opcode:=A_SBIS
  518. else
  519. taicpu(p).opcode:=A_SBIC;
  520. taicpu(p).loadconst(0, taicpu(hp1).oper[1]^.val);
  521. DebugMsg('Peephole InSbrx2Sbix performed', p);
  522. asml.Remove(hp1);
  523. hp1.free;
  524. result:=true;
  525. end;
  526. if InvertSkipInstruction(p) then
  527. result:=true;
  528. end;
  529. A_ANDI:
  530. begin
  531. {
  532. Turn
  533. andi rx, #pow2
  534. brne l
  535. <op>
  536. l:
  537. Into
  538. sbrs rx, #(1 shl imm)
  539. <op>
  540. l:
  541. }
  542. if (taicpu(p).ops=2) and
  543. (taicpu(p).oper[1]^.typ=top_const) and
  544. ispowerof2(taicpu(p).oper[1]^.val,i) and
  545. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  546. GetNextInstruction(p,hp1) and
  547. (hp1.typ=ait_instruction) and
  548. (taicpu(hp1).opcode=A_BRxx) and
  549. (taicpu(hp1).condition in [C_EQ,C_NE]) and
  550. (taicpu(hp1).ops>0) and
  551. (taicpu(hp1).oper[0]^.typ = top_ref) and
  552. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  553. GetNextInstruction(hp1,hp2) and
  554. (hp2.typ=ait_instruction) and
  555. GetNextInstruction(hp2,hp3) and
  556. (hp3.typ=ait_label) and
  557. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then
  558. begin
  559. DebugMsg('Peephole AndiBr2Sbr performed', p);
  560. taicpu(p).oper[1]^.val:=i;
  561. if taicpu(hp1).condition=C_NE then
  562. taicpu(p).opcode:=A_SBRS
  563. else
  564. taicpu(p).opcode:=A_SBRC;
  565. asml.Remove(hp1);
  566. hp1.free;
  567. result:=true;
  568. end
  569. {
  570. Remove
  571. andi rx, #y
  572. dealloc rx
  573. }
  574. else if (taicpu(p).ops=2) and
  575. (taicpu(p).oper[0]^.typ=top_reg) and
  576. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  577. (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or
  578. (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then
  579. begin
  580. DebugMsg('Redundant Andi removed', p);
  581. result:=RemoveCurrentP(p);
  582. end;
  583. end;
  584. A_ADD:
  585. begin
  586. if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
  587. GetNextInstruction(p, hp1) and
  588. MatchInstruction(hp1,A_ADC) then
  589. begin
  590. DebugMsg('Peephole AddAdc2Add performed', p);
  591. RemoveCurrentP(p, hp1);
  592. Result := True;
  593. end;
  594. end;
  595. A_SUB:
  596. begin
  597. if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
  598. GetNextInstruction(p, hp1) and
  599. MatchInstruction(hp1,A_SBC) then
  600. begin
  601. DebugMsg('Peephole SubSbc2Sub performed', p);
  602. taicpu(hp1).opcode:=A_SUB;
  603. RemoveCurrentP(p, hp1);
  604. Result := True;
  605. end;
  606. end;
  607. A_CLR:
  608. begin
  609. { turn the common
  610. clr rX
  611. mov/ld rX, rY
  612. into
  613. mov/ld rX, rY
  614. }
  615. if (taicpu(p).ops=1) and
  616. (taicpu(p).oper[0]^.typ=top_reg) and
  617. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  618. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  619. (hp1.typ=ait_instruction) and
  620. (taicpu(hp1).opcode in [A_MOV,A_LD]) and
  621. (taicpu(hp1).ops>0) and
  622. (taicpu(hp1).oper[0]^.typ=top_reg) and
  623. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
  624. begin
  625. DebugMsg('Peephole ClrMov2Mov performed', p);
  626. result:=RemoveCurrentP(p);
  627. end
  628. { turn
  629. clr rX
  630. ...
  631. adc rY, rX
  632. into
  633. ...
  634. adc rY, r1
  635. }
  636. else if (taicpu(p).ops=1) and
  637. (taicpu(p).oper[0]^.typ=top_reg) and
  638. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  639. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  640. (hp1.typ=ait_instruction) and
  641. (taicpu(hp1).opcode in [A_ADC,A_SBC]) and
  642. (taicpu(hp1).ops=2) and
  643. (taicpu(hp1).oper[1]^.typ=top_reg) and
  644. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  645. (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and
  646. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  647. begin
  648. DebugMsg('Peephole ClrAdc2Adc performed', p);
  649. taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg;
  650. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  651. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  652. if assigned(alloc) and assigned(dealloc) then
  653. begin
  654. asml.Remove(alloc);
  655. alloc.Free;
  656. asml.Remove(dealloc);
  657. dealloc.Free;
  658. end;
  659. result:=RemoveCurrentP(p);
  660. end;
  661. end;
  662. A_PUSH:
  663. begin
  664. { turn
  665. push reg0
  666. push reg1
  667. pop reg3
  668. pop reg2
  669. into
  670. movw reg2,reg0
  671. or
  672. mov reg3,reg1
  673. mov reg2,reg0
  674. }
  675. if GetNextInstruction(p,hp1) and
  676. MatchInstruction(hp1,A_PUSH) and
  677. GetNextInstruction(hp1,hp2) and
  678. MatchInstruction(hp2,A_POP) and
  679. GetNextInstruction(hp2,hp3) and
  680. MatchInstruction(hp3,A_POP) then
  681. begin
  682. if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  683. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  684. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  685. (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and
  686. ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then
  687. begin
  688. DebugMsg('Peephole PushPushPopPop2Movw performed', p);
  689. taicpu(hp3).ops:=2;
  690. taicpu(hp3).opcode:=A_MOVW;
  691. taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg);
  692. { We're removing 3 concurrent instructions. Remove hp1
  693. and hp2 manually instead of calling RemoveCurrentP
  694. as this means we won't be calling UpdateUsedRegs 3 times }
  695. asml.Remove(hp1);
  696. hp1.Free;
  697. asml.Remove(hp2);
  698. hp2.Free;
  699. { By removing p last, we've guaranteed that p.Next is
  700. valid (storing it prior to removing the instructions
  701. may result in a dangling pointer if hp1 immediately
  702. follows p), and because hp1, hp2 and hp3 came from
  703. sequential calls to GetNextInstruction, it is
  704. guaranteed that UpdateUsedRegs will stop at hp3. [Kit] }
  705. RemoveCurrentP(p, hp3);
  706. Result := True;
  707. end
  708. else
  709. begin
  710. DebugMsg('Peephole PushPushPopPop2MovMov performed', p);
  711. taicpu(p).ops:=2;
  712. taicpu(p).opcode:=A_MOV;
  713. taicpu(hp1).ops:=2;
  714. taicpu(hp1).opcode:=A_MOV;
  715. taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
  716. taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg);
  717. taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg);
  718. taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg);
  719. { life range of reg2 and reg3 is increased, fix register allocation entries }
  720. TransferUsedRegs(TmpUsedRegs);
  721. UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
  722. AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs);
  723. TransferUsedRegs(TmpUsedRegs);
  724. AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs);
  725. IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs);
  726. UpdateUsedRegs(tai(p.Next));
  727. asml.Remove(hp2);
  728. hp2.Free;
  729. asml.Remove(hp3);
  730. hp3.Free;
  731. result:=true;
  732. end
  733. end;
  734. end;
  735. A_CALL:
  736. if (cs_opt_level4 in current_settings.optimizerswitches) and
  737. GetNextInstruction(p,hp1) and
  738. MatchInstruction(hp1,A_RET) then
  739. begin
  740. DebugMsg('Peephole CallReg2Jmp performed', p);
  741. taicpu(p).opcode:=A_JMP;
  742. asml.Remove(hp1);
  743. hp1.Free;
  744. result:=true;
  745. end;
  746. A_RCALL:
  747. if (cs_opt_level4 in current_settings.optimizerswitches) and
  748. GetNextInstruction(p,hp1) and
  749. MatchInstruction(hp1,A_RET) then
  750. begin
  751. DebugMsg('Peephole RCallReg2RJmp performed', p);
  752. taicpu(p).opcode:=A_RJMP;
  753. asml.Remove(hp1);
  754. hp1.Free;
  755. result:=true;
  756. end;
  757. A_MOV:
  758. begin
  759. { change
  760. mov reg0, reg1
  761. dealloc reg0
  762. into
  763. dealloc reg0
  764. }
  765. if MatchOpType(taicpu(p),top_reg,top_reg) then
  766. begin
  767. TransferUsedRegs(TmpUsedRegs);
  768. UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
  769. if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and
  770. { reg. allocation information before calls is not perfect, so don't do this before
  771. calls/icalls }
  772. GetNextInstruction(p,hp1) and
  773. not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then
  774. begin
  775. DebugMsg('Peephole Mov2Nop performed', p);
  776. RemoveCurrentP(p, hp1);
  777. Result := True;
  778. exit;
  779. end;
  780. end;
  781. { turn
  782. mov reg0, reg1
  783. <op> reg2,reg0
  784. dealloc reg0
  785. into
  786. <op> reg2,reg1
  787. }
  788. if MatchOpType(taicpu(p),top_reg,top_reg) and
  789. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  790. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
  791. (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
  792. A_OUT,A_IN]) or
  793. { the reference register of ST/STD cannot be replaced }
  794. (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
  795. (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
  796. {(taicpu(hp1).ops=1) and
  797. (taicpu(hp1).oper[0]^.typ = top_reg) and
  798. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and }
  799. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  800. begin
  801. DebugMsg('Peephole MovOp2Op performed', p);
  802. for i := 0 to taicpu(hp1).ops-1 do
  803. if taicpu(hp1).oper[i]^.typ=top_reg then
  804. if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
  805. taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
  806. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  807. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  808. if assigned(alloc) and assigned(dealloc) then
  809. begin
  810. asml.Remove(alloc);
  811. alloc.Free;
  812. asml.Remove(dealloc);
  813. dealloc.Free;
  814. end;
  815. { life range of reg1 is increased }
  816. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
  817. { p will be removed, update used register as we continue
  818. with the next instruction after p }
  819. result:=RemoveCurrentP(p);
  820. end
  821. { remove
  822. mov reg0,reg0
  823. }
  824. else if (taicpu(p).ops=2) and
  825. (taicpu(p).oper[0]^.typ = top_reg) and
  826. (taicpu(p).oper[1]^.typ = top_reg) and
  827. (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
  828. begin
  829. DebugMsg('Peephole RedundantMov performed', p);
  830. result:=RemoveCurrentP(p);
  831. end
  832. {
  833. Turn
  834. mov rx,ry
  835. op rx,rz
  836. mov ry, rx
  837. Into
  838. op ry,rz
  839. }
  840. else if (taicpu(p).ops=2) and
  841. MatchOpType(taicpu(p),top_reg,top_reg) and
  842. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  843. (hp1.typ=ait_instruction) and
  844. (taicpu(hp1).ops >= 1) and
  845. (taicpu(hp1).oper[0]^.typ = top_reg) and
  846. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  847. MatchInstruction(hp2,A_MOV) and
  848. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  849. (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and
  850. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  851. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  852. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and
  853. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR,
  854. A_INC,A_DEC,
  855. A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and
  856. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  857. begin
  858. DebugMsg('Peephole MovOpMov2Op performed', p);
  859. if (taicpu(hp1).ops=2) and
  860. (taicpu(hp1).oper[1]^.typ=top_reg) and
  861. (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then
  862. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  863. taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg;
  864. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  865. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  866. if assigned(alloc) and assigned(dealloc) then
  867. begin
  868. asml.Remove(alloc);
  869. alloc.Free;
  870. asml.Remove(dealloc);
  871. dealloc.Free;
  872. end;
  873. asml.remove(hp2);
  874. hp2.free;
  875. result:=RemoveCurrentP(p);
  876. end
  877. {
  878. Turn
  879. mov rx,ry
  880. op rx,rw
  881. mov rw,rx
  882. Into
  883. op rw,ry
  884. }
  885. else if (taicpu(p).ops=2) and
  886. MatchOpType(taicpu(p),top_reg,top_reg) and
  887. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  888. (hp1.typ=ait_instruction) and
  889. (taicpu(hp1).ops = 2) and
  890. MatchOpType(taicpu(hp1),top_reg,top_reg) and
  891. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  892. (hp2.typ=ait_instruction) and
  893. (taicpu(hp2).opcode=A_MOV) and
  894. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  895. (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
  896. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  897. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  898. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and
  899. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and
  900. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  901. begin
  902. DebugMsg('Peephole MovOpMov2Op2 performed', p);
  903. taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  904. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  905. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  906. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  907. if assigned(alloc) and assigned(dealloc) then
  908. begin
  909. asml.Remove(alloc);
  910. alloc.Free;
  911. asml.Remove(dealloc);
  912. dealloc.Free;
  913. end;
  914. result:=RemoveCurrentP(p);
  915. asml.remove(hp2);
  916. hp2.free;
  917. end
  918. { fold
  919. mov reg2,reg0
  920. mov reg3,reg1
  921. to
  922. movw reg2,reg0
  923. }
  924. else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  925. (taicpu(p).ops=2) and
  926. (taicpu(p).oper[0]^.typ = top_reg) and
  927. (taicpu(p).oper[1]^.typ = top_reg) and
  928. getnextinstruction(p,hp1) and
  929. (hp1.typ = ait_instruction) and
  930. (taicpu(hp1).opcode = A_MOV) and
  931. (taicpu(hp1).ops=2) and
  932. (taicpu(hp1).oper[0]^.typ = top_reg) and
  933. (taicpu(hp1).oper[1]^.typ = top_reg) and
  934. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  935. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  936. ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
  937. (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
  938. begin
  939. DebugMsg('Peephole MovMov2Movw performed', p);
  940. alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
  941. if assigned(alloc) then
  942. begin
  943. asml.Remove(alloc);
  944. asml.InsertBefore(alloc,p);
  945. { proper book keeping of currently used registers }
  946. IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs);
  947. end;
  948. taicpu(p).opcode:=A_MOVW;
  949. asml.remove(hp1);
  950. hp1.free;
  951. result:=true;
  952. end
  953. {
  954. This removes the first mov from
  955. mov rX,...
  956. mov rX,...
  957. }
  958. else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) then
  959. while MatchInstruction(hp1,A_MOV) and
  960. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  961. { don't remove the first mov if the second is a mov rX,rX }
  962. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
  963. begin
  964. DebugMsg('Peephole MovMov2Mov performed', p);
  965. RemoveCurrentP(p,hp1);
  966. Result := True;
  967. GetNextInstruction(hp1,hp1);
  968. if not assigned(hp1) then
  969. break;
  970. end;
  971. end;
  972. A_SBIC,
  973. A_SBIS:
  974. begin
  975. {
  976. Turn
  977. sbic/sbis X, y
  978. jmp .L1
  979. op
  980. .L1:
  981. into
  982. sbis/sbic X,y
  983. op
  984. .L1:
  985. }
  986. if InvertSkipInstruction(p) then
  987. result:=true
  988. {
  989. Turn
  990. sbiX X, y
  991. jmp .L1
  992. jmp .L2
  993. .L1:
  994. op
  995. .L2:
  996. into
  997. sbiX X,y
  998. .L1:
  999. op
  1000. .L2:
  1001. }
  1002. else if GetNextInstruction(p, hp1) and
  1003. (hp1.typ=ait_instruction) and
  1004. (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
  1005. (taicpu(hp1).ops>0) and
  1006. (taicpu(hp1).oper[0]^.typ = top_ref) and
  1007. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  1008. GetNextInstruction(hp1, hp2) and
  1009. (hp2.typ=ait_instruction) and
  1010. (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and
  1011. (taicpu(hp2).ops>0) and
  1012. (taicpu(hp2).oper[0]^.typ = top_ref) and
  1013. (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and
  1014. GetNextInstruction(hp2, hp3) and
  1015. (hp3.typ=ait_label) and
  1016. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and
  1017. GetNextInstruction(hp3, hp4) and
  1018. (hp4.typ=ait_instruction) and
  1019. GetNextInstruction(hp4, hp5) and
  1020. (hp3.typ=ait_label) and
  1021. (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then
  1022. begin
  1023. DebugMsg('Peephole SbiJmpJmp2Sbi performed',p);
  1024. tai_label(hp3).labsym.decrefs;
  1025. tai_label(hp5).labsym.decrefs;
  1026. AsmL.remove(hp1);
  1027. taicpu(hp1).Free;
  1028. AsmL.remove(hp2);
  1029. taicpu(hp2).Free;
  1030. result:=true;
  1031. end;
  1032. end;
  1033. end;
  1034. end;
  1035. end;
  1036. end;
  1037. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  1038. begin
  1039. end;
  1040. begin
  1041. casmoptimizer:=TCpuAsmOptimizer;
  1042. End.