aoptcpu.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. {
  2. Copyright (c) 1998-2014 by the Free Pascal development team
  3. This unit calls the optimization procedures to optimize the assembler
  4. code for m68k
  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. {$ifdef EXTDEBUG}
  21. {$define DEBUG_AOPTCPU}
  22. {$endif EXTDEBUG}
  23. Interface
  24. uses
  25. cpubase, aoptobj, aoptcpub, aopt, aasmtai,
  26. cgbase;
  27. Type
  28. TCpuAsmOptimizer = class(TAsmOptimizer)
  29. function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean; override;
  30. function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
  31. function TryToFoldDoubleAND(var p: tai): boolean;
  32. function TryToRemoveTST(var p: tai): boolean;
  33. function TryToOptimizeMove(var p: tai): boolean;
  34. function MaybeRealConstOperSimplify(var p: tai): boolean;
  35. function OptPass1LEA(var p: tai): Boolean;
  36. function OptPass1MOVEM(var p: tai): Boolean;
  37. function OptPass1Bitwise(var p: tai): Boolean;
  38. { outputs a debug message into the assembler file }
  39. procedure DebugMsg(const s: string; p: tai);
  40. End;
  41. Implementation
  42. uses
  43. cutils, aasmcpu, cgutils, globtype, globals, verbose, cpuinfo, itcpugas, procinfo, cpupi,
  44. aoptutils;
  45. { Range check must be disabled explicitly as conversions between signed and unsigned
  46. 32-bit values are done without explicit typecasts }
  47. {$R-}
  48. function opname(var p: tai): string;
  49. begin
  50. result:=upcase(gas_op2str[taicpu(p).opcode]);
  51. end;
  52. function RefsEqual(const r1, r2: treference): boolean;
  53. begin
  54. RefsEqual :=
  55. (r1.offset = r2.offset) and
  56. (r1.base = r2.base) and
  57. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  58. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  59. (r1.relsymbol = r2.relsymbol) and
  60. (r1.volatility=[]) and
  61. (r2.volatility=[]);
  62. end;
  63. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean;
  64. begin
  65. result := oper1.typ = oper2.typ;
  66. if result then
  67. case oper1.typ of
  68. top_const:
  69. Result:=oper1.val = oper2.val;
  70. top_reg:
  71. Result:=oper1.reg = oper2.reg;
  72. top_ref:
  73. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  74. else
  75. internalerror(2016112401);
  76. end
  77. end;
  78. function MatchInstruction(const instr: tai; const op: TAsmOp; const opsize: topsizes): boolean;
  79. begin
  80. result :=
  81. (instr.typ = ait_instruction) and
  82. (taicpu(instr).opcode = op) and
  83. ((opsize = []) or (taicpu(instr).opsize in opsize));
  84. end;
  85. function MatchInstruction(const instr : tai;const ops : array of TAsmOp;
  86. const opsize : topsizes) : boolean;
  87. var
  88. op : TAsmOp;
  89. begin
  90. result:=false;
  91. for op in ops do
  92. begin
  93. if (instr.typ = ait_instruction) and
  94. (taicpu(instr).opcode = op) and
  95. ((opsize = []) or (taicpu(instr).opsize in opsize)) then
  96. begin
  97. result:=true;
  98. exit;
  99. end;
  100. end;
  101. end;
  102. function TCpuAsmOptimizer.MaybeRealConstOperSimplify(var p: tai): boolean;
  103. var
  104. tmpint64: int64;
  105. tmpsingle: single;
  106. begin
  107. result:=false;
  108. if (taicpu(p).oper[0]^.typ = top_realconst) then
  109. begin
  110. { if we work with actual integers, turn the operand into one }
  111. if frac(taicpu(p).oper[0]^.val_real) = 0 then
  112. begin
  113. tmpint64:=trunc(taicpu(p).oper[0]^.val_real);
  114. if (high(shortint) >= tmpint64) and (low(shortint) <= tmpint64) then
  115. begin
  116. taicpu(p).opsize := S_B;
  117. taicpu(p).oper[0]^.typ:=top_const;
  118. end
  119. else
  120. if (high(smallint) >= tmpint64) and (low(smallint) <= tmpint64) then
  121. begin
  122. taicpu(p).opsize := S_W;
  123. taicpu(p).oper[0]^.typ:=top_const;
  124. end
  125. else
  126. if (high(longint) >= tmpint64) and (low(longint) <= tmpint64) then
  127. begin
  128. taicpu(p).opsize := S_L;
  129. taicpu(p).oper[0]^.typ:=top_const;
  130. end;
  131. if (taicpu(p).oper[0]^.typ) = top_const then
  132. begin
  133. DebugMsg('Optimizer: FPU real const to integer',p);
  134. taicpu(p).oper[0]^.val:=tmpint64;
  135. result:=true;
  136. end;
  137. end
  138. else
  139. begin
  140. tmpsingle:=taicpu(p).oper[0]^.val_real;
  141. if (taicpu(p).opsize = S_FD) and
  142. ((taicpu(p).oper[0]^.val_real - tmpsingle) = 0.0) then
  143. begin
  144. DebugMsg('Optimizer: FPU real const to lesser precision',p);
  145. taicpu(p).opsize:=S_FS;
  146. result:=true;
  147. end;
  148. end;
  149. end;
  150. end;
  151. function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  152. var
  153. p: taicpu;
  154. begin
  155. if not assigned(hp) or
  156. (hp.typ <> ait_instruction) then
  157. begin
  158. Result := false;
  159. exit;
  160. end;
  161. p := taicpu(hp);
  162. Result :=
  163. (((p.opcode=A_MOVE) or (p.opcode=A_MOVEA) or (p.opcode=A_MVS) or
  164. (p.opcode=A_MVZ) or (p.opcode=A_MOVEQ) or (p.opcode=A_LEA)) and
  165. (p.oper[1]^.typ = top_reg) and
  166. (SuperRegistersEqual(p.oper[1]^.reg,reg)) and
  167. ((p.oper[0]^.typ = top_const) or
  168. ((p.oper[0]^.typ = top_reg) and
  169. not(SuperRegistersEqual(p.oper[0]^.reg,reg))) or
  170. ((p.oper[0]^.typ = top_ref) and
  171. not RegInRef(reg,p.oper[0]^.ref^)))) or
  172. ((p.opcode = A_FMOVE) and
  173. (p.oper[1]^.typ = top_reg) and
  174. (SuperRegistersEqual(p.oper[1]^.reg,reg)) and
  175. ((p.oper[0]^.typ = top_realconst) or
  176. ((p.oper[0]^.typ = top_reg) and
  177. not(SuperRegistersEqual(p.oper[0]^.reg,reg))))) or
  178. ((p.opcode = A_MOVEM) and
  179. (p.oper[1]^.typ = top_regset) and
  180. ((getsupreg(reg) in p.oper[1]^.dataregset) or
  181. (getsupreg(reg) in p.oper[1]^.addrregset))) or
  182. ((p.opcode = A_FMOVEM) and
  183. (p.oper[1]^.typ = top_regset) and
  184. (getsupreg(reg) in p.oper[1]^.fpuregset));
  185. end;
  186. {$ifdef DEBUG_AOPTCPU}
  187. procedure TCpuAsmOptimizer.DebugMsg(const s: string; p : tai);
  188. begin
  189. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  190. end;
  191. {$else DEBUG_AOPTCPU}
  192. procedure TCpuAsmOptimizer.DebugMsg(const s: string; p : tai);inline;
  193. begin
  194. end;
  195. {$endif DEBUG_AOPTCPU}
  196. function TCpuAsmOptimizer.TryToFoldDoubleAND(var p: tai): boolean;
  197. var
  198. next, next2: tai;
  199. opstr: string[15];
  200. begin
  201. result:=false;
  202. if ((taicpu(p).oper[0]^.typ=top_const) and (taicpu(p).oper[1]^.typ=top_reg)) and
  203. GetNextInstruction(p,next) and
  204. MatchInstruction(next,A_AND,[]) and
  205. (taicpu(next).oper[0]^.typ=top_const) and
  206. MatchOperand(taicpu(p).oper[1]^,taicpu(next).oper[1]^) then
  207. begin
  208. DebugMsg('Optimizer: folding double AND',p);
  209. if taicpu(p).opsize<taicpu(next).opsize then
  210. taicpu(p).opsize:=taicpu(next).opsize;
  211. taicpu(p).oper[0]^.val:=taicpu(p).oper[0]^.val and taicpu(next).oper[0]^.val;
  212. RemoveInstruction(next);
  213. result:=true;
  214. end;
  215. end;
  216. function TCpuAsmOptimizer.TryToRemoveTST(var p: tai): boolean;
  217. var
  218. next, next2: tai;
  219. opstr: string[15];
  220. begin
  221. result:=false;
  222. if not((taicpu(p).oper[1]^.typ=top_reg) and isaddressregister(taicpu(p).oper[1]^.reg)) and
  223. GetNextInstruction(p,next) and
  224. MatchInstruction(next,A_TST,[taicpu(p).opsize]) and
  225. MatchOperand(taicpu(p).oper[1]^,taicpu(next).oper[0]^) and
  226. GetNextInstruction(next,next2) and
  227. MatchInstruction(next2,[A_BXX,A_SXX],[S_NO,S_B]) and
  228. (taicpu(next2).condition in [C_NE,C_EQ,C_PL,C_MI]) then
  229. begin
  230. opstr:=opname(p);
  231. DebugMsg('Optimizer: '+opstr+', TST, Jxx/Sxx to '+opstr+', Jxx/Sxx',p);
  232. RemoveInstruction(next);
  233. result:=true;
  234. end;
  235. end;
  236. function TCpuAsmOptimizer.TryToOptimizeMove(var p: tai): boolean;
  237. var
  238. next, next2: tai;
  239. opstr: string[15];
  240. begin
  241. result:=false;
  242. if (taicpu(p).opcode=A_MOVE) then
  243. begin
  244. result:=TryToRemoveTST(p);
  245. if result then
  246. exit;
  247. end;
  248. if GetNextInstruction(p,next) and
  249. (next.typ = ait_instruction) and
  250. (taicpu(next).opcode = taicpu(p).opcode) and
  251. (taicpu(p).opsize = taicpu(next).opsize) and
  252. (taicpu(p).oper[1]^.typ = top_reg) and
  253. MatchOperand(taicpu(p).oper[1]^,taicpu(next).oper[0]^) then
  254. begin
  255. if not(RegInOp(taicpu(p).oper[1]^.reg,taicpu(next).oper[1]^)) and
  256. RegEndOfLife(taicpu(next).oper[0]^.reg, taicpu(next)) then
  257. begin
  258. opstr:=opname(p);
  259. case taicpu(p).oper[0]^.typ of
  260. top_reg:
  261. { do not optimize away FPU to INT to FPU reg moves. These are used for
  262. to-single-rounding on FPUs which have no FSMOVE/FDMOVE. (KB) }
  263. if not ((taicpu(p).opcode = A_FMOVE) and
  264. (getregtype(taicpu(p).oper[0]^.reg) <> getregtype(taicpu(p).oper[1]^.reg))) then
  265. begin
  266. { move %reg0, %tmpreg; move %tmpreg, <ea> -> move %reg0, <ea> }
  267. taicpu(p).loadOper(1,taicpu(next).oper[1]^);
  268. UpdateUsedRegs(p);
  269. RemoveInstruction(next);
  270. result:=true;
  271. { also remove leftover move %reg0, %reg0, which can occur as the result
  272. of the previous optimization, if %reg0 and %tmpreg was different types
  273. (addr vs. data), so these moves were left in by the cg }
  274. if MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) then
  275. begin
  276. DebugMsg('Optimizer: '+opstr+' + '+opstr+' removed',p);
  277. RemoveCurrentP(p);
  278. end
  279. else
  280. DebugMsg('Optimizer: '+opstr+' + '+opstr+' to '+opstr+' #1',p)
  281. end;
  282. top_const:
  283. begin
  284. // DebugMsg('Optimizer: '+opstr+' + '+opstr+' to '+opstr+' #2',p);
  285. end;
  286. top_ref:
  287. begin
  288. { move ref, %tmpreg; move %tmpreg, <ea> -> move ref, <ea> }
  289. { we only want to do this when <ea> is a reg or a simple reference }
  290. with taicpu(next).oper[1]^ do
  291. if (taicpu(next).opcode <> A_FMOVE) and
  292. ((typ = top_reg) or
  293. ((typ = top_ref) and
  294. ((ref^.index = NR_NO) or
  295. (ref^.base = NR_NO)) and
  296. (ref^.symbol = nil) and
  297. (ref^.offset = 0))) then
  298. begin
  299. DebugMsg('Optimizer: '+opstr+' + '+opstr+' to '+opstr+' #3',p);
  300. taicpu(p).loadOper(1,taicpu(next).oper[1]^);
  301. UpdateUsedRegs(p);
  302. RemoveInstruction(next);
  303. result:=true;
  304. end;
  305. end;
  306. else
  307. ;
  308. end;
  309. end;
  310. exit;
  311. end;
  312. if GetNextInstruction(p,next) and
  313. (next.typ = ait_instruction) and
  314. GetNextInstruction(next,next2) and
  315. (next2.typ = ait_instruction) and
  316. (taicpu(next).opcode <> taicpu(p).opcode) and
  317. (taicpu(next2).opcode = taicpu(p).opcode) and
  318. (taicpu(p).oper[0]^.typ = top_reg) and
  319. (taicpu(p).oper[1]^.typ = top_reg) and
  320. (getregtype(taicpu(p).oper[0]^.reg) = getregtype(taicpu(p).oper[1]^.reg)) and
  321. MatchOperand(taicpu(p).oper[1]^,taicpu(next2).oper[0]^) and
  322. MatchOperand(taicpu(next2).oper[1]^,taicpu(p).oper[0]^) and
  323. (taicpu(p).opsize = taicpu(next2).opsize) and
  324. ((taicpu(p).opcode = A_FMOVE) or
  325. (taicpu(p).opsize = taicpu(next).opsize)) then
  326. begin
  327. opstr:=opname(p);
  328. if not(RegInOp(taicpu(p).oper[1]^.reg,taicpu(next2).oper[1]^)) and
  329. not(RegInOp(taicpu(p).oper[1]^.reg,taicpu(next).oper[0]^)) and
  330. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(next2)) then
  331. begin
  332. { move %reg0, %tmpreg
  333. op ???, %tmpreg
  334. move %tmpreg, %reg0
  335. to:
  336. op ???, %reg0 }
  337. if MatchOperand(taicpu(p).oper[1]^,taicpu(next).oper[taicpu(next).ops-1]^) then
  338. begin
  339. {
  340. Disabled, because it breaks some tests... :( (KB)
  341. DebugMsg('Optimizer: '+opstr+' + OP + '+opstr+' to OP #1',next);
  342. taicpu(next).loadOper(taicpu(next).ops-1,taicpu(p).oper[0]^);
  343. asml.remove(p);
  344. asml.remove(next2);
  345. p.free;
  346. next2.free;
  347. result:=true;
  348. }
  349. end;
  350. end;
  351. end;
  352. end;
  353. function TCpuAsmOptimizer.OptPass1LEA(var p: tai): Boolean;
  354. var
  355. next: tai;
  356. begin
  357. Result:=false;
  358. { LEA (Ax),Ax is a NOP if src and dest reg is equal, so remove it. }
  359. if not assigned(taicpu(p).oper[0]^.ref^.symbol) and
  360. (((taicpu(p).oper[0]^.ref^.base = taicpu(p).oper[1]^.reg) and
  361. (taicpu(p).oper[0]^.ref^.index = NR_NO)) or
  362. ((taicpu(p).oper[0]^.ref^.index = taicpu(p).oper[1]^.reg) and
  363. (taicpu(p).oper[0]^.ref^.base = NR_NO))) and
  364. (taicpu(p).oper[0]^.ref^.offset = 0) then
  365. begin
  366. DebugMsg('Optimizer: LEA 0(Ax),Ax removed',p);
  367. result:=RemoveCurrentP(p);
  368. if result then
  369. exit;
  370. end;
  371. if (taicpu(p).oper[1]^.reg=NR_A7) and
  372. (taicpu(p).oper[0]^.ref^.base=NR_A7) and
  373. (taicpu(p).oper[0]^.ref^.index=NR_NO) and
  374. (taicpu(p).oper[0]^.ref^.symbol=nil) and
  375. (taicpu(p).oper[0]^.ref^.direction=dir_none) and
  376. GetNextInstruction(p,next) and
  377. MatchInstruction(next,A_MOVEM,[S_L]) and
  378. MatchOpType(taicpu(next),top_regset,top_ref) and
  379. ((taicpu(p).oper[0]^.ref^.offset=-(PopCnt(Byte(taicpu(next).oper[0]^.dataregset))+PopCnt(Byte(taicpu(next).oper[0]^.addrregset)))*4)) and
  380. (taicpu(next).oper[1]^.ref^.base=NR_A7) and
  381. (taicpu(next).oper[1]^.ref^.index=NR_NO) and
  382. (taicpu(next).oper[1]^.ref^.symbol=nil) and
  383. (taicpu(next).oper[1]^.ref^.direction=dir_none) and
  384. not (current_settings.cputype in cpu_coldfire) then
  385. begin
  386. DebugMsg('Optimizer: LEA, MOVE(M) to MOVE(M) predecremented',p);
  387. taicpu(next).oper[1]^.ref^.direction:=dir_dec;
  388. RemoveCurrentP(p,next);
  389. result:=true;
  390. exit;
  391. end;
  392. end;
  393. function TCpuAsmOptimizer.OptPass1MOVEM(var p: tai): Boolean;
  394. var
  395. next: tai;
  396. begin
  397. Result:=false;
  398. if MatchOpType(taicpu(p),top_ref,top_regset) and
  399. (taicpu(p).oper[0]^.ref^.base=NR_A7) and
  400. (taicpu(p).oper[0]^.ref^.index=NR_NO) and
  401. (taicpu(p).oper[0]^.ref^.symbol=nil) and
  402. (taicpu(p).oper[0]^.ref^.direction=dir_none) and
  403. GetNextInstruction(p,next) and
  404. MatchInstruction(next,A_LEA,[S_NO]) and
  405. (taicpu(next).oper[1]^.reg=NR_A7) and
  406. (taicpu(next).oper[0]^.ref^.base=NR_A7) and
  407. (taicpu(next).oper[0]^.ref^.index=NR_NO) and
  408. (taicpu(next).oper[0]^.ref^.symbol=nil) and
  409. (taicpu(next).oper[0]^.ref^.direction=dir_none) and
  410. ((taicpu(next).oper[0]^.ref^.offset=(PopCnt(Byte(taicpu(p).oper[1]^.dataregset))+PopCnt(Byte(taicpu(p).oper[1]^.addrregset)))*4)) and
  411. not (current_settings.cputype in cpu_coldfire) then
  412. begin
  413. DebugMsg('Optimizer: MOVE(M), LEA to MOVE(M) postincremented',p);
  414. taicpu(p).oper[0]^.ref^.direction:=dir_inc;
  415. RemoveInstruction(next);
  416. result:=true;
  417. exit;
  418. end;
  419. end;
  420. function TCpuAsmOptimizer.OptPass1Bitwise(var p: tai): Boolean;
  421. begin
  422. result:=false;
  423. case p.typ of
  424. ait_instruction:
  425. begin
  426. if taicpu(p).opcode = A_AND then
  427. result:=TryToFoldDoubleAND(p);
  428. if not result then
  429. result:=TryToRemoveTST(p);
  430. end;
  431. else
  432. ;
  433. end;
  434. end;
  435. function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  436. var
  437. next: tai;
  438. tmpref: treference;
  439. begin
  440. result:=false;
  441. case p.typ of
  442. ait_instruction:
  443. begin
  444. //asml.insertbefore(tai_comment.Create(strpnew('pass1 called for instr')), p);
  445. case taicpu(p).opcode of
  446. A_MOVE:
  447. result:=TryToOptimizeMove(p);
  448. A_MOVEM:
  449. result:=OptPass1MOVEM(p);
  450. A_LEA:
  451. result:=OptPass1LEA(p);
  452. { Bitwise operations }
  453. A_AND,A_OR,A_EOR:
  454. result:=OptPass1Bitwise(p);
  455. { Address register sub/add can be replaced with ADDQ/SUBQ or LEA if the value is in the
  456. SmallInt range, which is shorter to encode and faster to execute on most 68k }
  457. A_SUB,A_SUBA,A_ADD,A_ADDA:
  458. if (taicpu(p).oper[1]^.typ = top_reg) and isaddressregister(taicpu(p).oper[1]^.reg) and
  459. (taicpu(p).oper[0]^.typ = top_const) then
  460. begin
  461. if isvalueforaddqsubq(taicpu(p).oper[0]^.val) then
  462. begin
  463. DebugMsg('Optimizer: SUB/ADD #val,Ax to SUBQ/ADDQ',p);
  464. taicpu(p).opsize:=S_L; // this is safe, because we're targetting an address reg
  465. if taicpu(p).opcode in [A_ADD,A_ADDA] then
  466. taicpu(p).opcode:=A_ADDQ
  467. else
  468. taicpu(p).opcode:=A_SUBQ;
  469. result:=true;
  470. end
  471. else
  472. if isvalue16bit(abs(taicpu(p).oper[0]^.val)) then
  473. begin
  474. DebugMsg('Optimizer: SUB/ADD #val,Ax to LEA val(Ax),Ax',p);
  475. if (taicpu(p).opcode=A_SUB) or (taicpu(p).opcode=A_SUBA) then
  476. reference_reset_base(tmpref,taicpu(p).oper[1]^.reg,-taicpu(p).oper[0]^.val,ctempposinvalid,0,[])
  477. else
  478. reference_reset_base(tmpref,taicpu(p).oper[1]^.reg,taicpu(p).oper[0]^.val,ctempposinvalid,0,[]);
  479. taicpu(p).opcode:=A_LEA;
  480. taicpu(p).opsize:=S_NO;
  481. taicpu(p).loadref(0,tmpref);
  482. result:=true;
  483. end;
  484. end
  485. else
  486. result:=TryToRemoveTST(p);
  487. A_SUBQ,A_ADDQ:
  488. result:=TryToRemoveTST(p);
  489. { MOVEA #0,Ax to SUBA Ax,Ax, because it's shorter }
  490. A_MOVEA:
  491. if (taicpu(p).oper[0]^.typ = top_const) and
  492. (taicpu(p).oper[0]^.val = 0) then
  493. begin
  494. DebugMsg('Optimizer: MOVEA #0,Ax to SUBA Ax,Ax',p);
  495. taicpu(p).opcode:=A_SUBA;
  496. taicpu(p).opsize:=S_L; { otherwise it will be .W -> BOOM }
  497. taicpu(p).loadoper(0,taicpu(p).oper[1]^);
  498. result:=true;
  499. end;
  500. { CLR.L Dx on a 68000 is slower than MOVEQ #0,Dx }
  501. A_CLR:
  502. if (current_settings.cputype in [cpu_mc68000]) and
  503. (taicpu(p).oper[0]^.typ = top_reg) and
  504. (taicpu(p).opsize = S_L) and
  505. isintregister(taicpu(p).oper[0]^.reg) then
  506. begin
  507. //DebugMsg('Optimizer: CLR.L Dx to MOVEQ #0,Dx',p);
  508. taicpu(p).opcode:=A_MOVEQ;
  509. taicpu(p).loadoper(1,taicpu(p).oper[0]^);
  510. taicpu(p).loadconst(0,0);
  511. taicpu(p).ops:=2;
  512. result:=true;
  513. end;
  514. A_JSR:
  515. begin
  516. if (cs_opt_level4 in current_settings.optimizerswitches) and
  517. GetNextInstruction(p,next) and
  518. MatchInstruction(next,A_RTS,[S_NO]) and
  519. { play safe: if any parameter is pushed on the stack, we cannot to this optimization
  520. as the bottom stack element might be a parameter and not the return address as it is expected
  521. after a call (which we simulate by a jmp)
  522. Actually, as in this case the stack pointer is no used as a frame pointer and
  523. there will be more instructions to restore the stack frame before jsr, so this
  524. is unlikedly to happen }
  525. (current_procinfo.maxpushedparasize=0) then
  526. begin
  527. DebugMsg('Optimizer: JSR, RTS to JMP',p);
  528. taicpu(p).opcode:=A_JMP;
  529. RemoveInstruction(next);
  530. result:=true;
  531. end;
  532. end;
  533. { CMP #0,<ea> equals to TST <ea>, just shorter and TST is more flexible anyway }
  534. A_CMP,A_CMPI:
  535. if ((taicpu(p).oper[0]^.typ = top_const) and
  536. (taicpu(p).oper[0]^.val = 0)) and
  537. ((taicpu(p).oper[1]^.typ = top_ref) or
  538. ((taicpu(p).oper[1]^.typ = top_reg) and
  539. not (isaddressregister(taicpu(p).oper[1]^.reg) and
  540. not (CPUM68K_HAS_TSTAREG in cpu_capabilities[current_settings.cputype])))) then
  541. begin
  542. DebugMsg('Optimizer: CMP #0 to TST',p);
  543. taicpu(p).opcode:=A_TST;
  544. taicpu(p).loadoper(0,taicpu(p).oper[1]^);
  545. taicpu(p).clearop(1);
  546. taicpu(p).ops:=1;
  547. result:=true;
  548. end;
  549. A_FCMP:
  550. if (taicpu(p).oper[0]^.typ = top_realconst) then
  551. begin
  552. if (taicpu(p).oper[0]^.val_real = 0.0) then
  553. begin
  554. DebugMsg('Optimizer: FCMP #0.0 to FTST',p);
  555. taicpu(p).opcode:=A_FTST;
  556. taicpu(p).opsize:=S_FX;
  557. taicpu(p).loadoper(0,taicpu(p).oper[1]^);
  558. taicpu(p).clearop(1);
  559. taicpu(p).ops:=1;
  560. result:=true;
  561. end
  562. else
  563. result:=result or MaybeRealConstOperSimplify(p);
  564. end;
  565. A_FMOVE,A_FSMOVE,A_FDMOVE,
  566. A_FADD,A_FSADD,A_FDADD,A_FSUB,A_FSSUB,A_FDSUB,
  567. A_FMUL,A_FSMUL,A_FDMUL,A_FDIV,A_FSDIV,A_FDDIV,
  568. A_FSGLMUL,A_FSGLDIV:
  569. begin
  570. if (taicpu(p).opcode = A_FMOVE) and TryToOptimizeMove(p) then
  571. begin
  572. result:=true;
  573. exit;
  574. end;
  575. result:=result or MaybeRealConstOperSimplify(p);
  576. end;
  577. else
  578. ;
  579. end;
  580. end;
  581. else
  582. ;
  583. end;
  584. end;
  585. begin
  586. casmoptimizer:=TCpuAsmOptimizer;
  587. end.