aoptcpu.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. {
  2. Copyright (c) 1998-2004 by Jonas Maebe
  3. This unit calls the optimization procedures to optimize the assembler
  4. code for sparc
  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. Interface
  21. uses
  22. cgbase, cpubase, aoptobj, aoptcpub, aopt, aasmtai, aasmcpu;
  23. Type
  24. TAsmOpSet = set of TAsmOp;
  25. TCpuAsmOptimizer = class(TAsmOptimizer)
  26. function RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
  27. function GetNextInstructionUsingReg(Current: tai;
  28. var Next: tai; reg: TRegister): Boolean;
  29. function RegUsedAfterInstruction(reg: Tregister; p: tai;
  30. var AllUsedRegs: TAllUsedRegs): Boolean;
  31. function TryRemoveMov(var p: tai; opcode: TAsmOp): boolean;
  32. function TryRemoveMovToRefIndex(var p: tai; next: taicpu): boolean;
  33. function TryRemoveMovBeforeStore(var p: tai; next: taicpu; const storeops: TAsmOpSet): boolean;
  34. function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
  35. procedure PeepHoleOptPass2; override;
  36. End;
  37. Implementation
  38. uses
  39. globals,aasmbase,cpuinfo,verbose;
  40. function MatchInstruction(const instr: tai; const op: TAsmOp): boolean;
  41. begin
  42. result :=
  43. (instr.typ = ait_instruction) and
  44. (taicpu(instr).opcode = op);
  45. end;
  46. function MatchOperand(const oper: TOper; reg: TRegister): boolean;
  47. begin
  48. result:=(oper.typ=top_reg) and (oper.reg=reg);
  49. end;
  50. function IsSameReg(this,next: taicpu): boolean;
  51. begin
  52. result:=(next.oper[0]^.typ=top_reg) and
  53. (next.oper[1]^.typ=top_reg) and
  54. (next.oper[0]^.reg=next.oper[1]^.reg) and
  55. (next.oper[0]^.reg=this.oper[0]^.reg);
  56. end;
  57. function regLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  58. var
  59. p: taicpu;
  60. begin
  61. p:=taicpu(hp);
  62. result:=false;
  63. if not ((assigned(hp)) and (hp.typ=ait_instruction)) then
  64. exit;
  65. case p.opcode of
  66. { These instructions do not write into a register at all }
  67. A_NOP,
  68. A_C_EQ_D,A_C_EQ_S,A_C_LE_D,A_C_LE_S,A_C_LT_D,A_C_LT_S,
  69. A_BA,A_BC,
  70. A_SB,A_SH,A_SW,A_SWL,A_SWR,A_SWC1,A_SDC1:
  71. exit;
  72. end;
  73. result:=(p.ops>0) and (p.oper[0]^.typ=top_reg) and
  74. (p.oper[0]^.reg=reg);
  75. end;
  76. function CanBeCMOV(p: tai; condreg: tregister): boolean;
  77. begin
  78. result:=assigned(p) and (p.typ=ait_instruction) and
  79. ((taicpu(p).opcode in [A_MOV_D,A_MOV_S]) or
  80. (
  81. { register with condition must not be overwritten }
  82. (taicpu(p).opcode=A_MOVE) and
  83. (taicpu(p).oper[0]^.reg<>condreg)
  84. ));
  85. end;
  86. procedure ChangeToCMOV(p: taicpu; cond: tasmcond; reg: tregister);
  87. begin
  88. case cond of
  89. C_COP1TRUE:
  90. case p.opcode of
  91. A_MOV_D: p.opcode:=A_MOVT_D;
  92. A_MOV_S: p.opcode:=A_MOVT_S;
  93. A_MOVE: p.opcode:=A_MOVT;
  94. else
  95. InternalError(2014061701);
  96. end;
  97. C_COP1FALSE:
  98. case p.opcode of
  99. A_MOV_D: p.opcode:=A_MOVF_D;
  100. A_MOV_S: p.opcode:=A_MOVF_S;
  101. A_MOVE: p.opcode:=A_MOVF;
  102. else
  103. InternalError(2014061702);
  104. end;
  105. C_EQ:
  106. case p.opcode of
  107. A_MOV_D: p.opcode:=A_MOVZ_D;
  108. A_MOV_S: p.opcode:=A_MOVZ_S;
  109. A_MOVE: p.opcode:=A_MOVZ;
  110. else
  111. InternalError(2014061703);
  112. end;
  113. C_NE:
  114. case p.opcode of
  115. A_MOV_D: p.opcode:=A_MOVN_D;
  116. A_MOV_S: p.opcode:=A_MOVN_S;
  117. A_MOVE: p.opcode:=A_MOVN;
  118. else
  119. InternalError(2014061704);
  120. end;
  121. else
  122. InternalError(2014061705);
  123. end;
  124. p.ops:=3;
  125. p.loadreg(2,reg);
  126. end;
  127. function instructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  128. var
  129. p: taicpu;
  130. i: longint;
  131. begin
  132. result:=false;
  133. if not (assigned(hp) and (hp.typ=ait_instruction)) then
  134. exit;
  135. p:=taicpu(hp);
  136. i:=1;
  137. while(i<p.ops) do
  138. begin
  139. case p.oper[I]^.typ of
  140. top_reg:
  141. result:=(p.oper[I]^.reg=reg) and (I<2);
  142. top_ref:
  143. result:=
  144. (p.oper[I]^.ref^.base=reg) or
  145. (p.oper[I]^.ref^.index=reg);
  146. end;
  147. if result then exit; {Bailout if we found something}
  148. Inc(I);
  149. end;
  150. end;
  151. function TCpuAsmOptimizer.RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean;
  152. var
  153. i : Longint;
  154. begin
  155. result:=false;
  156. for i:=0 to taicpu(p1).ops-1 do
  157. if (taicpu(p1).oper[i]^.typ=top_reg) and (taicpu(p1).oper[i]^.reg=Reg) and (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then
  158. begin
  159. result:=true;
  160. exit;
  161. end;
  162. end;
  163. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  164. var Next: tai; reg: TRegister): Boolean;
  165. begin
  166. Next:=Current;
  167. repeat
  168. Result:=GetNextInstruction(Next,Next);
  169. until {not(cs_opt_level3 in current_settings.optimizerswitches) or} not(Result) or (Next.typ<>ait_instruction) or (RegInInstruction(reg,Next)) or
  170. (is_calljmp(taicpu(Next).opcode));
  171. if Result and (next.typ=ait_instruction) and is_calljmp(taicpu(next).opcode) then
  172. begin
  173. result:=false;
  174. next:=nil;
  175. end;
  176. end;
  177. function TCpuAsmOptimizer.RegUsedAfterInstruction(reg: Tregister; p: tai;
  178. var AllUsedRegs: TAllUsedRegs): Boolean;
  179. begin
  180. AllUsedRegs[getregtype(reg)].Update(tai(p.Next),true);
  181. RegUsedAfterInstruction :=
  182. AllUsedRegs[getregtype(reg)].IsUsed(reg) and
  183. not(regLoadedWithNewValue(reg,p)) and
  184. (
  185. not(GetNextInstruction(p,p)) or
  186. instructionLoadsFromReg(reg,p) or
  187. not(regLoadedWithNewValue(reg,p))
  188. );
  189. end;
  190. function TCpuAsmOptimizer.TryRemoveMov(var p: tai; opcode: TAsmOp): boolean;
  191. var
  192. next,hp1: tai;
  193. alloc,dealloc: tai_regalloc;
  194. begin
  195. { Fold
  196. op $reg1,...
  197. opcode $reg2,$reg1
  198. dealloc $reg1
  199. into
  200. op $reg2,...
  201. opcode may be A_MOVE, A_MOV_s, A_MOV_d, etc.
  202. }
  203. result:=false;
  204. if (taicpu(p).ops>0) and
  205. GetNextInstructionUsingReg(p,next,taicpu(p).oper[0]^.reg) and
  206. MatchInstruction(next,opcode) and
  207. MatchOperand(taicpu(next).oper[1]^,taicpu(p).oper[0]^.reg) and
  208. { the destination register of mov cannot be used between p and next }
  209. (not RegUsedBetween(taicpu(next).oper[0]^.reg,p,next)) then
  210. begin
  211. dealloc:=FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.Next));
  212. if assigned(dealloc) then
  213. begin
  214. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  215. and remove it if possible }
  216. GetLastInstruction(p,hp1);
  217. asml.Remove(dealloc);
  218. alloc:=FindRegAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  219. if assigned(alloc) then
  220. begin
  221. asml.Remove(alloc);
  222. alloc.free;
  223. dealloc.free;
  224. end
  225. else
  226. asml.InsertAfter(dealloc,p);
  227. { try to move the allocation of the target register }
  228. GetLastInstruction(next,hp1);
  229. alloc:=FindRegAlloc(taicpu(next).oper[0]^.reg,tai(hp1.Next));
  230. if assigned(alloc) then
  231. begin
  232. asml.Remove(alloc);
  233. asml.InsertBefore(alloc,p);
  234. { adjust used regs }
  235. IncludeRegInUsedRegs(taicpu(next).oper[0]^.reg,UsedRegs);
  236. end;
  237. { finally get rid of the mov }
  238. taicpu(p).loadreg(0,taicpu(next).oper[0]^.reg);
  239. asml.remove(next);
  240. next.free;
  241. result:=true;
  242. end;
  243. end;
  244. end;
  245. function TCpuAsmOptimizer.TryRemoveMovBeforeStore(var p: tai; next: taicpu; const storeops: TAsmOpSet): boolean;
  246. begin
  247. result:=(next.opcode in storeops) and
  248. MatchOperand(next.oper[0]^,taicpu(p).oper[0]^.reg) and
  249. { Ry cannot be modified between move and store }
  250. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,next)) and
  251. Assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.next)));
  252. if result then
  253. begin
  254. next.loadreg(0,taicpu(p).oper[1]^.reg);
  255. asml.remove(p);
  256. p.free;
  257. p:=next;
  258. end;
  259. end;
  260. function TCpuAsmOptimizer.TryRemoveMovToRefIndex(var p: tai; next: taicpu): boolean;
  261. begin
  262. result:=(next.oper[1]^.typ=top_ref) and
  263. (next.oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
  264. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,next)) and
  265. Assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.next)));
  266. if result then
  267. begin
  268. next.oper[1]^.ref^.base:=taicpu(p).oper[1]^.reg;
  269. asml.remove(p);
  270. p.free;
  271. p:=next;
  272. end;
  273. end;
  274. function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  275. var
  276. next,next2: tai;
  277. TmpUsedRegs: TAllUsedRegs;
  278. begin
  279. result:=false;
  280. case p.typ of
  281. ait_instruction:
  282. begin
  283. case taicpu(p).opcode of
  284. A_SEH:
  285. begin
  286. if GetNextInstructionUsingReg(p,next,taicpu(p).oper[0]^.reg) and
  287. MatchInstruction(next,A_SH) and
  288. MatchOperand(taicpu(next).oper[0]^,taicpu(p).oper[0]^.reg) and
  289. (not RegUsedBetween(taicpu(p).oper[1]^.reg,p,next)) and
  290. Assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.next))) then
  291. begin
  292. taicpu(next).loadreg(0,taicpu(p).oper[1]^.reg);
  293. asml.remove(p);
  294. p.free;
  295. p:=next;
  296. end
  297. else
  298. TryRemoveMov(p,A_MOVE);
  299. end;
  300. A_SEB:
  301. { TODO: can be handled similar to A_SEH, but it's almost never encountered }
  302. TryRemoveMov(p,A_MOVE);
  303. A_SLL:
  304. begin
  305. { if this is a sign extension... }
  306. if (taicpu(p).oper[2]^.typ=top_const) and
  307. GetNextInstruction(p,next) and
  308. MatchInstruction(next,A_SRA) and
  309. IsSameReg(taicpu(p),taicpu(next)) and
  310. (taicpu(next).oper[2]^.typ=top_const) and
  311. (taicpu(next).oper[2]^.val=taicpu(p).oper[2]^.val) and
  312. (taicpu(next).oper[2]^.val=16) and
  313. { ...followed by 16-bit store (possibly with PIC simplification, etc. in between) }
  314. GetNextInstructionUsingReg(next,next2,taicpu(p).oper[0]^.reg) and
  315. MatchInstruction(next2,A_SH) and
  316. (taicpu(next2).oper[0]^.typ=top_reg) and
  317. (taicpu(next2).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  318. { the initial register may not be reused }
  319. (not RegUsedBetween(taicpu(p).oper[1]^.reg,next,next2)) then
  320. begin
  321. if Assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next2.next))) then
  322. begin
  323. taicpu(next2).loadreg(0,taicpu(p).oper[1]^.reg);
  324. asml.remove(p);
  325. asml.remove(next);
  326. p.free;
  327. next.free;
  328. p:=next2;
  329. end;
  330. end
  331. else
  332. TryRemoveMov(p,A_MOVE);
  333. end;
  334. A_SRL:
  335. begin
  336. { TODO: also kill sign-extensions that follow, both SLL+SRA and SEB/SEH versions }
  337. { Remove 'andi' in sequences
  338. srl Rx,Ry,16
  339. andi Rx,Rx,65535
  340. srl Rx,Ry,24
  341. andi Rx,Rx,255
  342. since 'srl' clears all relevant upper bits }
  343. if (taicpu(p).oper[2]^.typ=top_const) and
  344. GetNextInstruction(p,next) and
  345. MatchInstruction(next,A_ANDI) and
  346. IsSameReg(taicpu(p),taicpu(next)) and
  347. (taicpu(next).oper[2]^.typ=top_const) and
  348. ((
  349. (taicpu(p).oper[2]^.val>=16) and
  350. (taicpu(next).oper[2]^.val=65535)
  351. ) or (
  352. (taicpu(p).oper[2]^.val>=24) and
  353. (taicpu(next).oper[2]^.val=255)
  354. )) then
  355. begin
  356. asml.remove(next);
  357. next.free;
  358. end
  359. else
  360. TryRemoveMov(p,A_MOVE);
  361. end;
  362. A_ANDI:
  363. begin
  364. { Remove sign extension after 'andi' if bit 7/15 of const operand is clear }
  365. if (taicpu(p).oper[2]^.typ=top_const) and
  366. GetNextInstruction(p,next) and
  367. MatchInstruction(next,A_SLL) and
  368. GetNextInstruction(next,next2) and
  369. MatchInstruction(next2,A_SRA) and
  370. IsSameReg(taicpu(p),taicpu(next)) and
  371. IsSameReg(taicpu(p),taicpu(next2)) and
  372. (taicpu(next).oper[2]^.typ=top_const) and
  373. (taicpu(next2).oper[2]^.typ=top_const) and
  374. (taicpu(next).oper[2]^.val=taicpu(next2).oper[2]^.val) and
  375. ((
  376. (taicpu(p).oper[2]^.val<=$7fff) and
  377. (taicpu(next).oper[2]^.val=16)
  378. ) or (
  379. (taicpu(p).oper[2]^.val<=$7f) and
  380. (taicpu(next).oper[2]^.val=24)
  381. )) then
  382. begin
  383. asml.remove(next);
  384. asml.remove(next2);
  385. next.free;
  386. next2.free;
  387. end
  388. { Remove zero extension if register is used only for byte/word memory store }
  389. else if (taicpu(p).oper[2]^.typ=top_const) and
  390. GetNextInstruction(p,next) and
  391. ((taicpu(p).oper[2]^.val=255) and MatchInstruction(next,A_SB)) or
  392. ((taicpu(p).oper[2]^.val=65535) and MatchInstruction(next,A_SH)) and
  393. (taicpu(next).oper[0]^.typ=top_reg) and
  394. (taicpu(next).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
  395. begin
  396. CopyUsedRegs(TmpUsedRegs);
  397. UpdateUsedRegs(TmpUsedRegs, tai(p.next));
  398. if not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,next,TmpUsedRegs) then
  399. begin
  400. taicpu(next).loadreg(0,taicpu(p).oper[1]^.reg);
  401. asml.remove(p);
  402. p.free;
  403. p:=next;
  404. end;
  405. ReleaseUsedRegs(TmpUsedRegs);
  406. end
  407. else
  408. TryRemoveMov(p,A_MOVE);
  409. end;
  410. A_MOV_S:
  411. begin
  412. if GetNextInstructionUsingReg(p,next,taicpu(p).oper[0]^.reg) and
  413. (next.typ=ait_instruction) then
  414. begin
  415. if TryRemoveMovBeforeStore(p,taicpu(next),[A_SWC1]) then
  416. { optimization successful };
  417. end;
  418. end;
  419. A_MOV_D:
  420. begin
  421. if GetNextInstructionUsingReg(p,next,taicpu(p).oper[0]^.reg) and
  422. (next.typ=ait_instruction) then
  423. begin
  424. if TryRemoveMovBeforeStore(p,taicpu(next),[A_SDC1]) then
  425. { optimization successful };
  426. end;
  427. end;
  428. A_MOVE:
  429. begin
  430. if GetNextInstructionUsingReg(p,next,taicpu(p).oper[0]^.reg) and
  431. (next.typ=ait_instruction) and
  432. (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,next)) then
  433. begin
  434. { MOVE Rx,Ry; store Rx,(ref); dealloc Rx ==> store Ry,(ref) }
  435. if TryRemoveMovBeforeStore(p,taicpu(next),[A_SB,A_SH,A_SW]) then
  436. { optimization successful }
  437. else if TryRemoveMovToRefIndex(p,taicpu(next)) then
  438. { successful as well }
  439. { MOVE Rx,Ry; opcode Rx,Rx,any ==> opcode Rx,Ry,any
  440. MOVE Rx,Ry; opcode Rx,Rz,Rx ==> opcode Rx,Rz,Ry }
  441. else if (taicpu(next).opcode in [A_ADD,A_ADDU,A_ADDI,A_ADDIU,A_SUB,A_SUBU]) and
  442. MatchOperand(taicpu(next).oper[0]^,taicpu(p).oper[0]^.reg) then
  443. begin
  444. if MatchOperand(taicpu(next).oper[1]^,taicpu(p).oper[0]^.reg) then
  445. begin
  446. taicpu(next).loadreg(1,taicpu(p).oper[1]^.reg);
  447. asml.remove(p);
  448. p.free;
  449. p:=next;
  450. end
  451. { TODO: if Ry=NR_R0, this effectively changes instruction into MOVE,
  452. providing further optimization possibilities }
  453. else if MatchOperand(taicpu(next).oper[2]^,taicpu(p).oper[0]^.reg) then
  454. begin
  455. taicpu(next).loadreg(2,taicpu(p).oper[1]^.reg);
  456. asml.remove(p);
  457. p.free;
  458. p:=next;
  459. end;
  460. end
  461. { MOVE Rx,Ry; opcode Rz,Rx,any; dealloc Rx ==> opcode Rz,Ry,any }
  462. else if (taicpu(next).opcode in [A_ADD,A_ADDU,A_ADDI,A_ADDIU,A_SUB,A_SUBU,A_SLT,A_SLTU,A_DIV,A_DIVU]) and
  463. Assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.next))) then
  464. begin
  465. if MatchOperand(taicpu(next).oper[1]^,taicpu(p).oper[0]^.reg) then
  466. begin
  467. taicpu(next).loadreg(1,taicpu(p).oper[1]^.reg);
  468. asml.remove(p);
  469. p.free;
  470. p:=next;
  471. end
  472. else if MatchOperand(taicpu(next).oper[2]^,taicpu(p).oper[0]^.reg) then
  473. begin
  474. taicpu(next).loadreg(2,taicpu(p).oper[1]^.reg);
  475. asml.remove(p);
  476. p.free;
  477. p:=next;
  478. end;
  479. end
  480. { MULT[U] must be handled separately due to different operand numbers }
  481. else if (taicpu(next).opcode in [A_MULT,A_MULTU]) and
  482. Assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.next))) then
  483. begin
  484. if MatchOperand(taicpu(next).oper[0]^,taicpu(p).oper[0]^.reg) then
  485. begin
  486. taicpu(next).loadreg(0,taicpu(p).oper[1]^.reg);
  487. asml.remove(p);
  488. p.free;
  489. p:=next;
  490. end
  491. else if MatchOperand(taicpu(next).oper[1]^,taicpu(p).oper[0]^.reg) then
  492. begin
  493. taicpu(next).loadreg(1,taicpu(p).oper[1]^.reg);
  494. asml.remove(p);
  495. p.free;
  496. p:=next;
  497. end;
  498. end
  499. else if TryRemoveMov(p,A_MOVE) then
  500. begin
  501. { Ended up with move between same register? Suicide then. }
  502. if (taicpu(p).oper[0]^.reg=taicpu(p).oper[1]^.reg) then
  503. begin
  504. GetNextInstruction(p,next);
  505. asml.remove(p);
  506. p.free;
  507. p:=next;
  508. end;
  509. end;
  510. { TODO: MOVE Rx,Ry; Bcc Rx,Rz,label; dealloc Rx ==> Bcc Ry,Rz,label }
  511. end;
  512. end;
  513. A_LB,A_LBU,A_LH,A_LHU,A_LW,
  514. A_ADD,A_ADDU,
  515. A_ADDI,A_ADDIU,
  516. A_SUB,A_SUBU,
  517. A_SRA,A_SRAV,
  518. A_SRLV,
  519. A_SLLV,
  520. A_MFLO,A_MFHI,
  521. A_AND,A_OR,A_XOR,A_ORI,A_XORI:
  522. TryRemoveMov(p,A_MOVE);
  523. A_LWC1,
  524. A_ADD_s, A_SUB_s, A_MUL_s, A_DIV_s,
  525. A_ABS_s, A_NEG_s, A_SQRT_s,
  526. A_CVT_s_w, A_CVT_s_l, A_CVT_s_d:
  527. TryRemoveMov(p,A_MOV_s);
  528. A_LDC1,
  529. A_ADD_d, A_SUB_d, A_MUL_d, A_DIV_d,
  530. A_ABS_d, A_NEG_d, A_SQRT_d,
  531. A_CVT_d_w, A_CVT_d_l, A_CVT_d_s:
  532. TryRemoveMov(p,A_MOV_d);
  533. end;
  534. end;
  535. end;
  536. end;
  537. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  538. var
  539. p: tai;
  540. l: longint;
  541. hp1,hp2,hp3: tai;
  542. condition: tasmcond;
  543. condreg: tregister;
  544. begin
  545. { Currently, everything below is mips4+ }
  546. if (current_settings.cputype<cpu_mips4) then
  547. exit;
  548. p:=BlockStart;
  549. ClearUsedRegs;
  550. while (p<>BlockEnd) Do
  551. begin
  552. UpdateUsedRegs(tai(p.next));
  553. case p.typ of
  554. ait_instruction:
  555. begin
  556. case taicpu(p).opcode of
  557. A_BC:
  558. begin
  559. condreg:=NR_NO;
  560. if (taicpu(p).condition in [C_COP1TRUE,C_COP1FALSE]) then
  561. { TODO: must be taken from "p" if/when codegen makes use of multiple %fcc }
  562. condreg:=NR_FCC0
  563. else if (taicpu(p).condition in [C_EQ,C_NE]) then
  564. begin
  565. if (taicpu(p).oper[0]^.reg=NR_R0) then
  566. condreg:=taicpu(p).oper[1]^.reg
  567. else if (taicpu(p).oper[1]^.reg=NR_R0) then
  568. condreg:=taicpu(p).oper[0]^.reg
  569. end;
  570. if (condreg<>NR_NO) then
  571. begin
  572. { check for
  573. bCC xxx
  574. <several movs>
  575. xxx:
  576. }
  577. l:=0;
  578. GetNextInstruction(p, hp1);
  579. while CanBeCMOV(hp1,condreg) do // CanBeCMOV returns False for nil or labels
  580. begin
  581. inc(l);
  582. GetNextInstruction(hp1,hp1);
  583. end;
  584. if assigned(hp1) then
  585. begin
  586. if FindLabel(tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol),hp1) then
  587. begin
  588. if (l<=4) and (l>0) then
  589. begin
  590. condition:=inverse_cond(taicpu(p).condition);
  591. hp2:=p;
  592. GetNextInstruction(p,hp1);
  593. p:=hp1;
  594. repeat
  595. ChangeToCMOV(taicpu(hp1),condition,condreg);
  596. GetNextInstruction(hp1,hp1);
  597. until not CanBeCMOV(hp1,condreg);
  598. { wait with removing else GetNextInstruction could
  599. ignore the label if it was the only usage in the
  600. jump moved away }
  601. tasmlabel(taicpu(hp2).oper[taicpu(hp2).ops-1]^.ref^.symbol).decrefs;
  602. RemoveDelaySlot(hp2);
  603. asml.remove(hp2);
  604. hp2.free;
  605. continue;
  606. end;
  607. end
  608. else
  609. begin
  610. { check further for
  611. bCC xxx
  612. <several movs 1>
  613. b yyy
  614. xxx:
  615. <several movs 2>
  616. yyy:
  617. }
  618. { hp2 points to jmp yyy }
  619. hp2:=hp1;
  620. { skip hp1 to xxx }
  621. GetNextInstruction(hp1, hp1);
  622. if assigned(hp2) and
  623. assigned(hp1) and
  624. (l<=3) and
  625. (hp2.typ=ait_instruction) and
  626. (taicpu(hp2).opcode=A_BA) and
  627. { real label and jump, no further references to the
  628. label are allowed }
  629. (tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol).getrefs<=2) and
  630. FindLabel(tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol),hp1) then
  631. begin
  632. l:=0;
  633. { skip hp1 to <several moves 2> }
  634. GetNextInstruction(hp1, hp1);
  635. while CanBeCMOV(hp1,condreg) do
  636. begin
  637. inc(l);
  638. GetNextInstruction(hp1, hp1);
  639. end;
  640. { hp1 points to yyy: }
  641. if assigned(hp1) and
  642. FindLabel(tasmlabel(taicpu(hp2).oper[taicpu(hp2).ops-1]^.ref^.symbol),hp1) then
  643. begin
  644. condition:=inverse_cond(taicpu(p).condition);
  645. GetNextInstruction(p,hp1);
  646. hp3:=p;
  647. p:=hp1;
  648. repeat
  649. ChangeToCMOV(taicpu(hp1),condition,condreg);
  650. GetNextInstruction(hp1,hp1);
  651. until not CanBeCMOV(hp1,condreg);
  652. { hp2 is still at b yyy }
  653. GetNextInstruction(hp2,hp1);
  654. { hp2 is now at xxx: }
  655. condition:=inverse_cond(condition);
  656. GetNextInstruction(hp1,hp1);
  657. { hp1 is now at <several movs 2> }
  658. repeat
  659. ChangeToCMOV(taicpu(hp1),condition,condreg);
  660. GetNextInstruction(hp1,hp1);
  661. until not CanBeCMOV(hp1,condreg);
  662. { remove bCC }
  663. tasmlabel(taicpu(hp3).oper[taicpu(hp3).ops-1]^.ref^.symbol).decrefs;
  664. RemoveDelaySlot(hp3);
  665. asml.remove(hp3);
  666. hp3.free;
  667. { remove jmp }
  668. tasmlabel(taicpu(hp2).oper[taicpu(hp2).ops-1]^.ref^.symbol).decrefs;
  669. RemoveDelaySlot(hp2);
  670. asml.remove(hp2);
  671. hp2.free;
  672. continue;
  673. end;
  674. end;
  675. end;
  676. end;
  677. end;
  678. end;
  679. end;
  680. end;
  681. end;
  682. UpdateUsedRegs(p);
  683. p:=tai(p.next);
  684. end;
  685. end;
  686. begin
  687. casmoptimizer:=TCpuAsmOptimizer;
  688. end.