aoptcpu.pas 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  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. begin
  208. result:=false;
  209. if GetNextInstruction(taicpu(p),hp1) and
  210. (hp1.typ=ait_instruction) and
  211. (taicpu(hp1).opcode in [A_RJMP,A_JMP]) and
  212. (taicpu(hp1).ops=1) and
  213. (taicpu(hp1).oper[0]^.typ=top_ref) and
  214. (taicpu(hp1).oper[0]^.ref^.offset=0) and
  215. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  216. GetNextInstructionWithoutLabel(hp1,hp2) and
  217. (hp2.typ=ait_instruction) and
  218. (not taicpu(hp2).is_jmp) and
  219. GetNextInstruction(hp2,hp3) and
  220. FindLabel(TAsmLabel(taicpu(hp1).oper[0]^.ref^.symbol),hp3) then
  221. begin
  222. DebugMsg('SkipJump2InvertedSkip', p);
  223. case taicpu(p).opcode of
  224. A_SBIS: taicpu(p).opcode:=A_SBIC;
  225. A_SBIC: taicpu(p).opcode:=A_SBIS;
  226. A_SBRS: taicpu(p).opcode:=A_SBRC;
  227. A_SBRC: taicpu(p).opcode:=A_SBRS;
  228. end;
  229. TAsmLabel(taicpu(hp1).oper[0]^.ref^.symbol).decrefs;
  230. asml.remove(hp1);
  231. hp1.free;
  232. end;
  233. end;
  234. function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  235. var
  236. hp1,hp2,hp3,hp4,hp5: tai;
  237. alloc, dealloc: tai_regalloc;
  238. i: integer;
  239. l: TAsmLabel;
  240. begin
  241. result := false;
  242. case p.typ of
  243. ait_instruction:
  244. begin
  245. {
  246. change
  247. <op> reg,x,y
  248. cp reg,r1
  249. into
  250. <op>s reg,x,y
  251. }
  252. { this optimization can applied only to the currently enabled operations because
  253. the other operations do not update all flags and FPC does not track flag usage }
  254. if MatchInstruction(p, [A_ADC,A_ADD,A_AND,A_ANDI,A_ASR,A_COM,A_DEC,A_EOR,
  255. A_INC,A_LSL,A_LSR,
  256. A_OR,A_ORI,A_ROL,A_ROR,A_SBC,A_SBCI,A_SUB,A_SUBI]) and
  257. GetNextInstruction(p, hp1) and
  258. ((MatchInstruction(hp1, A_CP) and
  259. (((taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg) and
  260. (taicpu(hp1).oper[1]^.reg = GetDefaultZeroReg)) or
  261. ((taicpu(p).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
  262. (taicpu(hp1).oper[0]^.reg = GetDefaultZeroReg) and
  263. (taicpu(p).opcode in [A_ADC,A_ADD,A_AND,A_ANDI,A_ASR,A_COM,A_EOR,
  264. A_LSL,A_LSR,
  265. A_OR,A_ORI,A_ROL,A_ROR,A_SUB,A_SBI])))) or
  266. (MatchInstruction(hp1, A_CPI) and
  267. (taicpu(p).opcode = A_ANDI) and
  268. (taicpu(p).oper[1]^.typ=top_const) and
  269. (taicpu(hp1).oper[1]^.typ=top_const) and
  270. (taicpu(p).oper[1]^.val=taicpu(hp1).oper[1]^.val))) and
  271. GetNextInstruction(hp1, hp2) and
  272. { be careful here, following instructions could use other flags
  273. however after a jump fpc never depends on the value of flags }
  274. { All above instructions set Z and N according to the following
  275. Z := result = 0;
  276. N := result[31];
  277. EQ = Z=1; NE = Z=0;
  278. MI = N=1; PL = N=0; }
  279. MatchInstruction(hp2, A_BRxx) and
  280. ((taicpu(hp2).condition in [C_EQ,C_NE,C_MI,C_PL]) or
  281. { sub/sbc set all flags }
  282. (taicpu(p).opcode in [A_SUB,A_SBI])){ and
  283. no flag allocation tracking implemented yet on avr
  284. assigned(FindRegDealloc(NR_DEFAULTFLAGS,tai(hp2.Next)))} then
  285. begin
  286. { move flag allocation if possible }
  287. { no flag allocation tracking implemented yet on avr
  288. GetLastInstruction(hp1, hp2);
  289. hp2:=FindRegAlloc(NR_DEFAULTFLAGS,tai(hp2.Next));
  290. if assigned(hp2) then
  291. begin
  292. asml.Remove(hp2);
  293. asml.insertbefore(hp2, p);
  294. end;
  295. }
  296. // If we compare to the same value we are masking then invert the comparison
  297. if (taicpu(hp1).opcode=A_CPI) or
  298. { sub/sbc with reverted? }
  299. ((taicpu(hp1).oper[0]^.reg = GetDefaultZeroReg) and (taicpu(p).opcode in [A_SUB,A_SBI])) then
  300. taicpu(hp2).condition:=inverse_cond(taicpu(hp2).condition);
  301. asml.InsertBefore(tai_regalloc.alloc(NR_DEFAULTFLAGS,p), p);
  302. asml.InsertAfter(tai_regalloc.dealloc(NR_DEFAULTFLAGS,hp2), hp2);
  303. IncludeRegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs);
  304. DebugMsg('Peephole OpCp2Op performed', p);
  305. asml.remove(hp1);
  306. hp1.free;
  307. Result:=true;
  308. end
  309. else
  310. case taicpu(p).opcode of
  311. A_LDI:
  312. begin
  313. { turn
  314. ldi reg0, imm
  315. <op> reg1, reg0
  316. dealloc reg0
  317. into
  318. <op>i reg1, imm
  319. }
  320. if MatchOpType(taicpu(p),top_reg,top_const) and
  321. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  322. MatchInstruction(hp1,[A_CP,A_MOV,A_AND,A_SUB],2) and
  323. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  324. MatchOpType(taicpu(hp1),top_reg,top_reg) and
  325. (getsupreg(taicpu(hp1).oper[0]^.reg) in [16..31]) and
  326. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  327. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) then
  328. begin
  329. TransferUsedRegs(TmpUsedRegs);
  330. UpdateUsedRegs(TmpUsedRegs,tai(p.next));
  331. UpdateUsedRegs(TmpUsedRegs,tai(hp1.next));
  332. if not(RegUsedAfterInstruction(taicpu(hp1).oper[1]^.reg, hp1, TmpUsedRegs)) then
  333. begin
  334. case taicpu(hp1).opcode of
  335. A_CP:
  336. taicpu(hp1).opcode:=A_CPI;
  337. A_MOV:
  338. taicpu(hp1).opcode:=A_LDI;
  339. A_AND:
  340. taicpu(hp1).opcode:=A_ANDI;
  341. A_SUB:
  342. taicpu(hp1).opcode:=A_SUBI;
  343. else
  344. internalerror(2016111901);
  345. end;
  346. taicpu(hp1).loadconst(1, taicpu(p).oper[1]^.val);
  347. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  348. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  349. if assigned(alloc) and assigned(dealloc) then
  350. begin
  351. asml.Remove(alloc);
  352. alloc.Free;
  353. asml.Remove(dealloc);
  354. dealloc.Free;
  355. end;
  356. DebugMsg('Peephole LdiOp2Opi performed', p);
  357. result:=RemoveCurrentP(p);
  358. end;
  359. end;
  360. end;
  361. A_STS:
  362. if (taicpu(p).oper[0]^.ref^.symbol=nil) and
  363. (taicpu(p).oper[0]^.ref^.relsymbol=nil) and
  364. (getsupreg(taicpu(p).oper[0]^.ref^.base)=RS_NO) and
  365. (getsupreg(taicpu(p).oper[0]^.ref^.index)=RS_NO) and
  366. (taicpu(p).oper[0]^.ref^.addressmode=AM_UNCHANGED) and
  367. (((CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  368. (taicpu(p).oper[0]^.ref^.offset>=0) and
  369. (taicpu(p).oper[0]^.ref^.offset<=63)) or
  370. (not(CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype]) and
  371. (taicpu(p).oper[0]^.ref^.offset>=32) and
  372. (taicpu(p).oper[0]^.ref^.offset<=95))) then
  373. begin
  374. DebugMsg('Peephole Sts2Out performed', p);
  375. taicpu(p).opcode:=A_OUT;
  376. if CPUAVR_NOMEMMAPPED_REGS in cpu_capabilities[current_settings.cputype] then
  377. taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset)
  378. else
  379. taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset-32);
  380. result:=true;
  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. result:=true;
  402. end;
  403. A_IN:
  404. if GetNextInstruction(p,hp1) then
  405. begin
  406. {
  407. in rX,Y
  408. ori rX,n
  409. out Y,rX
  410. into
  411. sbi rX,lg(n)
  412. }
  413. if (taicpu(p).oper[1]^.val<=31) and
  414. MatchInstruction(hp1,A_ORI) and
  415. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  416. (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
  417. GetNextInstruction(hp1,hp2) and
  418. MatchInstruction(hp2,A_OUT) and
  419. MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
  420. MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
  421. begin
  422. DebugMsg('Peephole InOriOut2Sbi performed', p);
  423. taicpu(p).opcode:=A_SBI;
  424. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  425. taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
  426. asml.Remove(hp1);
  427. hp1.Free;
  428. asml.Remove(hp2);
  429. hp2.Free;
  430. result:=true;
  431. end
  432. {
  433. in rX,Y
  434. andi rX,not(n)
  435. out Y,rX
  436. into
  437. cbi rX,lg(n)
  438. }
  439. else if (taicpu(p).oper[1]^.val<=31) and
  440. MatchInstruction(hp1,A_ANDI) and
  441. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  442. (PopCnt(byte(not(taicpu(hp1).oper[1]^.val)))=1) and
  443. GetNextInstruction(hp1,hp2) and
  444. MatchInstruction(hp2,A_OUT) and
  445. MatchOperand(taicpu(hp2).oper[1]^,taicpu(p).oper[0]^) and
  446. MatchOperand(taicpu(hp2).oper[0]^,taicpu(p).oper[1]^) then
  447. begin
  448. DebugMsg('Peephole InAndiOut2Cbi performed', p);
  449. taicpu(p).opcode:=A_CBI;
  450. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  451. taicpu(p).loadconst(1,BsrByte(not(taicpu(hp1).oper[1]^.val)));
  452. asml.Remove(hp1);
  453. hp1.Free;
  454. asml.Remove(hp2);
  455. hp2.Free;
  456. result:=true;
  457. end
  458. {
  459. in rX,Y
  460. andi rX,n
  461. breq/brne L1
  462. into
  463. sbis/sbic Y,lg(n)
  464. jmp L1
  465. .Ltemp:
  466. }
  467. else if (taicpu(p).oper[1]^.val<=31) and
  468. MatchInstruction(hp1,A_ANDI) and
  469. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  470. (PopCnt(byte(taicpu(hp1).oper[1]^.val))=1) and
  471. GetNextInstruction(hp1,hp2) and
  472. MatchInstruction(hp2,A_BRxx) and
  473. (taicpu(hp2).condition in [C_EQ,C_NE]) then
  474. begin
  475. if taicpu(hp2).condition=C_EQ then
  476. taicpu(p).opcode:=A_SBIS
  477. else
  478. taicpu(p).opcode:=A_SBIC;
  479. DebugMsg('Peephole InAndiBrx2SbixJmp performed', p);
  480. taicpu(p).loadconst(0,taicpu(p).oper[1]^.val);
  481. taicpu(p).loadconst(1,BsrByte(taicpu(hp1).oper[1]^.val));
  482. asml.Remove(hp1);
  483. hp1.Free;
  484. taicpu(hp2).condition:=C_None;
  485. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  486. taicpu(hp2).opcode:=A_JMP
  487. else
  488. taicpu(hp2).opcode:=A_RJMP;
  489. current_asmdata.getjumplabel(l);
  490. l.increfs;
  491. asml.InsertAfter(tai_label.create(l), hp2);
  492. result:=true;
  493. end;
  494. end;
  495. A_SBRS,
  496. A_SBRC:
  497. begin
  498. {
  499. Turn
  500. in rx, y
  501. sbr* rx, z
  502. Into
  503. sbi* y, z
  504. }
  505. if (taicpu(p).ops=2) and
  506. (taicpu(p).oper[0]^.typ=top_reg) and
  507. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  508. GetLastInstruction(p,hp1) and
  509. (hp1.typ=ait_instruction) and
  510. (taicpu(hp1).opcode=A_IN) and
  511. (taicpu(hp1).ops=2) and
  512. (taicpu(hp1).oper[1]^.typ=top_const) and
  513. (taicpu(hp1).oper[1]^.val in [0..31]) and
  514. MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^.reg) and
  515. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, hp1, p)) then
  516. begin
  517. if taicpu(p).opcode=A_SBRS then
  518. taicpu(p).opcode:=A_SBIS
  519. else
  520. taicpu(p).opcode:=A_SBIC;
  521. taicpu(p).loadconst(0, taicpu(hp1).oper[1]^.val);
  522. DebugMsg('Peephole InSbrx2Sbix performed', p);
  523. asml.Remove(hp1);
  524. hp1.free;
  525. result:=true;
  526. end;
  527. if InvertSkipInstruction(p) then
  528. result:=true;
  529. end;
  530. A_ANDI:
  531. begin
  532. {
  533. Turn
  534. andi rx, #pow2
  535. brne l
  536. <op>
  537. l:
  538. Into
  539. sbrs rx, #(1 shl imm)
  540. <op>
  541. l:
  542. }
  543. if (taicpu(p).ops=2) and
  544. (taicpu(p).oper[1]^.typ=top_const) and
  545. ispowerof2(taicpu(p).oper[1]^.val,i) and
  546. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  547. GetNextInstruction(p,hp1) and
  548. (hp1.typ=ait_instruction) and
  549. (taicpu(hp1).opcode=A_BRxx) and
  550. (taicpu(hp1).condition in [C_EQ,C_NE]) and
  551. (taicpu(hp1).ops>0) and
  552. (taicpu(hp1).oper[0]^.typ = top_ref) and
  553. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  554. GetNextInstruction(hp1,hp2) and
  555. (hp2.typ=ait_instruction) and
  556. GetNextInstruction(hp2,hp3) and
  557. (hp3.typ=ait_label) and
  558. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then
  559. begin
  560. DebugMsg('Peephole AndiBr2Sbr performed', p);
  561. taicpu(p).oper[1]^.val:=i;
  562. if taicpu(hp1).condition=C_NE then
  563. taicpu(p).opcode:=A_SBRS
  564. else
  565. taicpu(p).opcode:=A_SBRC;
  566. asml.Remove(hp1);
  567. hp1.free;
  568. result:=true;
  569. end
  570. {
  571. Remove
  572. andi rx, #y
  573. dealloc rx
  574. }
  575. else if (taicpu(p).ops=2) and
  576. (taicpu(p).oper[0]^.typ=top_reg) and
  577. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and
  578. (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or
  579. (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then
  580. begin
  581. DebugMsg('Redundant Andi removed', p);
  582. result:=RemoveCurrentP(p);
  583. end;
  584. end;
  585. A_ADD:
  586. begin
  587. if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
  588. GetNextInstruction(p, hp1) and
  589. MatchInstruction(hp1,A_ADC) then
  590. begin
  591. DebugMsg('Peephole AddAdc2Add performed', p);
  592. RemoveCurrentP(p, hp1);
  593. Result := True;
  594. end;
  595. end;
  596. A_SUB:
  597. begin
  598. if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and
  599. GetNextInstruction(p, hp1) and
  600. MatchInstruction(hp1,A_SBC) then
  601. begin
  602. DebugMsg('Peephole SubSbc2Sub performed', p);
  603. taicpu(hp1).opcode:=A_SUB;
  604. RemoveCurrentP(p, hp1);
  605. Result := True;
  606. end;
  607. end;
  608. A_CLR:
  609. begin
  610. { turn the common
  611. clr rX
  612. mov/ld rX, rY
  613. into
  614. mov/ld rX, rY
  615. }
  616. if (taicpu(p).ops=1) and
  617. (taicpu(p).oper[0]^.typ=top_reg) and
  618. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  619. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  620. (hp1.typ=ait_instruction) and
  621. (taicpu(hp1).opcode in [A_MOV,A_LD]) and
  622. (taicpu(hp1).ops>0) and
  623. (taicpu(hp1).oper[0]^.typ=top_reg) and
  624. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
  625. begin
  626. DebugMsg('Peephole ClrMov2Mov performed', p);
  627. result:=RemoveCurrentP(p);
  628. end
  629. { turn
  630. clr rX
  631. ...
  632. adc rY, rX
  633. into
  634. ...
  635. adc rY, r1
  636. }
  637. else if (taicpu(p).ops=1) and
  638. (taicpu(p).oper[0]^.typ=top_reg) and
  639. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  640. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  641. (hp1.typ=ait_instruction) and
  642. (taicpu(hp1).opcode in [A_ADC,A_SBC]) and
  643. (taicpu(hp1).ops=2) and
  644. (taicpu(hp1).oper[1]^.typ=top_reg) and
  645. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  646. (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and
  647. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  648. begin
  649. DebugMsg('Peephole ClrAdc2Adc performed', p);
  650. taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg;
  651. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  652. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  653. if assigned(alloc) and assigned(dealloc) then
  654. begin
  655. asml.Remove(alloc);
  656. alloc.Free;
  657. asml.Remove(dealloc);
  658. dealloc.Free;
  659. end;
  660. result:=RemoveCurrentP(p);
  661. end;
  662. end;
  663. A_PUSH:
  664. begin
  665. { turn
  666. push reg0
  667. push reg1
  668. pop reg3
  669. pop reg2
  670. into
  671. movw reg2,reg0
  672. or
  673. mov reg3,reg1
  674. mov reg2,reg0
  675. }
  676. if GetNextInstruction(p,hp1) and
  677. MatchInstruction(hp1,A_PUSH) and
  678. GetNextInstruction(hp1,hp2) and
  679. MatchInstruction(hp2,A_POP) and
  680. GetNextInstruction(hp2,hp3) and
  681. MatchInstruction(hp3,A_POP) then
  682. begin
  683. if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  684. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  685. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  686. (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and
  687. ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then
  688. begin
  689. DebugMsg('Peephole PushPushPopPop2Movw performed', p);
  690. taicpu(hp3).ops:=2;
  691. taicpu(hp3).opcode:=A_MOVW;
  692. taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg);
  693. { We're removing 3 concurrent instructions. Remove hp1
  694. and hp2 manually instead of calling RemoveCurrentP
  695. as this means we won't be calling UpdateUsedRegs 3 times }
  696. asml.Remove(hp1);
  697. hp1.Free;
  698. asml.Remove(hp2);
  699. hp2.Free;
  700. { By removing p last, we've guaranteed that p.Next is
  701. valid (storing it prior to removing the instructions
  702. may result in a dangling pointer if hp1 immediately
  703. follows p), and because hp1, hp2 and hp3 came from
  704. sequential calls to GetNextInstruction, it is
  705. guaranteed that UpdateUsedRegs will stop at hp3. [Kit] }
  706. RemoveCurrentP(p, hp3);
  707. Result := True;
  708. end
  709. else
  710. begin
  711. DebugMsg('Peephole PushPushPopPop2MovMov performed', p);
  712. taicpu(p).ops:=2;
  713. taicpu(p).opcode:=A_MOV;
  714. taicpu(hp1).ops:=2;
  715. taicpu(hp1).opcode:=A_MOV;
  716. taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
  717. taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg);
  718. taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg);
  719. taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg);
  720. { life range of reg2 and reg3 is increased, fix register allocation entries }
  721. TransferUsedRegs(TmpUsedRegs);
  722. UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
  723. AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs);
  724. TransferUsedRegs(TmpUsedRegs);
  725. AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs);
  726. IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs);
  727. UpdateUsedRegs(tai(p.Next));
  728. asml.Remove(hp2);
  729. hp2.Free;
  730. asml.Remove(hp3);
  731. hp3.Free;
  732. result:=true;
  733. end
  734. end;
  735. end;
  736. A_CALL:
  737. if (cs_opt_level4 in current_settings.optimizerswitches) and
  738. GetNextInstruction(p,hp1) and
  739. MatchInstruction(hp1,A_RET) then
  740. begin
  741. DebugMsg('Peephole CallReg2Jmp performed', p);
  742. taicpu(p).opcode:=A_JMP;
  743. asml.Remove(hp1);
  744. hp1.Free;
  745. result:=true;
  746. end;
  747. A_RCALL:
  748. if (cs_opt_level4 in current_settings.optimizerswitches) and
  749. GetNextInstruction(p,hp1) and
  750. MatchInstruction(hp1,A_RET) then
  751. begin
  752. DebugMsg('Peephole RCallReg2RJmp performed', p);
  753. taicpu(p).opcode:=A_RJMP;
  754. asml.Remove(hp1);
  755. hp1.Free;
  756. result:=true;
  757. end;
  758. A_MOV:
  759. begin
  760. { change
  761. mov reg0, reg1
  762. dealloc reg0
  763. into
  764. dealloc reg0
  765. }
  766. if MatchOpType(taicpu(p),top_reg,top_reg) then
  767. begin
  768. TransferUsedRegs(TmpUsedRegs);
  769. UpdateUsedRegs(TmpUsedRegs,tai(p.Next));
  770. if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and
  771. { reg. allocation information before calls is not perfect, so don't do this before
  772. calls/icalls }
  773. GetNextInstruction(p,hp1) and
  774. not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then
  775. begin
  776. DebugMsg('Peephole Mov2Nop performed', p);
  777. RemoveCurrentP(p, hp1);
  778. Result := True;
  779. exit;
  780. end;
  781. end;
  782. { turn
  783. mov reg0, reg1
  784. <op> reg2,reg0
  785. dealloc reg0
  786. into
  787. <op> reg2,reg1
  788. }
  789. if MatchOpType(taicpu(p),top_reg,top_reg) and
  790. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  791. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
  792. (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
  793. A_OUT,A_IN]) or
  794. { the reference register of ST/STD cannot be replaced }
  795. (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
  796. (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
  797. {(taicpu(hp1).ops=1) and
  798. (taicpu(hp1).oper[0]^.typ = top_reg) and
  799. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and }
  800. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  801. begin
  802. DebugMsg('Peephole MovOp2Op performed', p);
  803. for i := 0 to taicpu(hp1).ops-1 do
  804. if taicpu(hp1).oper[i]^.typ=top_reg then
  805. if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
  806. taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
  807. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  808. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  809. if assigned(alloc) and assigned(dealloc) then
  810. begin
  811. asml.Remove(alloc);
  812. alloc.Free;
  813. asml.Remove(dealloc);
  814. dealloc.Free;
  815. end;
  816. { life range of reg1 is increased }
  817. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
  818. { p will be removed, update used register as we continue
  819. with the next instruction after p }
  820. result:=RemoveCurrentP(p);
  821. end
  822. { remove
  823. mov reg0,reg0
  824. }
  825. else if (taicpu(p).ops=2) and
  826. (taicpu(p).oper[0]^.typ = top_reg) and
  827. (taicpu(p).oper[1]^.typ = top_reg) and
  828. (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
  829. begin
  830. DebugMsg('Peephole RedundantMov performed', p);
  831. result:=RemoveCurrentP(p);
  832. end
  833. {
  834. Turn
  835. mov rx,ry
  836. op rx,rz
  837. mov ry, rx
  838. Into
  839. op ry,rz
  840. }
  841. else if (taicpu(p).ops=2) and
  842. MatchOpType(taicpu(p),top_reg,top_reg) and
  843. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  844. (hp1.typ=ait_instruction) and
  845. (taicpu(hp1).ops >= 1) and
  846. (taicpu(hp1).oper[0]^.typ = top_reg) and
  847. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  848. MatchInstruction(hp2,A_MOV) and
  849. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  850. (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and
  851. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  852. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  853. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and
  854. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR,
  855. A_INC,A_DEC,
  856. A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and
  857. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  858. begin
  859. DebugMsg('Peephole MovOpMov2Op performed', p);
  860. if (taicpu(hp1).ops=2) and
  861. (taicpu(hp1).oper[1]^.typ=top_reg) and
  862. (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then
  863. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  864. taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg;
  865. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  866. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  867. if assigned(alloc) and assigned(dealloc) then
  868. begin
  869. asml.Remove(alloc);
  870. alloc.Free;
  871. asml.Remove(dealloc);
  872. dealloc.Free;
  873. end;
  874. asml.remove(hp2);
  875. hp2.free;
  876. result:=RemoveCurrentP(p);
  877. end
  878. {
  879. Turn
  880. mov rx,ry
  881. op rx,rw
  882. mov rw,rx
  883. Into
  884. op rw,ry
  885. }
  886. else if (taicpu(p).ops=2) and
  887. MatchOpType(taicpu(p),top_reg,top_reg) and
  888. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  889. (hp1.typ=ait_instruction) and
  890. (taicpu(hp1).ops = 2) and
  891. MatchOpType(taicpu(hp1),top_reg,top_reg) and
  892. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  893. (hp2.typ=ait_instruction) and
  894. (taicpu(hp2).opcode=A_MOV) and
  895. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  896. (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
  897. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  898. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  899. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and
  900. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and
  901. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  902. begin
  903. DebugMsg('Peephole MovOpMov2Op2 performed', p);
  904. taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  905. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  906. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  907. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  908. if assigned(alloc) and assigned(dealloc) then
  909. begin
  910. asml.Remove(alloc);
  911. alloc.Free;
  912. asml.Remove(dealloc);
  913. dealloc.Free;
  914. end;
  915. result:=RemoveCurrentP(p);
  916. asml.remove(hp2);
  917. hp2.free;
  918. end
  919. { fold
  920. mov reg2,reg0
  921. mov reg3,reg1
  922. to
  923. movw reg2,reg0
  924. }
  925. else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  926. (taicpu(p).ops=2) and
  927. (taicpu(p).oper[0]^.typ = top_reg) and
  928. (taicpu(p).oper[1]^.typ = top_reg) and
  929. getnextinstruction(p,hp1) and
  930. (hp1.typ = ait_instruction) and
  931. (taicpu(hp1).opcode = A_MOV) and
  932. (taicpu(hp1).ops=2) and
  933. (taicpu(hp1).oper[0]^.typ = top_reg) and
  934. (taicpu(hp1).oper[1]^.typ = top_reg) and
  935. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  936. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  937. ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
  938. (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
  939. begin
  940. DebugMsg('Peephole MovMov2Movw performed', p);
  941. alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
  942. if assigned(alloc) then
  943. begin
  944. asml.Remove(alloc);
  945. asml.InsertBefore(alloc,p);
  946. { proper book keeping of currently used registers }
  947. IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs);
  948. end;
  949. taicpu(p).opcode:=A_MOVW;
  950. asml.remove(hp1);
  951. hp1.free;
  952. result:=true;
  953. end
  954. {
  955. This removes the first mov from
  956. mov rX,...
  957. mov rX,...
  958. }
  959. else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and
  960. { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight }
  961. MatchInstruction(hp1,A_MOV) and
  962. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then
  963. while MatchInstruction(hp1,A_MOV) and
  964. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  965. { don't remove the first mov if the second is a mov rX,rX }
  966. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
  967. begin
  968. DebugMsg('Peephole MovMov2Mov 1 performed', p);
  969. RemoveCurrentP(p,hp1);
  970. Result := True;
  971. GetNextInstruction(hp1,hp1);
  972. if not assigned(hp1) then
  973. break;
  974. end
  975. {
  976. This removes the second mov from
  977. mov rX,rY
  978. ...
  979. mov rX,rY
  980. if rX and rY are not modified in-between
  981. }
  982. else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and
  983. MatchInstruction(hp1,A_MOV) and
  984. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  985. MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and
  986. not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then
  987. begin
  988. DebugMsg('Peephole MovMov2Mov 2 performed', p);
  989. AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs);
  990. RemoveInstruction(hp1);
  991. Result := True;
  992. end;
  993. end;
  994. A_SBIC,
  995. A_SBIS:
  996. begin
  997. {
  998. Turn
  999. sbic/sbis X, y
  1000. jmp .L1
  1001. op
  1002. .L1:
  1003. into
  1004. sbis/sbic X,y
  1005. op
  1006. .L1:
  1007. }
  1008. if InvertSkipInstruction(p) then
  1009. result:=true
  1010. {
  1011. Turn
  1012. sbiX X, y
  1013. jmp .L1
  1014. jmp .L2
  1015. .L1:
  1016. op
  1017. .L2:
  1018. into
  1019. sbiX X,y
  1020. .L1:
  1021. op
  1022. .L2:
  1023. }
  1024. else if GetNextInstruction(p, hp1) and
  1025. (hp1.typ=ait_instruction) and
  1026. (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
  1027. (taicpu(hp1).ops>0) and
  1028. (taicpu(hp1).oper[0]^.typ = top_ref) and
  1029. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  1030. GetNextInstruction(hp1, hp2) and
  1031. (hp2.typ=ait_instruction) and
  1032. (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and
  1033. (taicpu(hp2).ops>0) and
  1034. (taicpu(hp2).oper[0]^.typ = top_ref) and
  1035. (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and
  1036. GetNextInstruction(hp2, hp3) and
  1037. (hp3.typ=ait_label) and
  1038. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and
  1039. GetNextInstruction(hp3, hp4) and
  1040. (hp4.typ=ait_instruction) and
  1041. GetNextInstruction(hp4, hp5) and
  1042. (hp3.typ=ait_label) and
  1043. (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then
  1044. begin
  1045. DebugMsg('Peephole SbiJmpJmp2Sbi performed',p);
  1046. tai_label(hp3).labsym.decrefs;
  1047. tai_label(hp5).labsym.decrefs;
  1048. AsmL.remove(hp1);
  1049. taicpu(hp1).Free;
  1050. AsmL.remove(hp2);
  1051. taicpu(hp2).Free;
  1052. result:=true;
  1053. end;
  1054. end;
  1055. end;
  1056. end;
  1057. end;
  1058. end;
  1059. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  1060. begin
  1061. end;
  1062. begin
  1063. casmoptimizer:=TCpuAsmOptimizer;
  1064. End.