aoptcpu.pas 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  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[1]^.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 1 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. { turn
  823. mov reg1, reg0
  824. <op> reg1,xxxx
  825. dealloc reg1
  826. into
  827. <op> reg1,xxx
  828. }
  829. else if MatchOpType(taicpu(p),top_reg,top_reg) and
  830. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  831. not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
  832. MatchInstruction(hp1,[A_CP,A_CPC,A_CPI,A_SBRS,A_SBRC]) and
  833. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  834. begin
  835. DebugMsg('Peephole MovOp2Op 2 performed', p);
  836. for i := 0 to taicpu(hp1).ops-1 do
  837. if taicpu(hp1).oper[i]^.typ=top_reg then
  838. if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
  839. taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
  840. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  841. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  842. if assigned(alloc) and assigned(dealloc) then
  843. begin
  844. asml.Remove(alloc);
  845. alloc.Free;
  846. asml.Remove(dealloc);
  847. dealloc.Free;
  848. end;
  849. { life range of reg1 is increased }
  850. AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs);
  851. { p will be removed, update used register as we continue
  852. with the next instruction after p }
  853. result:=RemoveCurrentP(p);
  854. end
  855. { remove
  856. mov reg0,reg0
  857. }
  858. else if (taicpu(p).ops=2) and
  859. (taicpu(p).oper[0]^.typ = top_reg) and
  860. (taicpu(p).oper[1]^.typ = top_reg) and
  861. (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
  862. begin
  863. DebugMsg('Peephole RedundantMov performed', p);
  864. result:=RemoveCurrentP(p);
  865. end
  866. {
  867. Turn
  868. mov rx,ry
  869. op rx,rz
  870. mov ry, rx
  871. Into
  872. op ry,rz
  873. }
  874. else if (taicpu(p).ops=2) and
  875. MatchOpType(taicpu(p),top_reg,top_reg) and
  876. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  877. (hp1.typ=ait_instruction) and
  878. (taicpu(hp1).ops >= 1) and
  879. (taicpu(hp1).oper[0]^.typ = top_reg) and
  880. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  881. MatchInstruction(hp2,A_MOV) and
  882. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  883. (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and
  884. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  885. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  886. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and
  887. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR,
  888. A_INC,A_DEC,
  889. A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and
  890. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  891. begin
  892. DebugMsg('Peephole MovOpMov2Op performed', p);
  893. if (taicpu(hp1).ops=2) and
  894. (taicpu(hp1).oper[1]^.typ=top_reg) and
  895. (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then
  896. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  897. taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg;
  898. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  899. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  900. if assigned(alloc) and assigned(dealloc) then
  901. begin
  902. asml.Remove(alloc);
  903. alloc.Free;
  904. asml.Remove(dealloc);
  905. dealloc.Free;
  906. end;
  907. asml.remove(hp2);
  908. hp2.free;
  909. result:=RemoveCurrentP(p);
  910. end
  911. {
  912. Turn
  913. mov rx,ry
  914. op rx,rw
  915. mov rw,rx
  916. Into
  917. op rw,ry
  918. }
  919. else if (taicpu(p).ops=2) and
  920. MatchOpType(taicpu(p),top_reg,top_reg) and
  921. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  922. (hp1.typ=ait_instruction) and
  923. (taicpu(hp1).ops = 2) and
  924. MatchOpType(taicpu(hp1),top_reg,top_reg) and
  925. GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and
  926. (hp2.typ=ait_instruction) and
  927. (taicpu(hp2).opcode=A_MOV) and
  928. MatchOpType(taicpu(hp2),top_reg,top_reg) and
  929. (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and
  930. (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and
  931. (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and
  932. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and
  933. (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and
  934. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then
  935. begin
  936. DebugMsg('Peephole MovOpMov2Op2 performed', p);
  937. taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg;
  938. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  939. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  940. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next));
  941. if assigned(alloc) and assigned(dealloc) then
  942. begin
  943. asml.Remove(alloc);
  944. alloc.Free;
  945. asml.Remove(dealloc);
  946. dealloc.Free;
  947. end;
  948. result:=RemoveCurrentP(p);
  949. asml.remove(hp2);
  950. hp2.free;
  951. end
  952. { fold
  953. mov reg2,reg0
  954. mov reg3,reg1
  955. to
  956. movw reg2,reg0
  957. }
  958. else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  959. (taicpu(p).ops=2) and
  960. (taicpu(p).oper[0]^.typ = top_reg) and
  961. (taicpu(p).oper[1]^.typ = top_reg) and
  962. getnextinstruction(p,hp1) and
  963. (hp1.typ = ait_instruction) and
  964. (taicpu(hp1).opcode = A_MOV) and
  965. (taicpu(hp1).ops=2) and
  966. (taicpu(hp1).oper[0]^.typ = top_reg) and
  967. (taicpu(hp1).oper[1]^.typ = top_reg) and
  968. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  969. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  970. ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
  971. (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
  972. begin
  973. DebugMsg('Peephole MovMov2Movw performed', p);
  974. alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
  975. if assigned(alloc) then
  976. begin
  977. asml.Remove(alloc);
  978. asml.InsertBefore(alloc,p);
  979. { proper book keeping of currently used registers }
  980. IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs);
  981. end;
  982. taicpu(p).opcode:=A_MOVW;
  983. asml.remove(hp1);
  984. hp1.free;
  985. result:=true;
  986. end
  987. {
  988. This removes the first mov from
  989. mov rX,...
  990. mov rX,...
  991. }
  992. else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and
  993. { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight }
  994. MatchInstruction(hp1,A_MOV) and
  995. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then
  996. while MatchInstruction(hp1,A_MOV) and
  997. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  998. { don't remove the first mov if the second is a mov rX,rX }
  999. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
  1000. begin
  1001. DebugMsg('Peephole MovMov2Mov 1 performed', p);
  1002. RemoveCurrentP(p,hp1);
  1003. Result := True;
  1004. GetNextInstruction(hp1,hp1);
  1005. if not assigned(hp1) then
  1006. break;
  1007. end
  1008. {
  1009. This removes the second mov from
  1010. mov rX,rY
  1011. ...
  1012. mov rX,rY
  1013. if rX and rY are not modified in-between
  1014. }
  1015. else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and
  1016. MatchInstruction(hp1,A_MOV) and
  1017. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  1018. MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and
  1019. not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then
  1020. begin
  1021. DebugMsg('Peephole MovMov2Mov 2 performed', p);
  1022. AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs);
  1023. RemoveInstruction(hp1);
  1024. Result := True;
  1025. end;
  1026. end;
  1027. A_SBIC,
  1028. A_SBIS:
  1029. begin
  1030. {
  1031. Turn
  1032. sbic/sbis X, y
  1033. jmp .L1
  1034. op
  1035. .L1:
  1036. into
  1037. sbis/sbic X,y
  1038. op
  1039. .L1:
  1040. }
  1041. if InvertSkipInstruction(p) then
  1042. result:=true
  1043. {
  1044. Turn
  1045. sbiX X, y
  1046. jmp .L1
  1047. jmp .L2
  1048. .L1:
  1049. op
  1050. .L2:
  1051. into
  1052. sbiX X,y
  1053. .L1:
  1054. op
  1055. .L2:
  1056. }
  1057. else if GetNextInstruction(p, hp1) and
  1058. (hp1.typ=ait_instruction) and
  1059. (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
  1060. (taicpu(hp1).ops>0) and
  1061. (taicpu(hp1).oper[0]^.typ = top_ref) and
  1062. (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
  1063. GetNextInstruction(hp1, hp2) and
  1064. (hp2.typ=ait_instruction) and
  1065. (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and
  1066. (taicpu(hp2).ops>0) and
  1067. (taicpu(hp2).oper[0]^.typ = top_ref) and
  1068. (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and
  1069. GetNextInstruction(hp2, hp3) and
  1070. (hp3.typ=ait_label) and
  1071. (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and
  1072. GetNextInstruction(hp3, hp4) and
  1073. (hp4.typ=ait_instruction) and
  1074. GetNextInstruction(hp4, hp5) and
  1075. (hp3.typ=ait_label) and
  1076. (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then
  1077. begin
  1078. DebugMsg('Peephole SbiJmpJmp2Sbi performed',p);
  1079. tai_label(hp3).labsym.decrefs;
  1080. tai_label(hp5).labsym.decrefs;
  1081. AsmL.remove(hp1);
  1082. taicpu(hp1).Free;
  1083. AsmL.remove(hp2);
  1084. taicpu(hp2).Free;
  1085. result:=true;
  1086. end;
  1087. end;
  1088. end;
  1089. end;
  1090. end;
  1091. end;
  1092. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  1093. begin
  1094. end;
  1095. begin
  1096. casmoptimizer:=TCpuAsmOptimizer;
  1097. End.