regvars.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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 fpcdefs.inc}
  20. interface
  21. uses
  22. aasmbase,aasmtai,aasmcpu,
  23. node,
  24. symsym,
  25. cpubase, cginfo, tgobj, rgobj;
  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. procedure sync_regvars(list1, list2: taasmoutput; const regvarsloaded1,
  34. regvarsloaded2: regvar_booleanarray);
  35. implementation
  36. uses
  37. globtype,systems,comphook,
  38. cutils,cclasses,verbose,globals,
  39. symconst,symbase,symtype,symdef,paramgr,defbase,
  40. cgbase,cgobj,cgcpu,rgcpu;
  41. procedure searchregvars(p : tnamedindexitem;arg:pointer);
  42. var
  43. i,j,k : longint;
  44. parasym : boolean;
  45. begin
  46. parasym:=pboolean(arg)^;
  47. if (tsym(p).typ=varsym) and (vo_regable in tvarsym(p).varoptions) then
  48. begin
  49. j:=tvarsym(p).refs;
  50. { parameter get a less value }
  51. if parasym then
  52. begin
  53. if cs_littlesize in aktglobalswitches then
  54. dec(j,1)
  55. else
  56. dec(j,100);
  57. end;
  58. { walk through all momentary register variables }
  59. for i:=1 to maxvarregs do
  60. begin
  61. with pregvarinfo(aktprocdef.regvarinfo)^ do
  62. if ((regvars[i]=nil) or (j>regvars_refs[i])) and (j>0) then
  63. begin
  64. for k:=maxvarregs-1 downto i do
  65. begin
  66. regvars[k+1]:=regvars[k];
  67. regvars_para[k+1]:=regvars_para[k];
  68. regvars_refs[k+1]:=regvars_refs[k];
  69. end;
  70. { calc the new refs
  71. tvarsym(p).refs:=j; }
  72. regvars[i]:=tvarsym(p);
  73. regvars_para[i]:=parasym;
  74. regvars_refs[i]:=j;
  75. break;
  76. end;
  77. end;
  78. end;
  79. end;
  80. procedure searchfpuregvars(p : tnamedindexitem;arg:pointer);
  81. var
  82. i,j,k : longint;
  83. parasym : boolean;
  84. begin
  85. parasym:=pboolean(arg)^;
  86. if (tsym(p).typ=varsym) and (vo_fpuregable in tvarsym(p).varoptions) then
  87. begin
  88. j:=tvarsym(p).refs;
  89. { parameter get a less value }
  90. if parasym then
  91. begin
  92. if cs_littlesize in aktglobalswitches then
  93. dec(j,1)
  94. else
  95. dec(j,100);
  96. end;
  97. { walk through all momentary register variables }
  98. for i:=1 to maxfpuvarregs do
  99. begin
  100. with pregvarinfo(aktprocdef.regvarinfo)^ do
  101. if ((fpuregvars[i]=nil) or (j>fpuregvars_refs[i])) and (j>0) then
  102. begin
  103. for k:=maxfpuvarregs-1 downto i do
  104. begin
  105. fpuregvars[k+1]:=fpuregvars[k];
  106. fpuregvars_para[k+1]:=fpuregvars_para[k];
  107. fpuregvars_refs[k+1]:=fpuregvars_refs[k];
  108. end;
  109. { calc the new refs
  110. tvarsym(p).refs:=j; }
  111. fpuregvars[i]:=tvarsym(p);
  112. fpuregvars_para[i]:=parasym;
  113. fpuregvars_refs[i]:=j;
  114. break;
  115. end;
  116. end;
  117. end;
  118. end;
  119. procedure assign_regvars(p: tnode);
  120. { register variables }
  121. var
  122. regvarinfo: pregvarinfo;
  123. i: longint;
  124. parasym : boolean;
  125. begin
  126. { max. optimizations }
  127. { only if no asm is used }
  128. { and no try statement }
  129. if (cs_regalloc in aktglobalswitches) and
  130. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  131. begin
  132. new(regvarinfo);
  133. fillchar(regvarinfo^,sizeof(regvarinfo^),0);
  134. aktprocdef.regvarinfo := regvarinfo;
  135. if (p.registers32<4) then
  136. begin
  137. parasym:=false;
  138. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchregvars,@parasym);
  139. { copy parameter into a register ? }
  140. parasym:=true;
  141. symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchregvars,@parasym);
  142. { hold needed registers free }
  143. for i:=maxvarregs downto maxvarregs-p.registers32+1 do
  144. begin
  145. regvarinfo^.regvars[i]:=nil;
  146. regvarinfo^.regvars_para[i] := false;
  147. end;
  148. { now assign register }
  149. for i:=1 to maxvarregs-p.registers32 do
  150. begin
  151. if assigned(regvarinfo^.regvars[i]) and
  152. (rg.reg_pushes[varregs[i]] < regvarinfo^.regvars[i].refs) then
  153. begin
  154. { register is no longer available for }
  155. { expressions }
  156. { search the register which is the most }
  157. { unused }
  158. rg.makeregvar(varregs[i]);
  159. { possibly no 32 bit register are needed }
  160. { call by reference/const ? }
  161. if (regvarinfo^.regvars[i].varspez in [vs_var,vs_out]) or
  162. ((regvarinfo^.regvars[i].varspez=vs_const) and
  163. paramanager.push_addr_param(regvarinfo^.regvars[i].vartype.def)) then
  164. begin
  165. regvarinfo^.regvars[i].reg:=varregs[i];
  166. end
  167. else
  168. if (regvarinfo^.regvars[i].vartype.def.deftype in [orddef,enumdef]) and
  169. (regvarinfo^.regvars[i].vartype.def.size=1) then
  170. begin
  171. regvarinfo^.regvars[i].reg:=rg.makeregsize(varregs[i],OS_8);
  172. end
  173. else
  174. if (regvarinfo^.regvars[i].vartype.def.deftype in [orddef,enumdef]) and
  175. (regvarinfo^.regvars[i].vartype.def.size=2) then
  176. begin
  177. regvarinfo^.regvars[i].reg:=rg.makeregsize(varregs[i],OS_16);
  178. end
  179. else
  180. begin
  181. regvarinfo^.regvars[i].reg:=varregs[i];
  182. end;
  183. { procedure uses this register }
  184. include(rg.usedinproc,varregs[i]);
  185. end
  186. else
  187. begin
  188. regvarinfo^.regvars[i] := nil;
  189. regvarinfo^.regvars_para[i] := false;
  190. end;
  191. end;
  192. end;
  193. if ((p.registersfpu+1)<maxfpuvarregs) then
  194. begin
  195. parasym:=false;
  196. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchfpuregvars,@parasym);
  197. {$ifdef dummy}
  198. { copy parameter into a register ? }
  199. parasym:=true;
  200. symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  201. {$endif dummy}
  202. { hold needed registers free }
  203. { in non leaf procedures we must be very careful }
  204. { with assigning registers }
  205. if aktmaxfpuregisters=-1 then
  206. begin
  207. if (procinfo^.flags and pi_do_call)<>0 then
  208. begin
  209. for i:=maxfpuvarregs downto 2 do
  210. regvarinfo^.fpuregvars[i]:=nil;
  211. end
  212. else
  213. begin
  214. for i:=maxfpuvarregs downto maxfpuvarregs-p.registersfpu do
  215. regvarinfo^.fpuregvars[i]:=nil;
  216. end;
  217. end
  218. else
  219. begin
  220. for i:=aktmaxfpuregisters+1 to maxfpuvarregs do
  221. regvarinfo^.fpuregvars[i]:=nil;
  222. end;
  223. { now assign register }
  224. for i:=1 to maxfpuvarregs do
  225. begin
  226. if assigned(regvarinfo^.fpuregvars[i]) then
  227. begin
  228. {$ifdef i386}
  229. { reserve place on the FPU stack }
  230. regvarinfo^.fpuregvars[i].reg:=trgcpu(rg).correct_fpuregister(R_ST0,i);
  231. {$else i386}
  232. rg.makeregvar(regvarinfo^.fpuregvars[i].reg);
  233. {$endif i386}
  234. end;
  235. end;
  236. end;
  237. end;
  238. end;
  239. procedure store_regvar(asml: TAAsmoutput; reg: tregister);
  240. var
  241. i: longint;
  242. hr: treference;
  243. regvarinfo: pregvarinfo;
  244. vsym: tvarsym;
  245. begin
  246. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  247. if not assigned(regvarinfo) then
  248. exit;
  249. for i := 1 to maxvarregs do
  250. if assigned(regvarinfo^.regvars[i]) and
  251. (rg.makeregsize(regvarinfo^.regvars[i].reg,OS_INT) = reg) then
  252. begin
  253. if rg.regvar_loaded[rg.makeregsize(reg,OS_INT)] then
  254. begin
  255. vsym := tvarsym(regvarinfo^.regvars[i]);
  256. { we only have to store the regvar back to memory if it's }
  257. { possible that it's been modified (JM) }
  258. if not(vsym.varspez in [vs_const,vs_var,vs_out]) then
  259. begin
  260. reference_reset(hr);
  261. if vsym.owner.symtabletype in [inlinelocalsymtable,localsymtable] then
  262. hr.offset:=-vsym.address+vsym.owner.address_fixup
  263. else
  264. hr.offset:=vsym.address+vsym.owner.address_fixup;
  265. hr.base:=procinfo^.framepointer;
  266. cg.a_load_reg_ref(asml,def_cgsize(vsym.vartype.def),vsym.reg,hr);
  267. end;
  268. asml.concat(tai_regalloc.dealloc(rg.makeregsize(reg,OS_INT)));
  269. rg.regvar_loaded[rg.makeregsize(reg,OS_INT)] := false;
  270. end;
  271. break;
  272. end;
  273. end;
  274. procedure load_regvar(asml: TAAsmoutput; vsym: tvarsym);
  275. var
  276. hr: treference;
  277. opsize: tcgsize;
  278. reg : tregister;
  279. begin
  280. reg:=rg.makeregsize(vsym.reg,OS_INT);
  281. if not rg.regvar_loaded[reg] then
  282. begin
  283. asml.concat(tai_regalloc.alloc(reg));
  284. reference_reset(hr);
  285. if vsym.owner.symtabletype in [inlinelocalsymtable,localsymtable] then
  286. hr.offset:=-vsym.address+vsym.owner.address_fixup
  287. else
  288. hr.offset:=vsym.address+vsym.owner.address_fixup;
  289. hr.base:=procinfo^.framepointer;
  290. if (vsym.varspez in [vs_var,vs_out]) or
  291. ((vsym.varspez=vs_const) and
  292. paramanager.push_addr_param(vsym.vartype.def)) then
  293. opsize := OS_ADDR
  294. else
  295. opsize := def_cgsize(vsym.vartype.def);
  296. cg.a_load_ref_reg(asml,opsize,hr,reg);
  297. rg.regvar_loaded[reg] := true;
  298. end;
  299. end;
  300. procedure load_regvar_reg(asml: TAAsmoutput; reg: tregister);
  301. var
  302. i: longint;
  303. regvarinfo: pregvarinfo;
  304. reg_spare : tregister;
  305. begin
  306. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  307. if not assigned(regvarinfo) then
  308. exit;
  309. reg_spare := rg.makeregsize(reg,OS_INT);
  310. for i := 1 to maxvarregs do
  311. if assigned(regvarinfo^.regvars[i]) and
  312. (rg.makeregsize(regvarinfo^.regvars[i].reg,OS_INT) = reg_spare) then
  313. load_regvar(asml,tvarsym(regvarinfo^.regvars[i]))
  314. end;
  315. procedure load_all_regvars(asml: TAAsmoutput);
  316. var
  317. i: longint;
  318. regvarinfo: pregvarinfo;
  319. begin
  320. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  321. if not assigned(regvarinfo) then
  322. exit;
  323. for i := 1 to maxvarregs do
  324. if assigned(regvarinfo^.regvars[i]) {and
  325. (makereg32(regvarinfo^.regvars[i].reg) in [R_EAX,R_EBX,R_ECX,R_EDX])} then
  326. load_regvar(asml,tvarsym(regvarinfo^.regvars[i]))
  327. end;
  328. procedure load_regvars(asml: TAAsmoutput; p: tnode);
  329. var
  330. i: longint;
  331. regvarinfo: pregvarinfo;
  332. begin
  333. if (cs_regalloc in aktglobalswitches) and
  334. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  335. begin
  336. regvarinfo := pregvarinfo(aktprocdef.regvarinfo);
  337. { can happen when inlining assembler procedures (JM) }
  338. if not assigned(regvarinfo) then
  339. exit;
  340. for i:=1 to maxvarregs do
  341. begin
  342. if assigned(regvarinfo^.regvars[i]) then
  343. begin
  344. if cs_asm_source in aktglobalswitches then
  345. asml.insert(Tai_asm_comment.Create(strpnew(regvarinfo^.regvars[i].name+
  346. ' with weight '+tostr(regvarinfo^.regvars[i].refs)+' assigned to register '+
  347. std_reg2str[regvarinfo^.regvars[i].reg])));
  348. if (status.verbosity and v_debug)=v_debug then
  349. Message3(cg_d_register_weight,std_reg2str[regvarinfo^.regvars[i].reg],
  350. tostr(regvarinfo^.regvars[i].refs),regvarinfo^.regvars[i].name);
  351. end;
  352. end;
  353. for i:=1 to maxfpuvarregs do
  354. begin
  355. if assigned(regvarinfo^.fpuregvars[i]) then
  356. begin
  357. {$ifdef i386}
  358. { reserve place on the FPU stack }
  359. regvarinfo^.fpuregvars[i].reg:=trgcpu(rg).correct_fpuregister(R_ST0,i-1);
  360. asml.concat(Taicpu.op_none(A_FLDZ,S_NO));
  361. {$endif i386}
  362. end;
  363. end;
  364. {$ifdef i386}
  365. if assigned(p) then
  366. if cs_asm_source in aktglobalswitches then
  367. asml.insert(Tai_asm_comment.Create(strpnew(tostr(p.registersfpu)+
  368. ' registers on FPU stack used by temp. expressions')));
  369. {$endif i386}
  370. for i:=1 to maxfpuvarregs do
  371. begin
  372. if assigned(regvarinfo^.fpuregvars[i]) then
  373. begin
  374. if cs_asm_source in aktglobalswitches then
  375. asml.insert(Tai_asm_comment.Create(strpnew(regvarinfo^.fpuregvars[i].name+
  376. ' with weight '+tostr(regvarinfo^.fpuregvars[i].refs)+' assigned to register '+
  377. std_reg2str[regvarinfo^.fpuregvars[i].reg])));
  378. if (status.verbosity and v_debug)=v_debug then
  379. Message3(cg_d_register_weight,std_reg2str[regvarinfo^.fpuregvars[i].reg],
  380. tostr(regvarinfo^.fpuregvars[i].refs),regvarinfo^.fpuregvars[i].name);
  381. end;
  382. end;
  383. if cs_asm_source in aktglobalswitches then
  384. asml.insert(Tai_asm_comment.Create(strpnew('Register variable assignment:')));
  385. end;
  386. end;
  387. procedure sync_regvars(list1, list2: taasmoutput; const regvarsloaded1,
  388. regvarsloaded2: regvar_booleanarray);
  389. var
  390. counter: tregister;
  391. begin
  392. for counter := low(rg.regvar_loaded) to high(rg.regvar_loaded) do
  393. begin
  394. rg.regvar_loaded[counter] := regvarsloaded1[counter] and
  395. regvarsloaded2[counter];
  396. if regvarsloaded1[counter] xor regvarsloaded2[counter] then
  397. if regvarsloaded1[counter] then
  398. load_regvar_reg(list2,counter)
  399. else
  400. load_regvar_reg(list1,counter);
  401. end;
  402. end;
  403. procedure cleanup_regvars(asml: TAAsmoutput);
  404. var
  405. i: longint;
  406. reg : tregister;
  407. begin
  408. { can happen when inlining assembler procedures (JM) }
  409. if not assigned(aktprocdef.regvarinfo) then
  410. exit;
  411. if (cs_regalloc in aktglobalswitches) and
  412. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  413. with pregvarinfo(aktprocdef.regvarinfo)^ do
  414. begin
  415. {$ifdef i386}
  416. for i:=1 to maxfpuvarregs do
  417. if assigned(fpuregvars[i]) then
  418. { ... and clean it up }
  419. asml.concat(Taicpu.op_reg(A_FSTP,S_NO,R_ST0));
  420. {$endif i386}
  421. for i := 1 to maxvarregs do
  422. begin
  423. if assigned(regvars[i]) then
  424. begin
  425. reg:=rg.makeregsize(regvars[i].reg,OS_INT);
  426. if (rg.regvar_loaded[reg]) then
  427. asml.concat(tai_regalloc.dealloc(reg));
  428. end;
  429. end;
  430. end;
  431. end;
  432. end.
  433. {
  434. $Log$
  435. Revision 1.37 2002-07-20 11:57:57 florian
  436. * types.pas renamed to defbase.pas because D6 contains a types
  437. unit so this would conflicts if D6 programms are compiled
  438. + Willamette/SSE2 instructions to assembler added
  439. Revision 1.36 2002/07/11 14:41:30 florian
  440. * start of the new generic parameter handling
  441. Revision 1.35 2002/07/01 18:46:25 peter
  442. * internal linker
  443. * reorganized aasm layer
  444. Revision 1.34 2002/06/24 12:43:00 jonas
  445. * fixed errors found with new -CR code from Peter when cycling with -O2p3r
  446. Revision 1.33 2002/05/18 13:34:17 peter
  447. * readded missing revisions
  448. Revision 1.32 2002/05/16 19:46:44 carl
  449. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  450. + try to fix temp allocation (still in ifdef)
  451. + generic constructor calls
  452. + start of tassembler / tmodulebase class cleanup
  453. Revision 1.30 2002/05/12 16:53:10 peter
  454. * moved entry and exitcode to ncgutil and cgobj
  455. * foreach gets extra argument for passing local data to the
  456. iterator function
  457. * -CR checks also class typecasts at runtime by changing them
  458. into as
  459. * fixed compiler to cycle with the -CR option
  460. * fixed stabs with elf writer, finally the global variables can
  461. be watched
  462. * removed a lot of routines from cga unit and replaced them by
  463. calls to cgobj
  464. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  465. u32bit then the other is typecasted also to u32bit without giving
  466. a rangecheck warning/error.
  467. * fixed pascal calling method with reversing also the high tree in
  468. the parast, detected by tcalcst3 test
  469. Revision 1.29 2002/04/21 15:23:34 carl
  470. + changeregsize -> makeregsize
  471. Revision 1.28 2002/04/19 15:46:03 peter
  472. * mangledname rewrite, tprocdef.mangledname is now created dynamicly
  473. in most cases and not written to the ppu
  474. * add mangeledname_prefix() routine to generate the prefix of
  475. manglednames depending on the current procedure, object and module
  476. * removed static procprefix since the mangledname is now build only
  477. on demand from tprocdef.mangledname
  478. Revision 1.27 2002/04/15 19:44:19 peter
  479. * fixed stackcheck that would be called recursively when a stack
  480. error was found
  481. * generic changeregsize(reg,size) for i386 register resizing
  482. * removed some more routines from cga unit
  483. * fixed returnvalue handling
  484. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  485. Revision 1.26 2002/04/15 19:04:04 carl
  486. + reg2str -> std_reg2str()
  487. Revision 1.25 2002/04/06 18:13:01 jonas
  488. * several powerpc-related additions and fixes
  489. Revision 1.24 2002/04/02 17:11:29 peter
  490. * tlocation,treference update
  491. * LOC_CONSTANT added for better constant handling
  492. * secondadd splitted in multiple routines
  493. * location_force_reg added for loading a location to a register
  494. of a specified size
  495. * secondassignment parses now first the right and then the left node
  496. (this is compatible with Kylix). This saves a lot of push/pop especially
  497. with string operations
  498. * adapted some routines to use the new cg methods
  499. Revision 1.23 2002/03/31 20:26:36 jonas
  500. + a_loadfpu_* and a_loadmm_* methods in tcg
  501. * register allocation is now handled by a class and is mostly processor
  502. independent (+rgobj.pas and i386/rgcpu.pas)
  503. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  504. * some small improvements and fixes to the optimizer
  505. * some register allocation fixes
  506. * some fpuvaroffset fixes in the unary minus node
  507. * push/popusedregisters is now called rg.save/restoreusedregisters and
  508. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  509. also better optimizable)
  510. * fixed and optimized register saving/restoring for new/dispose nodes
  511. * LOC_FPU locations now also require their "register" field to be set to
  512. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  513. - list field removed of the tnode class because it's not used currently
  514. and can cause hard-to-find bugs
  515. }