regvars.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl and Jonas Maebe
  4. This unit handles register variable allocation
  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 regvars;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. aasm,
  23. node,
  24. symsym,
  25. cpubase;
  26. procedure assign_regvars(p: tnode);
  27. procedure load_regvars(asml: TAAsmoutput; p: tnode);
  28. procedure cleanup_regvars(asml: TAAsmoutput);
  29. procedure store_regvar(asml: TAAsmoutput; reg: tregister);
  30. procedure load_regvar(asml: TAAsmoutput; vsym: tvarsym);
  31. procedure load_regvar_reg(asml: TAAsmoutput; reg: tregister);
  32. procedure load_all_regvars(asml: TAAsmoutput);
  33. implementation
  34. uses
  35. globtype,systems,comphook,
  36. cutils,cclasses,verbose,globals,
  37. symconst,symbase,symtype,symdef,types,
  38. cgbase,cpuasm,tgcpu,cgobj,cgcpu,cga;
  39. var
  40. parasym : boolean;
  41. procedure searchregvars(p : tnamedindexitem);
  42. var
  43. i,j,k : longint;
  44. begin
  45. if (tsym(p).typ=varsym) and (vo_regable in tvarsym(p).varoptions) then
  46. begin
  47. j:=tvarsym(p).refs;
  48. { parameter get a less value }
  49. if parasym then
  50. begin
  51. if cs_littlesize in aktglobalswitches then
  52. dec(j,1)
  53. else
  54. dec(j,100);
  55. end;
  56. { walk through all momentary register variables }
  57. for i:=1 to maxvarregs do
  58. begin
  59. with pregvarinfo(aktprocdef.regvarinfo)^ do
  60. if ((regvars[i]=nil) or (j>regvars_refs[i])) and (j>0) then
  61. begin
  62. for k:=maxvarregs-1 downto i do
  63. begin
  64. regvars[k+1]:=regvars[k];
  65. regvars_para[k+1]:=regvars_para[k];
  66. regvars_refs[k+1]:=regvars_refs[k];
  67. end;
  68. { calc the new refs
  69. tvarsym(p).refs:=j; }
  70. regvars[i]:=tvarsym(p);
  71. regvars_para[i]:=parasym;
  72. regvars_refs[i]:=j;
  73. break;
  74. end;
  75. end;
  76. end;
  77. end;
  78. procedure searchfpuregvars(p : tnamedindexitem);
  79. var
  80. i,j,k : longint;
  81. begin
  82. if (tsym(p).typ=varsym) and (vo_fpuregable in tvarsym(p).varoptions) then
  83. begin
  84. j:=tvarsym(p).refs;
  85. { parameter get a less value }
  86. if parasym then
  87. begin
  88. if cs_littlesize in aktglobalswitches then
  89. dec(j,1)
  90. else
  91. dec(j,100);
  92. end;
  93. { walk through all momentary register variables }
  94. for i:=1 to maxfpuvarregs do
  95. begin
  96. with pregvarinfo(aktprocdef.regvarinfo)^ do
  97. if ((fpuregvars[i]=nil) or (j>fpuregvars_refs[i])) and (j>0) then
  98. begin
  99. for k:=maxfpuvarregs-1 downto i do
  100. begin
  101. fpuregvars[k+1]:=fpuregvars[k];
  102. fpuregvars_para[k+1]:=fpuregvars_para[k];
  103. fpuregvars_refs[k+1]:=fpuregvars_refs[k];
  104. end;
  105. { calc the new refs
  106. tvarsym(p).refs:=j; }
  107. fpuregvars[i]:=tvarsym(p);
  108. fpuregvars_para[i]:=parasym;
  109. fpuregvars_refs[i]:=j;
  110. break;
  111. end;
  112. end;
  113. end;
  114. end;
  115. procedure assign_regvars(p: tnode);
  116. { register variables }
  117. var
  118. regvarinfo: pregvarinfo;
  119. i: longint;
  120. begin
  121. { max. optimizations }
  122. { only if no asm is used }
  123. { and no try statement }
  124. if (cs_regalloc in aktglobalswitches) and
  125. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  126. begin
  127. new(regvarinfo);
  128. fillchar(regvarinfo^,sizeof(regvarinfo^),0);
  129. aktprocdef.regvarinfo := regvarinfo;
  130. if (p.registers32<4) then
  131. begin
  132. parasym:=false;
  133. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  134. { copy parameter into a register ? }
  135. parasym:=true;
  136. symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  137. { hold needed registers free }
  138. for i:=maxvarregs downto maxvarregs-p.registers32+1 do
  139. begin
  140. regvarinfo^.regvars[i]:=nil;
  141. regvarinfo^.regvars_para[i] := false;
  142. end;
  143. { now assign register }
  144. for i:=1 to maxvarregs-p.registers32 do
  145. begin
  146. if assigned(regvarinfo^.regvars[i]) and
  147. (reg_pushes[varregs[i]] < regvarinfo^.regvars[i].refs) then
  148. begin
  149. { register is no longer available for }
  150. { expressions }
  151. { search the register which is the most }
  152. { unused }
  153. usableregs:=usableregs-[varregs[i]];
  154. is_reg_var[varregs[i]]:=true;
  155. dec(c_usableregs);
  156. { possibly no 32 bit register are needed }
  157. { call by reference/const ? }
  158. if (regvarinfo^.regvars[i].varspez in [vs_var,vs_out]) or
  159. ((regvarinfo^.regvars[i].varspez=vs_const) and
  160. push_addr_param(regvarinfo^.regvars[i].vartype.def)) then
  161. begin
  162. regvarinfo^.regvars[i].reg:=varregs[i];
  163. end
  164. else
  165. {$ifdef i386}
  166. if (regvarinfo^.regvars[i].vartype.def.deftype in [orddef,enumdef]) and
  167. (torddef(regvarinfo^.regvars[i].vartype.def).size=1) then
  168. begin
  169. regvarinfo^.regvars[i].reg:=reg32toreg8(varregs[i]);
  170. end
  171. else
  172. if (regvarinfo^.regvars[i].vartype.def.deftype in [orddef,enumdef]) and
  173. (torddef(regvarinfo^.regvars[i].vartype.def).size=2) then
  174. begin
  175. regvarinfo^.regvars[i].reg:=reg32toreg16(varregs[i]);
  176. end
  177. else
  178. {$endif i386}
  179. begin
  180. regvarinfo^.regvars[i].reg:=varregs[i];
  181. end;
  182. if regvarinfo^.regvars_para[i] then
  183. unused:=unused - [regvarinfo^.regvars[i].reg];
  184. { procedure uses this register }
  185. {$ifdef i386}
  186. usedinproc:=usedinproc or ($80 shr byte(varregs[i]));
  187. {$else i386}
  188. usedinproc:=usedinproc + [varregs[i]];
  189. {$endif i386}
  190. end
  191. else
  192. begin
  193. regvarinfo^.regvars[i] := nil;
  194. regvarinfo^.regvars_para[i] := false;
  195. end;
  196. end;
  197. end;
  198. if ((p.registersfpu+1)<maxfpuvarregs) then
  199. begin
  200. parasym:=false;
  201. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchfpuregvars);
  202. {$ifdef dummy}
  203. { copy parameter into a register ? }
  204. parasym:=true;
  205. symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  206. {$endif dummy}
  207. { hold needed registers free }
  208. { in non leaf procedures we must be very careful }
  209. { with assigning registers }
  210. if aktmaxfpuregisters=-1 then
  211. begin
  212. if (procinfo^.flags and pi_do_call)<>0 then
  213. begin
  214. for i:=maxfpuvarregs downto 2 do
  215. regvarinfo^.fpuregvars[i]:=nil;
  216. end
  217. else
  218. begin
  219. for i:=maxfpuvarregs downto maxfpuvarregs-p.registersfpu do
  220. regvarinfo^.fpuregvars[i]:=nil;
  221. end;
  222. end
  223. else
  224. begin
  225. for i:=aktmaxfpuregisters+1 to maxfpuvarregs do
  226. regvarinfo^.fpuregvars[i]:=nil;
  227. end;
  228. { now assign register }
  229. for i:=1 to maxfpuvarregs do
  230. begin
  231. if assigned(regvarinfo^.fpuregvars[i]) then
  232. begin
  233. {$ifdef i386}
  234. { reserve place on the FPU stack }
  235. regvarinfo^.fpuregvars[i].reg:=correct_fpuregister(R_ST0,i-1);
  236. {$else i386}
  237. regvarinfo^.fpuregvars[i].reg:=fpuvarregs[i];
  238. {$endif i386}
  239. end;
  240. end;
  241. end;
  242. end;
  243. end;
  244. procedure store_regvar(asml: TAAsmoutput; reg: tregister);
  245. var
  246. i: longint;
  247. hr: treference;
  248. regvarinfo: pregvarinfo;
  249. vsym: tvarsym;
  250. begin
  251. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  252. if not assigned(regvarinfo) then
  253. exit;
  254. for i := 1 to maxvarregs do
  255. if assigned(regvarinfo^.regvars[i]) and
  256. (makereg32(regvarinfo^.regvars[i].reg) = reg) then
  257. begin
  258. if regvar_loaded[makereg32(reg)] then
  259. begin
  260. vsym := tvarsym(regvarinfo^.regvars[i]);
  261. { we only have to store the regvar back to memory if it's }
  262. { possible that it's been modified (JM) }
  263. if not(vsym.varspez in [vs_const,vs_var,vs_out]) then
  264. begin
  265. reset_reference(hr);
  266. if vsym.owner.symtabletype in [inlinelocalsymtable,localsymtable] then
  267. hr.offset:=-vsym.address+vsym.owner.address_fixup
  268. else hr.offset:=vsym.address+vsym.owner.address_fixup;
  269. hr.base:=procinfo^.framepointer;
  270. cg.a_load_reg_ref(exprasmlist,def_cgsize(vsym.vartype.def),vsym.reg,hr);
  271. { asml.concat(Taicpu.op_reg_ref(A_MOV,regsize(vsym.reg),vsym.reg,hr)); }
  272. end;
  273. asml.concat(Tairegalloc.dealloc(makereg32(reg)));
  274. regvar_loaded[makereg32(reg)] := false;
  275. end;
  276. break;
  277. end;
  278. end;
  279. procedure load_regvar(asml: TAAsmoutput; vsym: tvarsym);
  280. var
  281. hr: treference;
  282. opsize: tcgsize;
  283. begin
  284. if not regvar_loaded[makereg32(vsym.reg)] then
  285. begin
  286. asml.concat(Tairegalloc.alloc(makereg32(vsym.reg)));
  287. reset_reference(hr);
  288. if vsym.owner.symtabletype in [inlinelocalsymtable,localsymtable] then
  289. hr.offset:=-vsym.address+vsym.owner.address_fixup
  290. else hr.offset:=vsym.address+vsym.owner.address_fixup;
  291. hr.base:=procinfo^.framepointer;
  292. if (vsym.varspez in [vs_var,vs_out]) or
  293. ((vsym.varspez=vs_const) and
  294. push_addr_param(vsym.vartype.def)) then
  295. {FIXME!!! Needs to be OS_SIZE_OF_POINTER (JM) }
  296. opsize := OS_32
  297. else
  298. opsize := def_cgsize(vsym.vartype.def);
  299. cg.a_load_ref_reg(exprasmlist,opsize,hr,makereg32(vsym.reg));
  300. { asml.concat(Taicpu.op_ref_reg(opcode,opsize,hr,makereg32(vsym.reg))); }
  301. regvar_loaded[makereg32(vsym.reg)] := true;
  302. end;
  303. end;
  304. procedure load_regvar_reg(asml: TAAsmoutput; reg: tregister);
  305. var
  306. i: longint;
  307. regvarinfo: pregvarinfo;
  308. begin
  309. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  310. if not assigned(regvarinfo) then
  311. exit;
  312. reg := makereg32(reg);
  313. for i := 1 to maxvarregs do
  314. if assigned(regvarinfo^.regvars[i]) and
  315. (makereg32(regvarinfo^.regvars[i].reg) = reg) then
  316. load_regvar(asml,tvarsym(regvarinfo^.regvars[i]))
  317. end;
  318. procedure load_all_regvars(asml: TAAsmoutput);
  319. var
  320. i: longint;
  321. regvarinfo: pregvarinfo;
  322. begin
  323. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  324. if not assigned(regvarinfo) then
  325. exit;
  326. for i := 1 to maxvarregs do
  327. if assigned(regvarinfo^.regvars[i]) and
  328. (makereg32(regvarinfo^.regvars[i].reg) in [R_EAX,R_EBX,R_ECX,R_EDX]) then
  329. load_regvar(asml,tvarsym(regvarinfo^.regvars[i]))
  330. end;
  331. procedure load_regvars(asml: TAAsmoutput; p: tnode);
  332. var
  333. i: longint;
  334. regvarinfo: pregvarinfo;
  335. begin
  336. if (cs_regalloc in aktglobalswitches) and
  337. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  338. begin
  339. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  340. { can happen when inlining assembler procedures (JM) }
  341. if not assigned(regvarinfo) then
  342. exit;
  343. for i:=1 to maxvarregs do
  344. begin
  345. if assigned(regvarinfo^.regvars[i]) then
  346. begin
  347. if cs_asm_source in aktglobalswitches then
  348. asml.insert(Tai_asm_comment.Create(strpnew(regvarinfo^.regvars[i].name+
  349. ' with weight '+tostr(regvarinfo^.regvars[i].refs)+' assigned to register '+
  350. reg2str(regvarinfo^.regvars[i].reg))));
  351. if (status.verbosity and v_debug)=v_debug then
  352. Message3(cg_d_register_weight,reg2str(regvarinfo^.regvars[i].reg),
  353. tostr(regvarinfo^.regvars[i].refs),regvarinfo^.regvars[i].name);
  354. end;
  355. end;
  356. for i:=1 to maxfpuvarregs do
  357. begin
  358. if assigned(regvarinfo^.fpuregvars[i]) then
  359. begin
  360. {$ifdef i386}
  361. { reserve place on the FPU stack }
  362. regvarinfo^.fpuregvars[i].reg:=correct_fpuregister(R_ST0,i-1);
  363. asml.concat(Taicpu.op_none(A_FLDZ,S_NO));
  364. {$endif i386}
  365. end;
  366. end;
  367. {$ifdef i386}
  368. if assigned(p) then
  369. if cs_asm_source in aktglobalswitches then
  370. asml.insert(Tai_asm_comment.Create(strpnew(tostr(p.registersfpu)+
  371. ' registers on FPU stack used by temp. expressions')));
  372. {$endif i386}
  373. for i:=1 to maxfpuvarregs do
  374. begin
  375. if assigned(regvarinfo^.fpuregvars[i]) then
  376. begin
  377. if cs_asm_source in aktglobalswitches then
  378. asml.insert(Tai_asm_comment.Create(strpnew(regvarinfo^.fpuregvars[i].name+
  379. ' with weight '+tostr(regvarinfo^.fpuregvars[i].refs)+' assigned to register '+
  380. reg2str(regvarinfo^.fpuregvars[i].reg))));
  381. if (status.verbosity and v_debug)=v_debug then
  382. Message3(cg_d_register_weight,reg2str(regvarinfo^.fpuregvars[i].reg),
  383. tostr(regvarinfo^.fpuregvars[i].refs),regvarinfo^.fpuregvars[i].name);
  384. end;
  385. end;
  386. if cs_asm_source in aktglobalswitches then
  387. asml.insert(Tai_asm_comment.Create(strpnew('Register variable assignment:')));
  388. end;
  389. end;
  390. procedure cleanup_regvars(asml: TAAsmoutput);
  391. var
  392. i: longint;
  393. begin
  394. { can happen when inlining assembler procedures (JM) }
  395. if not assigned(aktprocdef.regvarinfo) then
  396. exit;
  397. if (cs_regalloc in aktglobalswitches) and
  398. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  399. with pregvarinfo(aktprocdef.regvarinfo)^ do
  400. begin
  401. {$ifdef i386}
  402. for i:=1 to maxfpuvarregs do
  403. if assigned(fpuregvars[i]) then
  404. { ... and clean it up }
  405. asml.concat(Taicpu.op_reg(A_FSTP,S_NO,R_ST0));
  406. {$endif i386}
  407. for i := 1 to maxvarregs do
  408. if assigned(regvars[i]) and
  409. (regvar_loaded[makereg32(regvars[i].reg)]) then
  410. asml.concat(Tairegalloc.dealloc(makereg32(regvars[i].reg)));
  411. end;
  412. end;
  413. end.
  414. {
  415. $Log$
  416. Revision 1.20 2001-11-05 16:49:32 jonas
  417. * constant regvars (addresses of var/out para's and const para's) aren't
  418. saved to memory anymore when their register will be destroyed
  419. * unit has been made mostly processor independent
  420. Revision 1.19 2001/11/02 22:58:06 peter
  421. * procsym definition rewrite
  422. Revision 1.18 2001/08/26 13:36:49 florian
  423. * some cg reorganisation
  424. * some PPC updates
  425. Revision 1.17 2001/04/21 12:03:12 peter
  426. * m68k updates merged from fixes branch
  427. Revision 1.16 2001/04/13 01:22:13 peter
  428. * symtable change to classes
  429. * range check generation and errors fixed, make cycle DEBUG=1 works
  430. * memory leaks fixed
  431. Revision 1.15 2000/12/25 00:07:28 peter
  432. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  433. tlinkedlist objects)
  434. Revision 1.14 2000/12/05 11:44:32 jonas
  435. + new integer regvar handling, should be much more efficient
  436. Revision 1.13 2000/11/29 00:30:39 florian
  437. * unused units removed from uses clause
  438. * some changes for widestrings
  439. Revision 1.12 2000/11/04 14:25:21 florian
  440. + merged Attila's changes for interfaces, not tested yet
  441. Revision 1.11 2000/10/31 22:02:51 peter
  442. * symtable splitted, no real code changes
  443. Revision 1.10 2000/10/14 10:14:52 peter
  444. * moehrendorf oct 2000 rewrite
  445. Revision 1.9 2000/10/01 19:48:25 peter
  446. * lot of compile updates for cg11
  447. Revision 1.8 2000/09/30 16:08:45 peter
  448. * more cg11 updates
  449. Revision 1.7 2000/09/30 13:08:16 jonas
  450. * regvars are now zeroed at the start of their life if they contain an 8
  451. or 16bit var/parameter, because the full 32bits are used if they are
  452. necessary for a btrl instruction
  453. Revision 1.6 2000/09/24 15:06:27 peter
  454. * use defines.inc
  455. Revision 1.5 2000/08/27 16:11:52 peter
  456. * moved some util functions from globals,cobjects to cutils
  457. * splitted files into finput,fmodule
  458. Revision 1.4 2000/08/17 11:07:51 jonas
  459. * fixed crash when inlining assembler procedures with -Or
  460. Revision 1.3 2000/08/04 05:52:00 jonas
  461. * correct version (I also had a regvars.pp locally, which was used
  462. instead of the regvars.pas on CVS, so I didn't notice the errors :( )
  463. Revision 1.2 2000/08/03 14:36:47 jonas
  464. * fixed inserting of allocated register for regvars (only those for
  465. parameters were done, and sometimes even the wrong ones)
  466. Revision 1.1 2000/08/03 13:17:25 jonas
  467. + allow regvars to be used inside inlined procs, which required the
  468. following changes:
  469. + load regvars in genentrycode/free them in genexitcode (cgai386)
  470. * moved all regvar related code to new regvars unit
  471. + added pregvarinfo type to hcodegen
  472. + added regvarinfo field to tprocinfo (symdef/symdefh)
  473. * deallocate the regvars of the caller in secondprocinline before
  474. inlining the called procedure and reallocate them afterwards
  475. }