aoptcpu.pas 27 KB

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