2
0

aoptcpurv.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit implements the common RiscV 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 aoptcpurv;
  19. interface
  20. {$I fpcdefs.inc}
  21. {$define DEBUG_AOPTCPU}
  22. uses
  23. cpubase,
  24. globals, globtype,
  25. cgbase,
  26. aoptobj, aoptcpub, aopt,
  27. aasmtai, aasmcpu;
  28. type
  29. TRVCpuAsmOptimizer = class(TAsmOptimizer)
  30. function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean; override;
  31. function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean; override;
  32. function RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
  33. Function GetNextInstructionUsingReg(Current: tai; Out Next: tai; reg: TRegister): Boolean;
  34. { outputs a debug message into the assembler file }
  35. procedure DebugMsg(const s: string; p: tai);
  36. function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
  37. end;
  38. implementation
  39. uses
  40. cutils;
  41. function MatchInstruction(const instr: tai; const op: TAsmOps; const AConditions: TAsmConds = []): boolean;
  42. begin
  43. result :=
  44. (instr.typ = ait_instruction) and
  45. (taicpu(instr).opcode in op) and
  46. ((AConditions=[]) or (taicpu(instr).condition in AConditions));
  47. end;
  48. function MatchInstruction(const instr: tai; const op: TAsmOp; const AConditions: TAsmConds = []): boolean;
  49. begin
  50. result :=
  51. (instr.typ = ait_instruction) and
  52. (taicpu(instr).opcode = op) and
  53. ((AConditions=[]) or (taicpu(instr).condition in AConditions));
  54. end;
  55. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  56. begin
  57. result := oper1.typ = oper2.typ;
  58. if result then
  59. case oper1.typ of
  60. top_const:
  61. Result:=oper1.val = oper2.val;
  62. top_reg:
  63. Result:=oper1.reg = oper2.reg;
  64. {top_ref:
  65. Result:=RefsEqual(oper1.ref^, oper2.ref^);}
  66. else Result:=false;
  67. end
  68. end;
  69. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  70. begin
  71. result := (oper.typ = top_reg) and (oper.reg = reg);
  72. end;
  73. {$ifdef DEBUG_AOPTCPU}
  74. procedure TRVCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
  75. begin
  76. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  77. end;
  78. {$else DEBUG_AOPTCPU}
  79. procedure TRVCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  80. begin
  81. end;
  82. {$endif DEBUG_AOPTCPU}
  83. function TRVCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  84. var
  85. p: taicpu;
  86. i: longint;
  87. begin
  88. result:=false;
  89. if not (assigned(hp) and (hp.typ=ait_instruction)) then
  90. exit;
  91. p:=taicpu(hp);
  92. i:=0;
  93. while(i<p.ops) do
  94. begin
  95. case p.oper[I]^.typ of
  96. top_reg:
  97. result:=(p.oper[I]^.reg=reg) and (p.spilling_get_operation_type(i)<>operand_write);
  98. top_ref:
  99. result:=
  100. (p.oper[I]^.ref^.base=reg);
  101. else
  102. ;
  103. end;
  104. if result then exit; {Bailout if we found something}
  105. Inc(I);
  106. end;
  107. end;
  108. function TRVCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  109. begin
  110. result:=
  111. (hp.typ=ait_instruction) and
  112. (taicpu(hp).ops>1) and
  113. (taicpu(hp).oper[0]^.typ=top_reg) and
  114. (taicpu(hp).oper[0]^.reg=reg) and
  115. (taicpu(hp).spilling_get_operation_type(0)<>operand_read);
  116. end;
  117. function TRVCpuAsmOptimizer.RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean;
  118. var
  119. i : Longint;
  120. begin
  121. result:=false;
  122. for i:=0 to taicpu(p1).ops-1 do
  123. case taicpu(p1).oper[i]^.typ of
  124. top_reg:
  125. if (taicpu(p1).oper[i]^.reg=Reg) and (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then
  126. exit(true);
  127. else
  128. ;
  129. end;
  130. end;
  131. function TRVCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai; out Next: tai; reg: TRegister): Boolean;
  132. begin
  133. Next:=Current;
  134. repeat
  135. Result:=GetNextInstruction(Next,Next);
  136. until not (Result) or
  137. not(cs_opt_level3 in current_settings.optimizerswitches) or
  138. (Next.typ<>ait_instruction) or
  139. RegInInstruction(reg,Next) or
  140. is_calljmp(taicpu(Next).opcode);
  141. end;
  142. function TRVCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  143. procedure RemoveInstr(var orig: tai; moveback: boolean = true);
  144. var
  145. n: tai;
  146. begin
  147. if moveback and (not GetLastInstruction(orig,n)) then
  148. GetNextInstruction(orig,n);
  149. AsmL.Remove(orig);
  150. orig.Free;
  151. orig:=n;
  152. end;
  153. var
  154. hp1: tai;
  155. begin
  156. result:=false;
  157. case p.typ of
  158. ait_instruction:
  159. begin
  160. case taicpu(p).opcode of
  161. A_ADDI:
  162. begin
  163. {
  164. Changes
  165. addi x, y, #
  166. addi/addiw z, x, #
  167. dealloc x
  168. To
  169. addi z, y, #+#
  170. }
  171. if (taicpu(p).ops=3) and
  172. (taicpu(p).oper[2]^.typ=top_const) and
  173. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  174. MatchInstruction(hp1,[A_ADDI{$ifdef riscv64},A_ADDIW{$endif}]) and
  175. (taicpu(hp1).ops=3) and
  176. MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^) and
  177. (taicpu(p).oper[2]^.typ=top_const) and
  178. is_imm12(taicpu(p).oper[2]^.val+taicpu(hp1).oper[2]^.val) and
  179. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  180. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  181. begin
  182. taicpu(hp1).loadreg(1,taicpu(p).oper[1]^.reg);
  183. taicpu(hp1).loadconst(2, taicpu(p).oper[2]^.val+taicpu(hp1).oper[2]^.val);
  184. DebugMsg('Peephole AddiAddi2Addi performed', hp1);
  185. RemoveInstr(p);
  186. result:=true;
  187. end
  188. {
  189. Changes
  190. addi x, z, (ref)
  191. ld/sd y, 0(x)
  192. dealloc x
  193. To
  194. ld/sd y, 0(ref)(x)
  195. }
  196. else if (taicpu(p).ops=3) and
  197. (taicpu(p).oper[2]^.typ=top_ref) and
  198. MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) and
  199. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  200. MatchInstruction(hp1, [A_LB,A_LBU,A_LH,A_LHU,A_LW,
  201. A_SB,A_SH,A_SW{$ifdef riscv64},A_LD,A_LWU,A_SD{$endif}]) and
  202. (taicpu(hp1).ops=2) and
  203. (taicpu(hp1).oper[1]^.typ=top_ref) and
  204. (taicpu(hp1).oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
  205. (taicpu(hp1).oper[1]^.ref^.offset=0) and
  206. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  207. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  208. begin
  209. taicpu(hp1).loadref(1,taicpu(p).oper[2]^.ref^);
  210. taicpu(hp1).oper[1]^.ref^.base:=taicpu(p).oper[1]^.reg;
  211. DebugMsg('Peephole AddiMem2Mem performed', hp1);
  212. RemoveInstr(p);
  213. result:=true;
  214. end
  215. {
  216. Changes
  217. addi x, z, #w
  218. ld/sd y, 0(x)
  219. dealloc x
  220. To
  221. ld/sd y, #w(z)
  222. }
  223. else if (taicpu(p).ops=3) and
  224. (taicpu(p).oper[2]^.typ=top_const) and
  225. //MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) and
  226. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  227. MatchInstruction(hp1, [A_LB,A_LBU,A_LH,A_LHU,A_LW,
  228. A_SB,A_SH,A_SW{$ifdef riscv64},A_LWU,A_LD,A_SD{$endif}]) and
  229. (taicpu(hp1).ops=2) and
  230. (taicpu(hp1).oper[1]^.typ=top_ref) and
  231. (taicpu(hp1).oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
  232. (taicpu(hp1).oper[1]^.ref^.offset=0) and
  233. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  234. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  235. begin
  236. //taicpu(hp1).loadconst(1,taicpu(p).oper[2]^.ref^);
  237. taicpu(hp1).oper[1]^.ref^.offset:=taicpu(p).oper[2]^.val;
  238. taicpu(hp1).oper[1]^.ref^.base:=taicpu(p).oper[1]^.reg;
  239. DebugMsg('Peephole AddiMem2Mem performed', hp1);
  240. RemoveInstr(p);
  241. result:=true;
  242. end;
  243. end;
  244. A_SUB:
  245. begin
  246. {
  247. Turn
  248. sub x,y,z
  249. bgeu X0,x,...
  250. dealloc x
  251. Into
  252. bne y,x,...
  253. }
  254. if (taicpu(p).ops=3) and
  255. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  256. MatchInstruction(hp1,A_Bxx,[C_GEU,C_EQ]) and
  257. (taicpu(hp1).ops=3) and
  258. MatchOperand(taicpu(hp1).oper[0]^,NR_X0) and
  259. MatchOperand(taicpu(hp1).oper[1]^,taicpu(p).oper[0]^) and
  260. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  261. (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
  262. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  263. begin
  264. taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
  265. taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
  266. taicpu(hp1).condition:=C_EQ;
  267. DebugMsg('Peephole SubBxx2Beq performed', hp1);
  268. RemoveInstr(p);
  269. result:=true;
  270. end;
  271. end;
  272. A_SLT,
  273. A_SLTU:
  274. begin
  275. {
  276. Turn
  277. sltu x,X0,y
  278. beq/bne x, X0, ...
  279. dealloc x
  280. Into
  281. bltu/geu X0, y, ...
  282. }
  283. if (taicpu(p).ops=3) and
  284. MatchOperand(taicpu(p).oper[1]^,NR_X0) and
  285. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  286. MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
  287. (taicpu(hp1).ops=3) and
  288. MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
  289. MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
  290. (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
  291. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  292. begin
  293. taicpu(hp1).loadreg(0,NR_X0);
  294. taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
  295. if taicpu(p).opcode=A_SLTU then
  296. begin
  297. if taicpu(hp1).condition=C_NE then
  298. taicpu(hp1).condition:=C_LTU
  299. else
  300. taicpu(hp1).condition:=C_GEU;
  301. end
  302. else
  303. begin
  304. if taicpu(hp1).condition=C_NE then
  305. taicpu(hp1).condition:=C_LT
  306. else
  307. taicpu(hp1).condition:=C_GE;
  308. end;
  309. DebugMsg('Peephole SltuB2B performed', hp1);
  310. RemoveInstr(p);
  311. result:=true;
  312. end
  313. {
  314. Turn
  315. sltu x,y,z
  316. beq/bne x, X0, ...
  317. dealloc x
  318. Into
  319. bltu/geu y, z, ...
  320. }
  321. else if (taicpu(p).ops=3) and
  322. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  323. MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
  324. (taicpu(hp1).ops=3) and
  325. MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
  326. MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
  327. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  328. (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
  329. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  330. begin
  331. taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
  332. taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
  333. if taicpu(p).opcode=A_SLTU then
  334. begin
  335. if taicpu(hp1).condition=C_NE then
  336. taicpu(hp1).condition:=C_LTU
  337. else
  338. taicpu(hp1).condition:=C_GEU;
  339. end
  340. else
  341. begin
  342. if taicpu(hp1).condition=C_NE then
  343. taicpu(hp1).condition:=C_LT
  344. else
  345. taicpu(hp1).condition:=C_GE;
  346. end;
  347. DebugMsg('Peephole SltuB2B performed', hp1);
  348. RemoveInstr(p);
  349. result:=true;
  350. end;
  351. end;
  352. A_SLTIU:
  353. begin
  354. {
  355. Turn
  356. sltiu x,y,1
  357. beq/ne x,x0,...
  358. dealloc x
  359. Into
  360. bne y,x0,...
  361. }
  362. if (taicpu(p).ops=3) and
  363. (taicpu(p).oper[2]^.typ=top_const) and
  364. (taicpu(p).oper[2]^.val=1) and
  365. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  366. MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
  367. (taicpu(hp1).ops=3) and
  368. MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
  369. MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
  370. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  371. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  372. begin
  373. taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
  374. taicpu(hp1).condition:=inverse_cond(taicpu(hp1).condition);
  375. DebugMsg('Peephole Sltiu0B2B performed', hp1);
  376. RemoveInstr(p);
  377. result:=true;
  378. end;
  379. end;
  380. A_SLTI:
  381. begin
  382. {
  383. Turn
  384. slti x,y,0
  385. beq/ne x,x0,...
  386. dealloc x
  387. Into
  388. bge/lt y,x0,...
  389. }
  390. if (taicpu(p).ops=3) and
  391. (taicpu(p).oper[2]^.typ=top_const) and
  392. (taicpu(p).oper[2]^.val=0) and
  393. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
  394. (hp1.typ=ait_instruction) and
  395. (taicpu(hp1).opcode=A_Bxx) and
  396. (taicpu(hp1).ops=3) and
  397. (taicpu(hp1).oper[0]^.typ=top_reg) and
  398. (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
  399. (taicpu(hp1).oper[1]^.typ=top_reg) and
  400. (taicpu(hp1).oper[1]^.reg=NR_X0) and
  401. (taicpu(hp1).condition in [C_NE,C_EQ]) and
  402. (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
  403. RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
  404. begin
  405. taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
  406. taicpu(hp1).loadreg(1,NR_X0);
  407. if taicpu(hp1).condition=C_NE then
  408. taicpu(hp1).condition:=C_LT
  409. else
  410. taicpu(hp1).condition:=C_GE;
  411. DebugMsg('Peephole Slti0B2B performed', hp1);
  412. RemoveInstr(p);
  413. result:=true;
  414. end;
  415. end;
  416. else
  417. ;
  418. end;
  419. end;
  420. else
  421. ;
  422. end;
  423. end;
  424. end.