aoptcpu.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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; const postfix: TOpPostfixes): boolean;
  73. begin
  74. result :=
  75. (instr.typ = ait_instruction) and
  76. (taicpu(instr).opcode = op) and
  77. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  78. end;
  79. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  80. begin
  81. result := (oper.typ = top_reg) and (oper.reg = reg);
  82. end;
  83. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  84. begin
  85. result := oper1.typ = oper2.typ;
  86. if result then
  87. case oper1.typ of
  88. top_const:
  89. Result:=oper1.val = oper2.val;
  90. top_reg:
  91. Result:=oper1.reg = oper2.reg;
  92. top_ref:
  93. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  94. else Result:=false;
  95. end
  96. end;
  97. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  98. Out Next: tai; reg: TRegister): Boolean;
  99. begin
  100. Next:=Current;
  101. repeat
  102. Result:=GetNextInstruction(Next,Next);
  103. until not (Result) or
  104. not(cs_opt_level3 in current_settings.optimizerswitches) or
  105. (Next.typ<>ait_instruction) or
  106. RegInInstruction(reg,Next) or
  107. is_calljmp(taicpu(Next).opcode);
  108. end;
  109. function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  110. var
  111. p: taicpu;
  112. begin
  113. p := taicpu(hp);
  114. Result := false;
  115. if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
  116. exit;
  117. end;
  118. function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  119. var
  120. p: taicpu;
  121. i: longint;
  122. begin
  123. instructionLoadsFromReg := false;
  124. if not (assigned(hp) and (hp.typ = ait_instruction)) then
  125. exit;
  126. p:=taicpu(hp);
  127. i:=1;
  128. { Start on oper[0]? }
  129. if taicpu(hp).spilling_get_operation_type(0) in [operand_read, operand_readwrite] then
  130. i:=0;
  131. while(i<p.ops) do
  132. begin
  133. case p.oper[I]^.typ of
  134. top_reg:
  135. Result := (p.oper[I]^.reg = reg);
  136. top_ref:
  137. Result :=
  138. (p.oper[I]^.ref^.base = reg) or
  139. (p.oper[I]^.ref^.index = reg);
  140. else
  141. ;
  142. end;
  143. { Bailout if we found something }
  144. if Result then
  145. exit;
  146. Inc(I);
  147. end;
  148. end;
  149. function TCpuAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
  150. var
  151. alloc,
  152. dealloc : tai_regalloc;
  153. hp1 : tai;
  154. begin
  155. Result:=false;
  156. if MatchInstruction(movp, A_MOV, [PF_None,PF_N]) and
  157. (taicpu(p).ops>=3) and
  158. { We can't optimize if there is a shiftop }
  159. (taicpu(movp).ops=2) and
  160. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  161. { the destination register of the mov might not be used beween p and movp }
  162. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  163. { Take care to only do this for instructions which REALLY load to the first register.
  164. Otherwise
  165. str reg0, [reg1]
  166. mov reg2, reg0
  167. will be optimized to
  168. str reg2, [reg1]
  169. }
  170. RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
  171. begin
  172. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  173. if assigned(dealloc) then
  174. begin
  175. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  176. result:=true;
  177. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  178. and remove it if possible }
  179. asml.Remove(dealloc);
  180. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
  181. if assigned(alloc) then
  182. begin
  183. asml.Remove(alloc);
  184. alloc.free;
  185. dealloc.free;
  186. end
  187. else
  188. asml.InsertAfter(dealloc,p);
  189. { try to move the allocation of the target register }
  190. GetLastInstruction(movp,hp1);
  191. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  192. if assigned(alloc) then
  193. begin
  194. asml.Remove(alloc);
  195. asml.InsertBefore(alloc,p);
  196. { adjust used regs }
  197. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  198. end;
  199. { finally get rid of the mov }
  200. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  201. { Remove preindexing and postindexing for LDR in some cases.
  202. For example:
  203. ldr reg2,[reg1, xxx]!
  204. mov reg1,reg2
  205. must be translated to:
  206. ldr reg1,[reg1, xxx]
  207. Preindexing must be removed there, since the same register is used as the base and as the target.
  208. Such case is not allowed for ARM CPU and produces crash. }
  209. //if (taicpu(p).opcode = A_LDR) and (taicpu(p).oper[1]^.typ = top_ref)
  210. // and (taicpu(movp).oper[0]^.reg = taicpu(p).oper[1]^.ref^.base)
  211. //then
  212. // taicpu(p).oper[1]^.ref^.addressmode:=AM_OFFSET;
  213. asml.remove(movp);
  214. movp.free;
  215. end;
  216. end;
  217. end;
  218. begin
  219. casmoptimizer:=TCpuAsmOptimizer;
  220. End.