rgcpu.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. rgobj;
  26. type
  27. trgcpu = class(trgobj)
  28. private
  29. procedure spilling_create_load_store(list: TAsmList; pos: tai; const spilltemp:treference;tempreg:tregister; is_store: boolean);
  30. public
  31. procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  32. procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  33. procedure add_constraints(reg:tregister);override;
  34. function get_spill_subreg(r:tregister) : tsubregister;override;
  35. end;
  36. trgcputhumb2 = class(trgobj)
  37. procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  38. procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
  39. end;
  40. trgintcputhumb2 = class(trgcputhumb2)
  41. procedure add_cpu_interferences(p : tai);override;
  42. end;
  43. trgintcpu = class(trgcpu)
  44. procedure add_cpu_interferences(p : tai);override;
  45. end;
  46. implementation
  47. uses
  48. verbose, cutils,globtype,globals,cpuinfo,
  49. cgobj,
  50. procinfo;
  51. procedure trgintcputhumb2.add_cpu_interferences(p: tai);
  52. var
  53. r : tregister;
  54. begin
  55. if p.typ=ait_instruction then
  56. begin
  57. case taicpu(p).opcode of
  58. A_ADD:
  59. begin
  60. if taicpu(p).ops = 3 then
  61. begin
  62. if (taicpu(p).oper[0]^.typ = top_reg) and
  63. (taicpu(p).oper[1]^.typ = top_reg) and
  64. (taicpu(p).oper[2]^.typ in [top_reg, top_shifterop]) then
  65. begin
  66. { if d == 13 || (d == 15 && S == ‘0’) || n == 15 || m IN [13,15] then UNPREDICTABLE; }
  67. add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R13);
  68. if taicpu(p).oppostfix <> PF_S then
  69. add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R15);
  70. add_edge(getsupreg(taicpu(p).oper[1]^.reg), RS_R15);
  71. if (taicpu(p).oper[2]^.typ = top_shifterop) and
  72. (taicpu(p).oper[2]^.shifterop^.rs <> NR_NO) then
  73. begin
  74. add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R13);
  75. add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R15);
  76. end
  77. else if (taicpu(p).oper[2]^.typ = top_reg) then
  78. begin
  79. add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R13);
  80. add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R15);
  81. end;
  82. end;
  83. end;
  84. end;
  85. A_LDRB,
  86. A_STRB,
  87. A_STR,
  88. A_LDR,
  89. A_LDRH,
  90. A_STRH,
  91. A_LDRSB,
  92. A_LDRSH,
  93. A_LDRD,
  94. A_STRD:
  95. { don't mix up the framepointer and stackpointer with pre/post indexed operations }
  96. if (taicpu(p).oper[1]^.typ=top_ref) and
  97. (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
  98. begin
  99. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(current_procinfo.framepointer));
  100. { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
  101. { while compiling the compiler. }
  102. r:=NR_STACK_POINTER_REG;
  103. if current_procinfo.framepointer<>r then
  104. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(r));
  105. end;
  106. end;
  107. end;
  108. end;
  109. procedure trgcpu.spilling_create_load_store(list: TAsmList; pos: tai; const spilltemp:treference;tempreg:tregister; is_store: boolean);
  110. var
  111. tmpref : treference;
  112. helplist : TAsmList;
  113. l : tasmlabel;
  114. hreg : tregister;
  115. immshift: byte;
  116. a: aint;
  117. begin
  118. helplist:=TAsmList.create;
  119. { load consts entry }
  120. if getregtype(tempreg)=R_INTREGISTER then
  121. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  122. else
  123. hreg:=cg.getintregister(helplist,OS_ADDR);
  124. { Lets remove the bits we can fold in later and check if the result can be easily with an add or sub }
  125. a:=abs(spilltemp.offset);
  126. if is_shifter_const(a and not($FFF), immshift) then
  127. if spilltemp.offset > 0 then
  128. begin
  129. {$ifdef DEBUG_SPILLING}
  130. helplist.concat(tai_comment.create(strpnew('Spilling: Use ADD to fix spill offset')));
  131. {$endif}
  132. helplist.concat(taicpu.op_reg_reg_const(A_ADD, hreg, current_procinfo.framepointer,
  133. a and not($FFF)));
  134. reference_reset_base(tmpref, hreg, a and $FFF, sizeof(aint));
  135. end
  136. else
  137. begin
  138. {$ifdef DEBUG_SPILLING}
  139. helplist.concat(tai_comment.create(strpnew('Spilling: Use SUB to fix spill offset')));
  140. {$endif}
  141. helplist.concat(taicpu.op_reg_reg_const(A_SUB, hreg, current_procinfo.framepointer,
  142. a and not($FFF)));
  143. reference_reset_base(tmpref, hreg, -(a and $FFF), sizeof(aint));
  144. end
  145. else
  146. begin
  147. {$ifdef DEBUG_SPILLING}
  148. helplist.concat(tai_comment.create(strpnew('Spilling: Use a_load_const_reg to fix spill offset')));
  149. {$endif}
  150. cg.a_load_const_reg(helplist,OS_ADDR,spilltemp.offset,hreg);
  151. reference_reset_base(tmpref,current_procinfo.framepointer,0,sizeof(aint));
  152. tmpref.index:=hreg;
  153. end;
  154. if spilltemp.index<>NR_NO then
  155. internalerror(200401263);
  156. if is_store then
  157. helplist.concat(spilling_create_store(tempreg,tmpref))
  158. else
  159. helplist.concat(spilling_create_load(tmpref,tempreg));
  160. if getregtype(tempreg)=R_INTREGISTER then
  161. ungetregisterinline(helplist,hreg);
  162. list.insertlistafter(pos,helplist);
  163. helplist.free;
  164. end;
  165. procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  166. begin
  167. { don't load spilled register between
  168. mov lr,pc
  169. mov pc,r4
  170. but befure the mov lr,pc
  171. }
  172. if assigned(pos.previous) and
  173. (pos.typ=ait_instruction) and
  174. (taicpu(pos).opcode=A_MOV) and
  175. (taicpu(pos).oper[0]^.typ=top_reg) and
  176. (taicpu(pos).oper[0]^.reg=NR_R14) and
  177. (taicpu(pos).oper[1]^.typ=top_reg) and
  178. (taicpu(pos).oper[1]^.reg=NR_PC) then
  179. pos:=tai(pos.previous);
  180. if abs(spilltemp.offset)>4095 then
  181. spilling_create_load_store(list, pos, spilltemp, tempreg, false)
  182. else
  183. inherited do_spill_read(list,pos,spilltemp,tempreg);
  184. end;
  185. procedure trgcpu.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  186. begin
  187. if abs(spilltemp.offset)>4095 then
  188. spilling_create_load_store(list, pos, spilltemp, tempreg, true)
  189. else
  190. inherited do_spill_written(list,pos,spilltemp,tempreg);
  191. end;
  192. procedure trgcpu.add_constraints(reg:tregister);
  193. var
  194. supreg,i : Tsuperregister;
  195. begin
  196. case getsubreg(reg) of
  197. { Let 32bit floats conflict with all double precision regs > 15
  198. (since these don't have 32 bit equivalents) }
  199. R_SUBFS:
  200. begin
  201. supreg:=getsupreg(reg);
  202. for i:=RS_D16 to RS_D31 do
  203. add_edge(supreg,i);
  204. end;
  205. end;
  206. end;
  207. function trgcpu.get_spill_subreg(r:tregister) : tsubregister;
  208. begin
  209. if (getregtype(r)<>R_MMREGISTER) then
  210. result:=defaultsub
  211. else
  212. result:=getsubreg(r);
  213. end;
  214. procedure trgcputhumb2.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  215. var
  216. tmpref : treference;
  217. helplist : TAsmList;
  218. l : tasmlabel;
  219. hreg : tregister;
  220. begin
  221. { don't load spilled register between
  222. mov lr,pc
  223. mov pc,r4
  224. but befure the mov lr,pc
  225. }
  226. if assigned(pos.previous) and
  227. (pos.typ=ait_instruction) and
  228. (taicpu(pos).opcode=A_MOV) and
  229. (taicpu(pos).oper[0]^.typ=top_reg) and
  230. (taicpu(pos).oper[0]^.reg=NR_R14) and
  231. (taicpu(pos).oper[1]^.typ=top_reg) and
  232. (taicpu(pos).oper[1]^.reg=NR_PC) then
  233. pos:=tai(pos.previous);
  234. if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
  235. begin
  236. helplist:=TAsmList.create;
  237. reference_reset(tmpref,sizeof(aint));
  238. { create consts entry }
  239. current_asmdata.getjumplabel(l);
  240. cg.a_label(current_procinfo.aktlocaldata,l);
  241. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  242. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(spilltemp.offset));
  243. { load consts entry }
  244. if getregtype(tempreg)=R_INTREGISTER then
  245. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  246. else
  247. hreg:=cg.getintregister(helplist,OS_ADDR);
  248. tmpref.symbol:=l;
  249. tmpref.base:=NR_R15;
  250. helplist.concat(taicpu.op_reg_ref(A_LDR,hreg,tmpref));
  251. reference_reset_base(tmpref,current_procinfo.framepointer,0,sizeof(aint));
  252. tmpref.index:=hreg;
  253. if spilltemp.index<>NR_NO then
  254. internalerror(200401263);
  255. helplist.concat(spilling_create_load(tmpref,tempreg));
  256. if getregtype(tempreg)=R_INTREGISTER then
  257. ungetregisterinline(helplist,hreg);
  258. list.insertlistafter(pos,helplist);
  259. helplist.free;
  260. end
  261. else
  262. inherited do_spill_read(list,pos,spilltemp,tempreg);
  263. end;
  264. procedure trgcputhumb2.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
  265. var
  266. tmpref : treference;
  267. helplist : TAsmList;
  268. l : tasmlabel;
  269. hreg : tregister;
  270. begin
  271. if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
  272. begin
  273. helplist:=TAsmList.create;
  274. reference_reset(tmpref,sizeof(aint));
  275. { create consts entry }
  276. current_asmdata.getjumplabel(l);
  277. cg.a_label(current_procinfo.aktlocaldata,l);
  278. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  279. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(spilltemp.offset));
  280. { load consts entry }
  281. if getregtype(tempreg)=R_INTREGISTER then
  282. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  283. else
  284. hreg:=cg.getintregister(helplist,OS_ADDR);
  285. tmpref.symbol:=l;
  286. tmpref.base:=NR_R15;
  287. helplist.concat(taicpu.op_reg_ref(A_LDR,hreg,tmpref));
  288. if spilltemp.index<>NR_NO then
  289. internalerror(200401263);
  290. reference_reset_base(tmpref,current_procinfo.framepointer,0,sizeof(pint));
  291. tmpref.index:=hreg;
  292. helplist.concat(spilling_create_store(tempreg,tmpref));
  293. if getregtype(tempreg)=R_INTREGISTER then
  294. ungetregisterinline(helplist,hreg);
  295. list.insertlistafter(pos,helplist);
  296. helplist.free;
  297. end
  298. else
  299. inherited do_spill_written(list,pos,spilltemp,tempreg);
  300. end;
  301. procedure trgintcpu.add_cpu_interferences(p : tai);
  302. var
  303. r : tregister;
  304. begin
  305. if p.typ=ait_instruction then
  306. begin
  307. case taicpu(p).opcode of
  308. A_MLA,
  309. A_MUL:
  310. if current_settings.cputype<cpu_armv6 then
  311. add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
  312. A_UMULL,
  313. A_UMLAL,
  314. A_SMULL,
  315. A_SMLAL:
  316. begin
  317. add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
  318. add_edge(getsupreg(taicpu(p).oper[1]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
  319. add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
  320. end;
  321. A_LDRB,
  322. A_STRB,
  323. A_STR,
  324. A_LDR,
  325. A_LDRH,
  326. A_STRH:
  327. { don't mix up the framepointer and stackpointer with pre/post indexed operations }
  328. if (taicpu(p).oper[1]^.typ=top_ref) and
  329. (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
  330. begin
  331. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(current_procinfo.framepointer));
  332. { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
  333. { while compiling the compiler. }
  334. r:=NR_STACK_POINTER_REG;
  335. if current_procinfo.framepointer<>r then
  336. add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(r));
  337. end;
  338. end;
  339. end;
  340. end;
  341. end.