regvars.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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. procedure assign_regvars(p: tnode);
  25. procedure load_regvars(asml: paasmoutput; p: tnode);
  26. procedure cleanup_regvars(asml: paasmoutput);
  27. implementation
  28. uses
  29. globtype,systems,comphook,
  30. cutils,cobjects,verbose,globals,
  31. symconst,symbase,symtype,symdef,symsym,symtable,types,
  32. hcodegen,temp_gen,cpubase,cpuasm
  33. {$ifdef i386}
  34. ,tgeni386,cgai386
  35. {$endif}
  36. {$ifdef m68k}
  37. ,tgen68k,cga68k
  38. {$endif}
  39. ;
  40. var
  41. parasym : boolean;
  42. procedure searchregvars(p : pnamedindexobject);
  43. var
  44. i,j,k : longint;
  45. begin
  46. if (psym(p)^.typ=varsym) and (vo_regable in pvarsym(p)^.varoptions) then
  47. begin
  48. j:=pvarsym(p)^.refs;
  49. { parameter get a less value }
  50. if parasym then
  51. begin
  52. if cs_littlesize in aktglobalswitches then
  53. dec(j,1)
  54. else
  55. dec(j,100);
  56. end;
  57. { walk through all momentary register variables }
  58. for i:=1 to maxvarregs do
  59. begin
  60. with pregvarinfo(aktprocsym^.definition^.regvarinfo)^ do
  61. if ((regvars[i]=nil) or (j>regvars_refs[i])) and (j>0) then
  62. begin
  63. for k:=maxvarregs-1 downto i do
  64. begin
  65. regvars[k+1]:=regvars[k];
  66. regvars_para[k+1]:=regvars_para[k];
  67. regvars_refs[k+1]:=regvars_refs[k];
  68. end;
  69. { calc the new refs
  70. pvarsym(p)^.refs:=j; }
  71. regvars[i]:=pvarsym(p);
  72. regvars_para[i]:=parasym;
  73. regvars_refs[i]:=j;
  74. break;
  75. end;
  76. end;
  77. end;
  78. end;
  79. procedure searchfpuregvars(p : pnamedindexobject);
  80. var
  81. i,j,k : longint;
  82. begin
  83. if (psym(p)^.typ=varsym) and (vo_fpuregable in pvarsym(p)^.varoptions) then
  84. begin
  85. j:=pvarsym(p)^.refs;
  86. { parameter get a less value }
  87. if parasym then
  88. begin
  89. if cs_littlesize in aktglobalswitches then
  90. dec(j,1)
  91. else
  92. dec(j,100);
  93. end;
  94. { walk through all momentary register variables }
  95. for i:=1 to maxfpuvarregs do
  96. begin
  97. with pregvarinfo(aktprocsym^.definition^.regvarinfo)^ do
  98. if ((fpuregvars[i]=nil) or (j>fpuregvars_refs[i])) and (j>0) then
  99. begin
  100. for k:=maxfpuvarregs-1 downto i do
  101. begin
  102. fpuregvars[k+1]:=fpuregvars[k];
  103. fpuregvars_para[k+1]:=fpuregvars_para[k];
  104. fpuregvars_refs[k+1]:=fpuregvars_refs[k];
  105. end;
  106. { calc the new refs
  107. pvarsym(p)^.refs:=j; }
  108. fpuregvars[i]:=pvarsym(p);
  109. fpuregvars_para[i]:=parasym;
  110. fpuregvars_refs[i]:=j;
  111. break;
  112. end;
  113. end;
  114. end;
  115. end;
  116. {$ifdef i386}
  117. function reg32(reg: tregister): tregister;
  118. begin
  119. case regsize(reg) of
  120. S_B: reg32 := reg8toreg32(reg);
  121. S_W: reg32 := reg16toreg32(reg);
  122. S_L: reg32 := reg;
  123. end;
  124. end;
  125. {$else i386}
  126. function reg32(reg: tregister): tregister;
  127. begin
  128. reg32 := reg;
  129. end;
  130. {$endif i386}
  131. procedure assign_regvars(p: tnode);
  132. { register variables }
  133. var
  134. regvarinfo: pregvarinfo;
  135. i: longint;
  136. begin
  137. { max. optimizations }
  138. { only if no asm is used }
  139. { and no try statement }
  140. if (cs_regalloc in aktglobalswitches) and
  141. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  142. begin
  143. new(regvarinfo);
  144. fillchar(regvarinfo^,sizeof(regvarinfo^),0);
  145. aktprocsym^.definition^.regvarinfo := regvarinfo;
  146. if (p.registers32<4) then
  147. begin
  148. parasym:=false;
  149. symtablestack^.foreach({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  150. { copy parameter into a register ? }
  151. parasym:=true;
  152. symtablestack^.next^.foreach({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  153. { hold needed registers free }
  154. for i:=maxvarregs downto maxvarregs-p.registers32+1 do
  155. begin
  156. regvarinfo^.regvars[i]:=nil;
  157. regvarinfo^.regvars_para[i] := false;
  158. end;
  159. { now assign register }
  160. for i:=1 to maxvarregs-p.registers32 do
  161. begin
  162. if assigned(regvarinfo^.regvars[i]) and
  163. (reg_pushes[varregs[i]] < regvarinfo^.regvars[i]^.refs) then
  164. begin
  165. { register is no longer available for }
  166. { expressions }
  167. { search the register which is the most }
  168. { unused }
  169. usableregs:=usableregs-[varregs[i]];
  170. is_reg_var[varregs[i]]:=true;
  171. dec(c_usableregs);
  172. { possibly no 32 bit register are needed }
  173. { call by reference/const ? }
  174. if (regvarinfo^.regvars[i]^.varspez in [vs_var,vs_out]) or
  175. ((regvarinfo^.regvars[i]^.varspez=vs_const) and
  176. push_addr_param(regvarinfo^.regvars[i]^.vartype.def)) then
  177. begin
  178. regvarinfo^.regvars[i]^.reg:=varregs[i];
  179. end
  180. else
  181. if (regvarinfo^.regvars[i]^.vartype.def^.deftype in [orddef,enumdef]) and
  182. (porddef(regvarinfo^.regvars[i]^.vartype.def)^.size=1) then
  183. begin
  184. {$ifdef i386}
  185. regvarinfo^.regvars[i]^.reg:=reg32toreg8(varregs[i]);
  186. {$endif}
  187. end
  188. else
  189. if (regvarinfo^.regvars[i]^.vartype.def^.deftype in [orddef,enumdef]) and
  190. (porddef(regvarinfo^.regvars[i]^.vartype.def)^.size=2) then
  191. begin
  192. {$ifdef i386}
  193. regvarinfo^.regvars[i]^.reg:=reg32toreg16(varregs[i]);
  194. {$endif}
  195. end
  196. else
  197. begin
  198. regvarinfo^.regvars[i]^.reg:=varregs[i];
  199. end;
  200. if regvarinfo^.regvars_para[i] then
  201. unused:=unused - [regvarinfo^.regvars[i]^.reg];
  202. { procedure uses this register }
  203. {$ifdef i386}
  204. usedinproc:=usedinproc or ($80 shr byte(varregs[i]));
  205. {$endif i386}
  206. {$ifdef m68k}
  207. usedinproc:=usedinproc or ($800 shr word(varregs[i]));
  208. {$endif m68k}
  209. end
  210. else
  211. begin
  212. regvarinfo^.regvars[i] := nil;
  213. regvarinfo^.regvars_para[i] := false;
  214. end;
  215. end;
  216. end;
  217. if ((p.registersfpu+1)<maxfpuvarregs) then
  218. begin
  219. parasym:=false;
  220. symtablestack^.foreach({$ifdef FPCPROCVAR}@{$endif}searchfpuregvars);
  221. {$ifdef dummy}
  222. { copy parameter into a register ? }
  223. parasym:=true;
  224. symtablestack^.next^.foreach({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  225. {$endif dummy}
  226. { hold needed registers free }
  227. { in non leaf procedures we must be very careful }
  228. { with assigning registers }
  229. if aktmaxfpuregisters=-1 then
  230. begin
  231. if (procinfo^.flags and pi_do_call)<>0 then
  232. begin
  233. for i:=maxfpuvarregs downto 2 do
  234. regvarinfo^.fpuregvars[i]:=nil;
  235. end
  236. else
  237. begin
  238. for i:=maxfpuvarregs downto maxfpuvarregs-p.registersfpu do
  239. regvarinfo^.fpuregvars[i]:=nil;
  240. end;
  241. end
  242. else
  243. begin
  244. for i:=aktmaxfpuregisters+1 to maxfpuvarregs do
  245. regvarinfo^.fpuregvars[i]:=nil;
  246. end;
  247. { now assign register }
  248. for i:=1 to maxfpuvarregs do
  249. begin
  250. if assigned(regvarinfo^.fpuregvars[i]) then
  251. begin
  252. {$ifdef i386}
  253. { reserve place on the FPU stack }
  254. regvarinfo^.fpuregvars[i]^.reg:=correct_fpuregister(R_ST0,i-1);
  255. {$endif i386}
  256. {$ifdef m68k}
  257. regvarinfo^.fpuregvars[i]^.reg:=fpuvarregs[i];
  258. {$endif m68k}
  259. end;
  260. end;
  261. end;
  262. end;
  263. end;
  264. procedure load_regvars(asml: paasmoutput; p: tnode);
  265. var
  266. i: longint;
  267. hr : preference;
  268. regvarinfo: pregvarinfo;
  269. {$ifdef i386}
  270. opsize: topsize;
  271. opcode: tasmop;
  272. signed: boolean;
  273. {$endif i386}
  274. begin
  275. if (cs_regalloc in aktglobalswitches) and
  276. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  277. begin
  278. regvarinfo := pregvarinfo(aktprocsym^.definition^.regvarinfo);
  279. { can happen when inlining assembler procedures (JM) }
  280. if not assigned(regvarinfo) then
  281. exit;
  282. for i:=1 to maxvarregs do
  283. begin
  284. { parameter must be load }
  285. if regvarinfo^.regvars_para[i] then
  286. begin
  287. {$ifdef i386}
  288. asml^.concat(new(pairegalloc,alloc(reg32(regvarinfo^.regvars[i]^.reg))));
  289. {$endif i386}
  290. { procinfo is there actual, }
  291. { because we can't never be in a }
  292. { nested procedure }
  293. { when loading parameter to reg }
  294. new(hr);
  295. reset_reference(hr^);
  296. hr^.offset:=pvarsym(regvarinfo^.regvars[i])^.address+procinfo^.para_offset;
  297. hr^.base:=procinfo^.framepointer;
  298. {$ifdef i386}
  299. { zero the regvars because the upper 48bits must be clear }
  300. { for 8bits vars when using them with btrl (JM) }
  301. signed :=
  302. (pvarsym(regvarinfo^.regvars[i])^.vartype.def^.deftype =
  303. orddef) and
  304. is_signed(pvarsym(regvarinfo^.regvars[i])^.vartype.def);
  305. case regsize(regvarinfo^.regvars[i]^.reg) of
  306. S_L:
  307. begin
  308. opsize := S_L;
  309. opcode := A_MOV;
  310. end;
  311. S_W:
  312. begin
  313. opsize := S_WL;
  314. if signed then
  315. opcode := A_MOVSX
  316. else opcode := A_MOVZX;
  317. end;
  318. S_B:
  319. begin
  320. opsize := S_BL;
  321. if signed then
  322. opcode := A_MOVSX
  323. else opcode := A_MOVZX;
  324. end;
  325. end;
  326. asml^.concat(new(paicpu,op_ref_reg(opcode,opsize,
  327. hr,reg32(regvarinfo^.regvars[i]^.reg))));
  328. {$endif i386}
  329. {$ifdef m68k}
  330. asml^.concat(new(paicpu,op_ref_reg(A_MOVE,regsize(regvarinfo^.regvars[i]^.reg),
  331. hr,regvarinfo^.regvars[i]^.reg)));
  332. {$endif m68k}
  333. end
  334. end;
  335. for i:=1 to maxvarregs do
  336. begin
  337. if assigned(regvarinfo^.regvars[i]) then
  338. begin
  339. {$ifdef i386}
  340. if not(regvarinfo^.regvars_para[i]) then
  341. begin
  342. asml^.concat(new(pairegalloc,alloc(reg32(regvarinfo^.regvars[i]^.reg))));
  343. { zero the regvars because the upper 48bits must be clear }
  344. { for 8bits vars when using them with btrl (JM) }
  345. if (regsize(regvarinfo^.regvars[i]^.reg) in [S_B,S_W]) then
  346. asml^.concat(new(paicpu,op_reg_reg(A_XOR,S_L,
  347. reg32(regvarinfo^.regvars[i]^.reg),
  348. reg32(regvarinfo^.regvars[i]^.reg))));
  349. end;
  350. {$endif i386}
  351. if cs_asm_source in aktglobalswitches then
  352. asml^.insert(new(pai_asm_comment,init(strpnew(regvarinfo^.regvars[i]^.name+
  353. ' with weight '+tostr(regvarinfo^.regvars[i]^.refs)+' assigned to register '+
  354. reg2str(regvarinfo^.regvars[i]^.reg)))));
  355. if (status.verbosity and v_debug)=v_debug then
  356. Message3(cg_d_register_weight,reg2str(regvarinfo^.regvars[i]^.reg),
  357. tostr(regvarinfo^.regvars[i]^.refs),regvarinfo^.regvars[i]^.name);
  358. end;
  359. end;
  360. for i:=1 to maxfpuvarregs do
  361. begin
  362. if assigned(regvarinfo^.fpuregvars[i]) then
  363. begin
  364. {$ifdef i386}
  365. { reserve place on the FPU stack }
  366. regvarinfo^.fpuregvars[i]^.reg:=correct_fpuregister(R_ST0,i-1);
  367. asml^.concat(new(paicpu,op_none(A_FLDZ,S_NO)));
  368. {$endif i386}
  369. {$ifdef dummy}
  370. { parameter must be load }
  371. if regvarinfo^.fpuregvars_para[i] then
  372. begin
  373. { procinfo is there actual, }
  374. { because we can't never be in a }
  375. { nested procedure }
  376. { when loading parameter to reg }
  377. new(hr);
  378. reset_reference(hr^);
  379. hr^.offset:=pvarsym(regvarinfo^.regvars[i])^.address+procinfo^.para_offset;
  380. hr^.base:=procinfo^.framepointer;
  381. {$ifdef i386}
  382. asml^.concat(new(paicpu,op_ref_reg(A_MOV,regsize(regvarinfo^.regvars[i]^.reg),
  383. hr,regvarinfo^.regvars[i]^.reg)));
  384. {$endif i386}
  385. {$ifdef m68k}
  386. asml^.concat(new(paicpu,op_ref_reg(A_MOVE,regsize(regvarinfo^.regvars[i]^.reg),
  387. hr,regvarinfo^.regvars[i]^.reg)));
  388. {$endif m68k}
  389. end;
  390. {$endif dummy}
  391. end;
  392. end;
  393. if assigned(p) then
  394. if cs_asm_source in aktglobalswitches then
  395. asml^.insert(new(pai_asm_comment,init(strpnew(tostr(p.registersfpu)+
  396. ' registers on FPU stack used by temp. expressions'))));
  397. for i:=1 to maxfpuvarregs do
  398. begin
  399. if assigned(regvarinfo^.fpuregvars[i]) then
  400. begin
  401. if cs_asm_source in aktglobalswitches then
  402. asml^.insert(new(pai_asm_comment,init(strpnew(regvarinfo^.fpuregvars[i]^.name+
  403. ' with weight '+tostr(regvarinfo^.fpuregvars[i]^.refs)+' assigned to register '+
  404. reg2str(regvarinfo^.fpuregvars[i]^.reg)))));
  405. if (status.verbosity and v_debug)=v_debug then
  406. Message3(cg_d_register_weight,reg2str(regvarinfo^.fpuregvars[i]^.reg),
  407. tostr(regvarinfo^.fpuregvars[i]^.refs),regvarinfo^.fpuregvars[i]^.name);
  408. end;
  409. end;
  410. if cs_asm_source in aktglobalswitches then
  411. asml^.insert(new(pai_asm_comment,init(strpnew('Register variable assignment:'))));
  412. end;
  413. end;
  414. procedure cleanup_regvars(asml: paasmoutput);
  415. var
  416. i: longint;
  417. begin
  418. {$ifdef i386}
  419. { can happen when inlining assembler procedures (JM) }
  420. if not assigned(aktprocsym^.definition^.regvarinfo) then
  421. exit;
  422. if (cs_regalloc in aktglobalswitches) and
  423. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  424. with pregvarinfo(aktprocsym^.definition^.regvarinfo)^ do
  425. begin
  426. for i:=1 to maxfpuvarregs do
  427. if assigned(fpuregvars[i]) then
  428. { ... and clean it up }
  429. asml^.concat(new(paicpu,op_reg(A_FSTP,S_NO,R_ST0)));
  430. for i := 1 to maxvarregs do
  431. if assigned(regvars[i]) then
  432. asml^.concat(new(pairegalloc,dealloc(reg32(regvars[i]^.reg))));
  433. end;
  434. {$endif i386}
  435. end;
  436. end.
  437. {
  438. $Log$
  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. }