aoptcpu.pas 22 KB

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