aoptcpu.pas 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit implements the ARM64 optimizer object
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit aoptcpu;
  19. {$i fpcdefs.inc}
  20. { $define DEBUG_AOPTCPU}
  21. Interface
  22. uses
  23. globtype, globals,
  24. cutils,
  25. cgbase, cpubase, aasmtai, aasmcpu, aopt, aoptcpub;
  26. Type
  27. TCpuAsmOptimizer = class(TAsmOptimizer)
  28. function CanDoJumpOpts: Boolean; override;
  29. { uses the same constructor as TAopObj }
  30. function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;override;
  31. function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;override;
  32. function GetNextInstructionUsingReg(Current : tai; out Next : tai; reg : TRegister) : Boolean;
  33. procedure DebugMsg(const s : string; p : tai);
  34. private
  35. function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
  36. End;
  37. Implementation
  38. uses
  39. aasmbase,
  40. aoptutils,
  41. cgutils,
  42. verbose;
  43. {$ifdef DEBUG_AOPTCPU}
  44. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
  45. begin
  46. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  47. end;
  48. {$else DEBUG_AOPTCPU}
  49. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  50. begin
  51. end;
  52. {$endif DEBUG_AOPTCPU}
  53. function CanBeCond(p : tai) : boolean;
  54. begin
  55. result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
  56. end;
  57. function TCpuAsmOptimizer.CanDoJumpOpts: Boolean;
  58. begin
  59. Result := true;
  60. end;
  61. function RefsEqual(const r1, r2: treference): boolean;
  62. begin
  63. refsequal :=
  64. (r1.offset = r2.offset) and
  65. (r1.base = r2.base) and
  66. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  67. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  68. (r1.relsymbol = r2.relsymbol) and
  69. (r1.volatility=[]) and
  70. (r2.volatility=[]);
  71. end;
  72. function MatchInstruction(const instr: tai; const op: TAsmOp): boolean;
  73. begin
  74. result :=
  75. (instr.typ = ait_instruction) and
  76. (taicpu(instr).opcode = op);
  77. end;
  78. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  79. begin
  80. result := (oper.typ = top_reg) and (oper.reg = reg);
  81. end;
  82. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  83. begin
  84. result := oper1.typ = oper2.typ;
  85. if result then
  86. case oper1.typ of
  87. top_const:
  88. Result:=oper1.val = oper2.val;
  89. top_reg:
  90. Result:=oper1.reg = oper2.reg;
  91. top_ref:
  92. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  93. else Result:=false;
  94. end
  95. end;
  96. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  97. Out Next: tai; reg: TRegister): Boolean;
  98. begin
  99. Next:=Current;
  100. repeat
  101. Result:=GetNextInstruction(Next,Next);
  102. until not (Result) or
  103. not(cs_opt_level3 in current_settings.optimizerswitches) or
  104. (Next.typ<>ait_instruction) or
  105. RegInInstruction(reg,Next) or
  106. is_calljmp(taicpu(Next).opcode);
  107. end;
  108. function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  109. var
  110. p: taicpu;
  111. begin
  112. p := taicpu(hp);
  113. Result := false;
  114. if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
  115. exit;
  116. end;
  117. function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  118. var
  119. p: taicpu;
  120. i: longint;
  121. begin
  122. instructionLoadsFromReg := false;
  123. if not (assigned(hp) and (hp.typ = ait_instruction)) then
  124. exit;
  125. p:=taicpu(hp);
  126. i:=1;
  127. { Start on oper[0]? }
  128. if taicpu(hp).spilling_get_operation_type(0) in [operand_read, operand_readwrite] then
  129. i:=0;
  130. while(i<p.ops) do
  131. begin
  132. case p.oper[I]^.typ of
  133. top_reg:
  134. Result := (p.oper[I]^.reg = reg);
  135. top_ref:
  136. Result :=
  137. (p.oper[I]^.ref^.base = reg) or
  138. (p.oper[I]^.ref^.index = reg);
  139. else
  140. ;
  141. end;
  142. { Bailout if we found something }
  143. if Result then
  144. exit;
  145. Inc(I);
  146. end;
  147. end;
  148. function TCpuAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
  149. var
  150. alloc,
  151. dealloc : tai_regalloc;
  152. hp1 : tai;
  153. begin
  154. Result:=false;
  155. if MatchInstruction(movp, A_MOV) and
  156. (taicpu(p).ops>=3) and
  157. { We can't optimize if there is a shiftop }
  158. (taicpu(movp).ops=2) and
  159. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  160. { the destination register of the mov might not be used beween p and movp }
  161. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  162. { Take care to only do this for instructions which REALLY load to the first register.
  163. Otherwise
  164. str reg0, [reg1]
  165. mov reg2, reg0
  166. will be optimized to
  167. str reg2, [reg1]
  168. }
  169. RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
  170. begin
  171. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  172. if assigned(dealloc) then
  173. begin
  174. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  175. result:=true;
  176. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  177. and remove it if possible }
  178. asml.Remove(dealloc);
  179. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
  180. if assigned(alloc) then
  181. begin
  182. asml.Remove(alloc);
  183. alloc.free;
  184. dealloc.free;
  185. end
  186. else
  187. asml.InsertAfter(dealloc,p);
  188. { try to move the allocation of the target register }
  189. GetLastInstruction(movp,hp1);
  190. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  191. if assigned(alloc) then
  192. begin
  193. asml.Remove(alloc);
  194. asml.InsertBefore(alloc,p);
  195. { adjust used regs }
  196. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  197. end;
  198. { finally get rid of the mov }
  199. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  200. { Remove preindexing and postindexing for LDR in some cases.
  201. For example:
  202. ldr reg2,[reg1, xxx]!
  203. mov reg1,reg2
  204. must be translated to:
  205. ldr reg1,[reg1, xxx]
  206. Preindexing must be removed there, since the same register is used as the base and as the target.
  207. Such case is not allowed for ARM CPU and produces crash. }
  208. //if (taicpu(p).opcode = A_LDR) and (taicpu(p).oper[1]^.typ = top_ref)
  209. // and (taicpu(movp).oper[0]^.reg = taicpu(p).oper[1]^.ref^.base)
  210. //then
  211. // taicpu(p).oper[1]^.ref^.addressmode:=AM_OFFSET;
  212. asml.remove(movp);
  213. movp.free;
  214. end;
  215. end;
  216. end;
  217. begin
  218. casmoptimizer:=TCpuAsmOptimizer;
  219. End.