aoptcpu.pas 50 KB

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