aoptcpu.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit implements the ARM 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. Interface
  21. uses cpubase, cgbase, aasmtai, aopt, aoptcpub;
  22. Type
  23. TCpuAsmOptimizer = class(TAsmOptimizer)
  24. Function GetNextInstructionUsingReg(Current: tai; Var Next: tai;reg : TRegister): Boolean;
  25. function RegInInstruction(Reg: TRegister; p1: tai): Boolean; override;
  26. { uses the same constructor as TAopObj }
  27. function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
  28. procedure PeepHoleOptPass2;override;
  29. End;
  30. Implementation
  31. uses
  32. cpuinfo,
  33. aasmbase,aasmcpu,
  34. globals,globtype,
  35. cgutils;
  36. function CanBeCond(p : tai) : boolean;
  37. begin
  38. result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
  39. end;
  40. function RefsEqual(const r1, r2: treference): boolean;
  41. begin
  42. refsequal :=
  43. (r1.offset = r2.offset) and
  44. (r1.base = r2.base) and
  45. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  46. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  47. (r1.relsymbol = r2.relsymbol) and
  48. (r1.addressmode = r2.addressmode);
  49. end;
  50. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  51. begin
  52. result:=oper1.typ=oper2.typ;
  53. if result then
  54. case oper1.typ of
  55. top_const:
  56. Result:=oper1.val = oper2.val;
  57. top_reg:
  58. Result:=oper1.reg = oper2.reg;
  59. top_ref:
  60. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  61. else Result:=false;
  62. end
  63. end;
  64. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  65. begin
  66. result := (oper.typ = top_reg) and (oper.reg = reg);
  67. end;
  68. function TCpuAsmOptimizer.RegInInstruction(Reg: TRegister; p1: tai): Boolean;
  69. begin
  70. If (p1.typ = ait_instruction) and (taicpu(p1).opcode in [A_MUL,A_MULS,A_FMUL,A_FMULS,A_FMULSU]) and
  71. ((getsupreg(reg)=RS_R0) or (getsupreg(reg)=RS_R1)) then
  72. Result:=true
  73. else
  74. Result:=inherited RegInInstruction(Reg, p1);
  75. end;
  76. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  77. var Next: tai; reg: TRegister): Boolean;
  78. begin
  79. Next:=Current;
  80. repeat
  81. Result:=GetNextInstruction(Next,Next);
  82. until not(cs_opt_level3 in current_settings.optimizerswitches) or not(Result) or (Next.typ<>ait_instruction) or (RegInInstruction(reg,Next)) or
  83. (is_calljmp(taicpu(Next).opcode));
  84. end;
  85. function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  86. var
  87. hp1,hp2,hp3: tai;
  88. alloc, dealloc: tai_regalloc;
  89. i: integer;
  90. begin
  91. result := false;
  92. case p.typ of
  93. ait_instruction:
  94. begin
  95. case taicpu(p).opcode of
  96. A_LDI:
  97. begin
  98. { turn
  99. ldi reg0, imm
  100. cp reg1, reg0
  101. dealloc reg0
  102. into
  103. cpi reg1, imm
  104. }
  105. if (taicpu(p).ops=2) and
  106. (taicpu(p).oper[0]^.typ=top_reg) and
  107. (taicpu(p).oper[1]^.typ=top_const) and
  108. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  109. (hp1.typ=ait_instruction) and
  110. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  111. (taicpu(hp1).opcode=A_CP) and
  112. (taicpu(hp1).ops=2) and
  113. (taicpu(hp1).oper[1]^.typ=top_reg) and
  114. (getsupreg(taicpu(hp1).oper[0]^.reg) in [16..31]) and
  115. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  116. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  117. begin
  118. taicpu(hp1).opcode:=A_CPI;
  119. taicpu(hp1).loadconst(1, taicpu(p).oper[1]^.val);
  120. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  121. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  122. if assigned(alloc) and assigned(dealloc) then
  123. begin
  124. asml.Remove(alloc);
  125. alloc.Free;
  126. asml.Remove(dealloc);
  127. dealloc.Free;
  128. end;
  129. GetNextInstruction(p,hp1);
  130. asml.Remove(p);
  131. p.Free;
  132. p:=hp1;
  133. result:=true;
  134. end;
  135. end;
  136. A_STS:
  137. if (taicpu(p).oper[0]^.ref^.symbol=nil) and
  138. (taicpu(p).oper[0]^.ref^.relsymbol=nil) and
  139. (getsupreg(taicpu(p).oper[0]^.ref^.base)=RS_NO) and
  140. (getsupreg(taicpu(p).oper[0]^.ref^.index)=RS_NO) and
  141. (taicpu(p).oper[0]^.ref^.addressmode=AM_UNCHANGED) and
  142. (taicpu(p).oper[0]^.ref^.offset>=32) and
  143. (taicpu(p).oper[0]^.ref^.offset<=95) then
  144. begin
  145. taicpu(p).opcode:=A_OUT;
  146. taicpu(p).loadconst(0,taicpu(p).oper[0]^.ref^.offset-32);
  147. end;
  148. A_LDS:
  149. if (taicpu(p).oper[1]^.ref^.symbol=nil) and
  150. (taicpu(p).oper[1]^.ref^.relsymbol=nil) and
  151. (getsupreg(taicpu(p).oper[1]^.ref^.base)=RS_NO) and
  152. (getsupreg(taicpu(p).oper[1]^.ref^.index)=RS_NO) and
  153. (taicpu(p).oper[1]^.ref^.addressmode=AM_UNCHANGED) and
  154. (taicpu(p).oper[1]^.ref^.offset>=32) and
  155. (taicpu(p).oper[1]^.ref^.offset<=95) then
  156. begin
  157. taicpu(p).opcode:=A_IN;
  158. taicpu(p).loadconst(1,taicpu(p).oper[1]^.ref^.offset-32);
  159. end;
  160. A_CLR:
  161. begin
  162. { turn the common
  163. clr rX
  164. mov/ld rX, rY
  165. into
  166. mov/ld rX, rY
  167. }
  168. if (taicpu(p).ops=1) and
  169. (taicpu(p).oper[0]^.typ=top_reg) and
  170. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  171. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  172. (hp1.typ=ait_instruction) and
  173. (taicpu(hp1).opcode in [A_MOV,A_LD]) and
  174. (taicpu(hp1).ops>0) and
  175. (taicpu(hp1).oper[0]^.typ=top_reg) and
  176. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then
  177. begin
  178. asml.Remove(p);
  179. p.Free;
  180. p:=hp1;
  181. result:=true;
  182. end
  183. { turn
  184. clr rX
  185. ...
  186. adc rY, rX
  187. into
  188. ...
  189. adc rY, r1
  190. }
  191. else if (taicpu(p).ops=1) and
  192. (taicpu(p).oper[0]^.typ=top_reg) and
  193. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  194. (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
  195. (hp1.typ=ait_instruction) and
  196. (taicpu(hp1).opcode in [A_ADC,A_SBC]) and
  197. (taicpu(hp1).ops=2) and
  198. (taicpu(hp1).oper[1]^.typ=top_reg) and
  199. (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
  200. (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and
  201. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  202. begin
  203. taicpu(hp1).oper[1]^.reg:=NR_R1;
  204. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  205. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  206. if assigned(alloc) and assigned(dealloc) then
  207. begin
  208. asml.Remove(alloc);
  209. alloc.Free;
  210. asml.Remove(dealloc);
  211. dealloc.Free;
  212. end;
  213. GetNextInstruction(p,hp1);
  214. asml.Remove(p);
  215. p.free;
  216. p:=hp1;
  217. result:=true;
  218. end;
  219. end;
  220. A_PUSH:
  221. begin
  222. { turn
  223. push reg0
  224. push reg1
  225. pop reg3
  226. pop reg2
  227. into
  228. movw reg2,reg0
  229. }
  230. if (taicpu(p).ops=1) and
  231. (taicpu(p).oper[0]^.typ=top_reg) and
  232. GetNextInstruction(p,hp1) and
  233. (hp1.typ=ait_instruction) and
  234. (taicpu(hp1).opcode=A_PUSH) and
  235. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  236. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  237. GetNextInstruction(hp1,hp2) and
  238. (hp2.typ=ait_instruction) and
  239. (taicpu(hp2).opcode=A_POP) and
  240. GetNextInstruction(hp2,hp3) and
  241. (hp3.typ=ait_instruction) and
  242. (taicpu(hp3).opcode=A_POP) and
  243. (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and
  244. ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then
  245. begin
  246. taicpu(p).ops:=2;
  247. taicpu(p).opcode:=A_MOVW;
  248. taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
  249. taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg);
  250. asml.Remove(hp1);
  251. hp1.Free;
  252. asml.Remove(hp2);
  253. hp2.Free;
  254. asml.Remove(hp3);
  255. hp3.Free;
  256. result:=true;
  257. end;
  258. end;
  259. A_MOV:
  260. begin
  261. { turn
  262. mov reg0, reg1
  263. push reg0
  264. dealloc reg0
  265. into
  266. push reg1
  267. }
  268. if (taicpu(p).ops=2) and
  269. (taicpu(p).oper[0]^.typ = top_reg) and
  270. (taicpu(p).oper[1]^.typ = top_reg) and
  271. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  272. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and
  273. (hp1.typ = ait_instruction) and
  274. (taicpu(hp1).opcode in [A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_EOR,A_AND,A_OR]) and
  275. RegInInstruction(taicpu(p).oper[0]^.reg, hp1) and
  276. (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
  277. {(taicpu(hp1).ops=1) and
  278. (taicpu(hp1).oper[0]^.typ = top_reg) and
  279. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and }
  280. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  281. begin
  282. for i := 0 to taicpu(hp1).ops-1 do
  283. if taicpu(hp1).oper[i]^.typ=top_reg then
  284. if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then
  285. taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg;
  286. alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
  287. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  288. if assigned(alloc) and assigned(dealloc) then
  289. begin
  290. asml.Remove(alloc);
  291. alloc.Free;
  292. asml.Remove(dealloc);
  293. dealloc.Free;
  294. end;
  295. GetNextInstruction(p,hp1);
  296. asml.Remove(p);
  297. p.free;
  298. p:=hp1;
  299. result:=true;
  300. end
  301. { remove
  302. mov reg0,reg0
  303. }
  304. else if (taicpu(p).ops=2) and
  305. (taicpu(p).oper[0]^.typ = top_reg) and
  306. (taicpu(p).oper[1]^.typ = top_reg) and
  307. (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then
  308. begin
  309. GetNextInstruction(p,hp1);
  310. asml.remove(p);
  311. p.free;
  312. p:=hp1;
  313. result:=true;
  314. end
  315. { fold
  316. mov reg2,reg0
  317. mov reg3,reg1
  318. to
  319. movw reg2,reg0
  320. }
  321. else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and
  322. (taicpu(p).ops=2) and
  323. (taicpu(p).oper[0]^.typ = top_reg) and
  324. (taicpu(p).oper[1]^.typ = top_reg) and
  325. getnextinstruction(p,hp1) and
  326. (hp1.typ = ait_instruction) and
  327. (taicpu(hp1).opcode = A_MOV) and
  328. (taicpu(hp1).ops=2) and
  329. (taicpu(hp1).oper[0]^.typ = top_reg) and
  330. (taicpu(hp1).oper[1]^.typ = top_reg) and
  331. (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and
  332. ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and
  333. ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and
  334. (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then
  335. begin
  336. alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous));
  337. if assigned(alloc) then
  338. begin
  339. asml.Remove(alloc);
  340. asml.InsertBefore(alloc,p);
  341. end;
  342. taicpu(p).opcode:=A_MOVW;
  343. asml.remove(hp1);
  344. hp1.free;
  345. result:=true;
  346. end
  347. {
  348. This removes the first mov from
  349. mov rX,...
  350. mov rX,...
  351. }
  352. else if taicpu(hp1).opcode=A_MOV then
  353. while (hp1.typ=ait_instruction) and (taicpu(hp1).opcode=A_MOV) and
  354. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  355. { don't remove the first mov if the second is a mov rX,rX }
  356. not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do
  357. begin
  358. asml.remove(p);
  359. p.free;
  360. p:=hp1;
  361. GetNextInstruction(hp1,hp1);
  362. result:=true;
  363. if not assigned(hp1) then
  364. break;
  365. end;
  366. end;
  367. end;
  368. end;
  369. end;
  370. end;
  371. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  372. begin
  373. end;
  374. begin
  375. casmoptimizer:=TCpuAsmOptimizer;
  376. End.