rgcpu.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. {
  2. Copyright (c) 1998-2003 by Florian Klaempfl
  3. This unit implements the arm specific class for the register
  4. allocator
  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 rgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. aasmbase,aasmtai,aasmdata,aasmcpu,
  23. cgbase,cgutils,
  24. cpubase,
  25. {$ifdef DEBUG_SPILLING}
  26. cutils,
  27. {$endif}
  28. rgobj;
  29. type
  30. trgcpu = class(trgobj)
  31. private
  32. procedure spilling_create_load_store(list: TAsmList; pos: tai; const spilltemp:treference;tempreg:tregister; is_store: boolean);
  33. public
  34. procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  35. procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  36. procedure add_constraints(reg:tregister);override;
  37. function get_spill_subreg(r:tregister) : tsubregister;override;
  38. end;
  39. trgcputhumb2 = class(trgobj)
  40. private
  41. procedure SplitITBlock(list:TAsmList;pos:tai);
  42. public
  43. procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  44. procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  45. end;
  46. trgintcputhumb2 = class(trgcputhumb2)
  47. procedure add_cpu_interferences(p : tai);override;
  48. end;
  49. trgintcpu = class(trgcpu)
  50. procedure add_cpu_interferences(p : tai);override;
  51. end;
  52. implementation
  53. uses
  54. verbose,globtype,globals,cpuinfo,
  55. cgobj,
  56. procinfo;
  57. procedure trgintcputhumb2.add_cpu_interferences(p: tai);
  58. var
  59. r : tregister;
  60. hr : longint;
  61. begin
  62. if p.typ=ait_instruction then
  63. begin
  64. case taicpu(p).opcode of
  65. A_CBNZ,
  66. A_CBZ:
  67. begin
  68. for hr := RS_R8 to RS_R15 do
  69. add_edge(getsupreg(taicpu(p).oper[0]^.reg), hr);
  70. end;
  71. A_ADD:
  72. begin
  73. if taicpu(p).ops = 3 then
  74. begin
  75. if (taicpu(p).oper[0]^.typ = top_reg) and
  76. (taicpu(p).oper[1]^.typ = top_reg) and
  77. (taicpu(p).oper[2]^.typ in [top_reg, top_shifterop]) then
  78. begin
  79. { if d == 13 || (d == 15 && S == ‘0’) || n == 15 || m IN [13,15] then UNPREDICTABLE; }
  80. add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R13);
  81. if taicpu(p).oppostfix <> PF_S then
  82. add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R15);
  83. add_edge(getsupreg(taicpu(p).oper[1]^.reg), RS_R15);
  84. if (taicpu(p).oper[2]^.typ = top_shifterop) and
  85. (taicpu(p).oper[2]^.shifterop^.rs <> NR_NO) then
  86. begin
  87. add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R13);
  88. add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R15);
  89. end
  90. else if (taicpu(p).oper[2]^.typ = top_reg) then
  91. begin
  92. add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R13);
  93. add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R15);
  94. end;
  95. end;
  96. end;
  97. end;
  98. A_LDRB,
  99. A_STRB,
  100. A_STR,
  101. A_LDR,
  102. A_LDRH,
  103. A_STRH,
  104. A_LDRSB,
  105. A_LDRSH,
  106. A_LDRD,
  107. A_STRD:
  108. { don't mix up the framepointer and stackpointer with pre/post indexed operations }
  109. if (taicpu(p).oper[1]^.typ=top_ref) and
  110. (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
  111. begin
  112. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(current_procinfo.framepointer));
  113. { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
  114. { while compiling the compiler. }
  115. r:=NR_STACK_POINTER_REG;
  116. if current_procinfo.framepointer<>r then
  117. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(r));
  118. end;
  119. end;
  120. end;
  121. end;
  122. procedure trgcpu.spilling_create_load_store(list: TAsmList; pos: tai; const spilltemp:treference;tempreg:tregister; is_store: boolean);
  123. var
  124. tmpref : treference;
  125. helplist : TAsmList;
  126. l : tasmlabel;
  127. hreg : tregister;
  128. immshift: byte;
  129. a: aint;
  130. begin
  131. helplist:=TAsmList.create;
  132. { load consts entry }
  133. if getregtype(tempreg)=R_INTREGISTER then
  134. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  135. else
  136. hreg:=cg.getintregister(helplist,OS_ADDR);
  137. { Lets remove the bits we can fold in later and check if the result can be easily with an add or sub }
  138. a:=abs(spilltemp.offset);
  139. if is_shifter_const(a and not($FFF), immshift) then
  140. if spilltemp.offset > 0 then
  141. begin
  142. {$ifdef DEBUG_SPILLING}
  143. helplist.concat(tai_comment.create(strpnew('Spilling: Use ADD to fix spill offset')));
  144. {$endif}
  145. helplist.concat(taicpu.op_reg_reg_const(A_ADD, hreg, current_procinfo.framepointer,
  146. a and not($FFF)));
  147. reference_reset_base(tmpref, hreg, a and $FFF, sizeof(aint));
  148. end
  149. else
  150. begin
  151. {$ifdef DEBUG_SPILLING}
  152. helplist.concat(tai_comment.create(strpnew('Spilling: Use SUB to fix spill offset')));
  153. {$endif}
  154. helplist.concat(taicpu.op_reg_reg_const(A_SUB, hreg, current_procinfo.framepointer,
  155. a and not($FFF)));
  156. reference_reset_base(tmpref, hreg, -(a and $FFF), sizeof(aint));
  157. end
  158. else
  159. begin
  160. {$ifdef DEBUG_SPILLING}
  161. helplist.concat(tai_comment.create(strpnew('Spilling: Use a_load_const_reg to fix spill offset')));
  162. {$endif}
  163. cg.a_load_const_reg(helplist,OS_ADDR,spilltemp.offset,hreg);
  164. reference_reset_base(tmpref,current_procinfo.framepointer,0,sizeof(aint));
  165. tmpref.index:=hreg;
  166. end;
  167. if spilltemp.index<>NR_NO then
  168. internalerror(200401263);
  169. if is_store then
  170. helplist.concat(spilling_create_store(tempreg,tmpref))
  171. else
  172. helplist.concat(spilling_create_load(tmpref,tempreg));
  173. if getregtype(tempreg)=R_INTREGISTER then
  174. ungetregisterinline(helplist,hreg);
  175. list.insertlistafter(pos,helplist);
  176. helplist.free;
  177. end;
  178. procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  179. begin
  180. { don't load spilled register between
  181. mov lr,pc
  182. mov pc,r4
  183. but befure the mov lr,pc
  184. }
  185. if assigned(pos.previous) and
  186. (pos.typ=ait_instruction) and
  187. (taicpu(pos).opcode=A_MOV) and
  188. (taicpu(pos).oper[0]^.typ=top_reg) and
  189. (taicpu(pos).oper[0]^.reg=NR_R14) and
  190. (taicpu(pos).oper[1]^.typ=top_reg) and
  191. (taicpu(pos).oper[1]^.reg=NR_PC) then
  192. pos:=tai(pos.previous);
  193. if abs(spilltemp.offset)>4095 then
  194. spilling_create_load_store(list, pos, spilltemp, tempreg, false)
  195. else
  196. inherited do_spill_read(list,pos,spilltemp,tempreg);
  197. end;
  198. procedure trgcpu.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  199. begin
  200. if abs(spilltemp.offset)>4095 then
  201. spilling_create_load_store(list, pos, spilltemp, tempreg, true)
  202. else
  203. inherited do_spill_written(list,pos,spilltemp,tempreg);
  204. end;
  205. procedure trgcpu.add_constraints(reg:tregister);
  206. var
  207. supreg,i : Tsuperregister;
  208. begin
  209. case getsubreg(reg) of
  210. { Let 32bit floats conflict with all double precision regs > 15
  211. (since these don't have 32 bit equivalents) }
  212. R_SUBFS:
  213. begin
  214. supreg:=getsupreg(reg);
  215. for i:=RS_D16 to RS_D31 do
  216. add_edge(supreg,i);
  217. end;
  218. end;
  219. end;
  220. function trgcpu.get_spill_subreg(r:tregister) : tsubregister;
  221. begin
  222. if (getregtype(r)<>R_MMREGISTER) then
  223. result:=defaultsub
  224. else
  225. result:=getsubreg(r);
  226. end;
  227. function GetITRemainderOp(originalOp:TAsmOp;remLevels:longint;var newOp: TAsmOp;var NeedsCondSwap:boolean) : TAsmOp;
  228. const
  229. remOps : array[1..3] of array[A_ITE..A_ITTTT] of TAsmOp = (
  230. (A_IT,A_IT, A_IT,A_IT,A_IT,A_IT, A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT),
  231. (A_NONE,A_NONE, A_ITT,A_ITE,A_ITE,A_ITT, A_ITT,A_ITT,A_ITE,A_ITE,A_ITE,A_ITE,A_ITT,A_ITT),
  232. (A_NONE,A_NONE, A_NONE,A_NONE,A_NONE,A_NONE, A_ITTT,A_ITEE,A_ITET,A_ITTE,A_ITTE,A_ITET,A_ITEE,A_ITTT));
  233. newOps : array[1..3] of array[A_ITE..A_ITTTT] of TAsmOp = (
  234. (A_IT,A_IT, A_ITE,A_ITT,A_ITE,A_ITT, A_ITEE,A_ITTE,A_ITET,A_ITTT,A_ITEE,A_ITTE,A_ITET,A_ITTT),
  235. (A_NONE,A_NONE, A_IT,A_IT,A_IT,A_IT, A_ITE,A_ITT,A_ITE,A_ITT,A_ITE,A_ITT,A_ITE,A_ITT),
  236. (A_NONE,A_NONE, A_NONE,A_NONE,A_NONE,A_NONE, A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT));
  237. needsSwap: array[1..3] of array[A_ITE..A_ITTTT] of Boolean = (
  238. (true ,false, true ,true ,false,false, true ,true ,true ,true ,false,false,false,false),
  239. (false,false, true ,false,true ,false, true ,true ,false,false,true ,true ,false,false),
  240. (false,false, false,false,false,false, true ,false,true ,false,true ,false,true ,false));
  241. begin
  242. result:=remOps[remLevels][originalOp];
  243. newOp:=newOps[remLevels][originalOp];
  244. NeedsCondSwap:=needsSwap[remLevels][originalOp];
  245. end;
  246. procedure trgcputhumb2.SplitITBlock(list: TAsmList; pos: tai);
  247. var
  248. hp : tai;
  249. level,itLevel : LongInt;
  250. remOp,newOp : TAsmOp;
  251. needsSwap : boolean;
  252. begin
  253. hp:=pos;
  254. level := 0;
  255. while assigned(hp) do
  256. begin
  257. if IsIT(taicpu(hp).opcode) then
  258. break
  259. else if hp.typ=ait_instruction then
  260. inc(level);
  261. hp:=tai(hp.Previous);
  262. end;
  263. if not assigned(hp) then
  264. internalerror(2012100801); // We are supposed to have found the ITxxx instruction here
  265. if (hp.typ<>ait_instruction) or
  266. (not IsIT(taicpu(hp).opcode)) then
  267. internalerror(2012100802); // Sanity check
  268. itLevel := GetITLevels(taicpu(hp).opcode);
  269. if level=itLevel then
  270. exit; // pos was the last instruction in the IT block anyway
  271. remOp:=GetITRemainderOp(taicpu(hp).opcode,itLevel-level,newOp,needsSwap);
  272. if (remOp=A_NONE) or
  273. (newOp=A_NONE) then
  274. Internalerror(2012100803);
  275. taicpu(hp).opcode:=newOp;
  276. if needsSwap then
  277. list.InsertAfter(taicpu.op_cond(remOp,inverse_cond(taicpu(hp).oper[0]^.cc)), pos)
  278. else
  279. list.InsertAfter(taicpu.op_cond(remOp,taicpu(hp).oper[0]^.cc), pos);
  280. end;
  281. procedure trgcputhumb2.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  282. var
  283. tmpref : treference;
  284. helplist : TAsmList;
  285. l : tasmlabel;
  286. hreg : tregister;
  287. begin
  288. { don't load spilled register between
  289. mov lr,pc
  290. mov pc,r4
  291. but befure the mov lr,pc
  292. }
  293. if assigned(pos.previous) and
  294. (pos.typ=ait_instruction) and
  295. (taicpu(pos).opcode=A_MOV) and
  296. (taicpu(pos).oper[0]^.typ=top_reg) and
  297. (taicpu(pos).oper[0]^.reg=NR_R14) and
  298. (taicpu(pos).oper[1]^.typ=top_reg) and
  299. (taicpu(pos).oper[1]^.reg=NR_PC) then
  300. pos:=tai(pos.previous);
  301. if (pos.typ=ait_instruction) and
  302. (taicpu(pos).condition<>C_None) and
  303. (taicpu(pos).opcode<>A_B) then
  304. SplitITBlock(list, pos)
  305. else if (pos.typ=ait_instruction) and
  306. IsIT(taicpu(pos).opcode) then
  307. begin
  308. if not assigned(pos.Previous) then
  309. list.InsertBefore(tai_comment.Create('Dummy'), pos);
  310. pos:=tai(pos.Previous);
  311. end;
  312. if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
  313. begin
  314. helplist:=TAsmList.create;
  315. reference_reset(tmpref,sizeof(aint));
  316. { create consts entry }
  317. current_asmdata.getjumplabel(l);
  318. cg.a_label(current_procinfo.aktlocaldata,l);
  319. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  320. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(spilltemp.offset));
  321. { load consts entry }
  322. if getregtype(tempreg)=R_INTREGISTER then
  323. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  324. else
  325. hreg:=cg.getintregister(helplist,OS_ADDR);
  326. tmpref.symbol:=l;
  327. tmpref.base:=NR_R15;
  328. helplist.concat(taicpu.op_reg_ref(A_LDR,hreg,tmpref));
  329. reference_reset_base(tmpref,current_procinfo.framepointer,0,sizeof(aint));
  330. tmpref.index:=hreg;
  331. if spilltemp.index<>NR_NO then
  332. internalerror(200401263);
  333. helplist.concat(spilling_create_load(tmpref,tempreg));
  334. if getregtype(tempreg)=R_INTREGISTER then
  335. ungetregisterinline(helplist,hreg);
  336. list.insertlistafter(pos,helplist);
  337. helplist.free;
  338. end
  339. else
  340. inherited do_spill_read(list,pos,spilltemp,tempreg);
  341. end;
  342. procedure trgcputhumb2.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  343. var
  344. tmpref : treference;
  345. helplist : TAsmList;
  346. l : tasmlabel;
  347. hreg : tregister;
  348. begin
  349. if (pos.typ=ait_instruction) and
  350. (taicpu(pos).condition<>C_None) and
  351. (taicpu(pos).opcode<>A_B) then
  352. SplitITBlock(list, pos)
  353. else if (pos.typ=ait_instruction) and
  354. IsIT(taicpu(pos).opcode) then
  355. begin
  356. if not assigned(pos.Previous) then
  357. list.InsertBefore(tai_comment.Create('Dummy'), pos);
  358. pos:=tai(pos.Previous);
  359. end;
  360. if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
  361. begin
  362. helplist:=TAsmList.create;
  363. reference_reset(tmpref,sizeof(aint));
  364. { create consts entry }
  365. current_asmdata.getjumplabel(l);
  366. cg.a_label(current_procinfo.aktlocaldata,l);
  367. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  368. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(spilltemp.offset));
  369. { load consts entry }
  370. if getregtype(tempreg)=R_INTREGISTER then
  371. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  372. else
  373. hreg:=cg.getintregister(helplist,OS_ADDR);
  374. tmpref.symbol:=l;
  375. tmpref.base:=NR_R15;
  376. helplist.concat(taicpu.op_reg_ref(A_LDR,hreg,tmpref));
  377. if spilltemp.index<>NR_NO then
  378. internalerror(200401263);
  379. reference_reset_base(tmpref,current_procinfo.framepointer,0,sizeof(pint));
  380. tmpref.index:=hreg;
  381. helplist.concat(spilling_create_store(tempreg,tmpref));
  382. if getregtype(tempreg)=R_INTREGISTER then
  383. ungetregisterinline(helplist,hreg);
  384. list.insertlistafter(pos,helplist);
  385. helplist.free;
  386. end
  387. else
  388. inherited do_spill_written(list,pos,spilltemp,tempreg);
  389. end;
  390. procedure trgintcpu.add_cpu_interferences(p : tai);
  391. var
  392. r : tregister;
  393. begin
  394. if p.typ=ait_instruction then
  395. begin
  396. case taicpu(p).opcode of
  397. A_MLA,
  398. A_MUL:
  399. if current_settings.cputype<cpu_armv6 then
  400. add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
  401. A_UMULL,
  402. A_UMLAL,
  403. A_SMULL,
  404. A_SMLAL:
  405. begin
  406. add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
  407. add_edge(getsupreg(taicpu(p).oper[1]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
  408. add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
  409. end;
  410. A_LDRB,
  411. A_STRB,
  412. A_STR,
  413. A_LDR,
  414. A_LDRH,
  415. A_STRH:
  416. { don't mix up the framepointer and stackpointer with pre/post indexed operations }
  417. if (taicpu(p).oper[1]^.typ=top_ref) and
  418. (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
  419. begin
  420. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(current_procinfo.framepointer));
  421. { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
  422. { while compiling the compiler. }
  423. r:=NR_STACK_POINTER_REG;
  424. if current_procinfo.framepointer<>r then
  425. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(r));
  426. end;
  427. end;
  428. end;
  429. end;
  430. end.