aoptcpu.pas 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. { uses the same constructor as TAopObj }
  29. function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;override;
  30. function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;override;
  31. function GetNextInstructionUsingReg(Current : tai; out Next : tai; reg : TRegister) : Boolean;
  32. procedure DebugMsg(const s : string; p : tai);
  33. private
  34. function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
  35. End;
  36. Implementation
  37. uses
  38. aasmbase,
  39. aoptutils,
  40. cgutils,
  41. verbose;
  42. {$ifdef DEBUG_AOPTCPU}
  43. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
  44. begin
  45. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  46. end;
  47. {$else DEBUG_AOPTCPU}
  48. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  49. begin
  50. end;
  51. {$endif DEBUG_AOPTCPU}
  52. function CanBeCond(p : tai) : boolean;
  53. begin
  54. result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
  55. end;
  56. function RefsEqual(const r1, r2: treference): boolean;
  57. begin
  58. refsequal :=
  59. (r1.offset = r2.offset) and
  60. (r1.base = r2.base) and
  61. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  62. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  63. (r1.relsymbol = r2.relsymbol) and
  64. (r1.volatility=[]) and
  65. (r2.volatility=[]);
  66. end;
  67. function MatchInstruction(const instr: tai; const op: TAsmOp): boolean;
  68. begin
  69. result :=
  70. (instr.typ = ait_instruction) and
  71. (taicpu(instr).opcode = op);
  72. end;
  73. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  74. begin
  75. result := (oper.typ = top_reg) and (oper.reg = reg);
  76. end;
  77. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  78. begin
  79. result := oper1.typ = oper2.typ;
  80. if result then
  81. case oper1.typ of
  82. top_const:
  83. Result:=oper1.val = oper2.val;
  84. top_reg:
  85. Result:=oper1.reg = oper2.reg;
  86. top_ref:
  87. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  88. else Result:=false;
  89. end
  90. end;
  91. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  92. Out Next: tai; reg: TRegister): Boolean;
  93. begin
  94. Next:=Current;
  95. repeat
  96. Result:=GetNextInstruction(Next,Next);
  97. until not (Result) or
  98. not(cs_opt_level3 in current_settings.optimizerswitches) or
  99. (Next.typ<>ait_instruction) or
  100. RegInInstruction(reg,Next) or
  101. is_calljmp(taicpu(Next).opcode);
  102. end;
  103. function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  104. var
  105. p: taicpu;
  106. begin
  107. p := taicpu(hp);
  108. Result := false;
  109. if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
  110. exit;
  111. end;
  112. function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  113. var
  114. p: taicpu;
  115. i: longint;
  116. begin
  117. instructionLoadsFromReg := false;
  118. if not (assigned(hp) and (hp.typ = ait_instruction)) then
  119. exit;
  120. p:=taicpu(hp);
  121. i:=1;
  122. { Start on oper[0]? }
  123. if taicpu(hp).spilling_get_operation_type(0) in [operand_read, operand_readwrite] then
  124. i:=0;
  125. while(i<p.ops) do
  126. begin
  127. case p.oper[I]^.typ of
  128. top_reg:
  129. Result := (p.oper[I]^.reg = reg);
  130. top_ref:
  131. Result :=
  132. (p.oper[I]^.ref^.base = reg) or
  133. (p.oper[I]^.ref^.index = reg);
  134. else
  135. ;
  136. end;
  137. { Bailout if we found something }
  138. if Result then
  139. exit;
  140. Inc(I);
  141. end;
  142. end;
  143. function TCpuAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
  144. var
  145. alloc,
  146. dealloc : tai_regalloc;
  147. hp1 : tai;
  148. begin
  149. Result:=false;
  150. if MatchInstruction(movp, A_MOV) and
  151. (taicpu(p).ops>=3) and
  152. { We can't optimize if there is a shiftop }
  153. (taicpu(movp).ops=2) and
  154. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  155. { the destination register of the mov might not be used beween p and movp }
  156. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  157. { Take care to only do this for instructions which REALLY load to the first register.
  158. Otherwise
  159. str reg0, [reg1]
  160. mov reg2, reg0
  161. will be optimized to
  162. str reg2, [reg1]
  163. }
  164. RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
  165. begin
  166. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  167. if assigned(dealloc) then
  168. begin
  169. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  170. result:=true;
  171. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  172. and remove it if possible }
  173. asml.Remove(dealloc);
  174. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
  175. if assigned(alloc) then
  176. begin
  177. asml.Remove(alloc);
  178. alloc.free;
  179. dealloc.free;
  180. end
  181. else
  182. asml.InsertAfter(dealloc,p);
  183. { try to move the allocation of the target register }
  184. GetLastInstruction(movp,hp1);
  185. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  186. if assigned(alloc) then
  187. begin
  188. asml.Remove(alloc);
  189. asml.InsertBefore(alloc,p);
  190. { adjust used regs }
  191. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  192. end;
  193. { finally get rid of the mov }
  194. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  195. { Remove preindexing and postindexing for LDR in some cases.
  196. For example:
  197. ldr reg2,[reg1, xxx]!
  198. mov reg1,reg2
  199. must be translated to:
  200. ldr reg1,[reg1, xxx]
  201. Preindexing must be removed there, since the same register is used as the base and as the target.
  202. Such case is not allowed for ARM CPU and produces crash. }
  203. //if (taicpu(p).opcode = A_LDR) and (taicpu(p).oper[1]^.typ = top_ref)
  204. // and (taicpu(movp).oper[0]^.reg = taicpu(p).oper[1]^.ref^.base)
  205. //then
  206. // taicpu(p).oper[1]^.ref^.addressmode:=AM_OFFSET;
  207. asml.remove(movp);
  208. movp.free;
  209. end;
  210. end;
  211. end;
  212. begin
  213. casmoptimizer:=TCpuAsmOptimizer;
  214. End.