regvars.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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,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. type
  41. pregvarinfo = ^tregvarinfo;
  42. tregvarinfo = record
  43. regvars : array[1..maxvarregs] of pvarsym;
  44. regvars_para : array[1..maxvarregs] of boolean;
  45. regvars_refs : array[1..maxvarregs] of longint;
  46. fpuregvars : array[1..maxfpuvarregs] of pvarsym;
  47. fpuregvars_para : array[1..maxfpuvarregs] of boolean;
  48. fpuregvars_refs : array[1..maxfpuvarregs] of longint;
  49. end;
  50. var
  51. parasym : boolean;
  52. procedure searchregvars(p : pnamedindexobject);
  53. var
  54. i,j,k : longint;
  55. begin
  56. if (psym(p)^.typ=varsym) and (vo_regable in pvarsym(p)^.varoptions) then
  57. begin
  58. j:=pvarsym(p)^.refs;
  59. { parameter get a less value }
  60. if parasym then
  61. begin
  62. if cs_littlesize in aktglobalswitches then
  63. dec(j,1)
  64. else
  65. dec(j,100);
  66. end;
  67. { walk through all momentary register variables }
  68. for i:=1 to maxvarregs do
  69. begin
  70. with pregvarinfo(aktprocsym^.definition^.regvarinfo)^ do
  71. if ((regvars[i]=nil) or (j>regvars_refs[i])) and (j>0) then
  72. begin
  73. for k:=maxvarregs-1 downto i do
  74. begin
  75. regvars[k+1]:=regvars[k];
  76. regvars_para[k+1]:=regvars_para[k];
  77. regvars_refs[k+1]:=regvars_refs[k];
  78. end;
  79. { calc the new refs
  80. pvarsym(p)^.refs:=j; }
  81. regvars[i]:=pvarsym(p);
  82. regvars_para[i]:=parasym;
  83. regvars_refs[i]:=j;
  84. break;
  85. end;
  86. end;
  87. end;
  88. end;
  89. procedure searchfpuregvars(p : pnamedindexobject);
  90. var
  91. i,j,k : longint;
  92. begin
  93. if (psym(p)^.typ=varsym) and (vo_fpuregable in pvarsym(p)^.varoptions) then
  94. begin
  95. j:=pvarsym(p)^.refs;
  96. { parameter get a less value }
  97. if parasym then
  98. begin
  99. if cs_littlesize in aktglobalswitches then
  100. dec(j,1)
  101. else
  102. dec(j,100);
  103. end;
  104. { walk through all momentary register variables }
  105. for i:=1 to maxfpuvarregs do
  106. begin
  107. with pregvarinfo(aktprocsym^.definition^.regvarinfo)^ do
  108. if ((fpuregvars[i]=nil) or (j>fpuregvars_refs[i])) and (j>0) then
  109. begin
  110. for k:=maxfpuvarregs-1 downto i do
  111. begin
  112. fpuregvars[k+1]:=fpuregvars[k];
  113. fpuregvars_para[k+1]:=fpuregvars_para[k];
  114. fpuregvars_refs[k+1]:=fpuregvars_refs[k];
  115. end;
  116. { calc the new refs
  117. pvarsym(p)^.refs:=j; }
  118. fpuregvars[i]:=pvarsym(p);
  119. fpuregvars_para[i]:=parasym;
  120. fpuregvars_refs[i]:=j;
  121. break;
  122. end;
  123. end;
  124. end;
  125. end;
  126. {$ifdef i386}
  127. function reg32(reg: tregister): tregister;
  128. begin
  129. case regsize(reg) of
  130. S_B: reg32 := reg8toreg32(reg);
  131. S_W: reg32 := reg16toreg32(reg);
  132. S_L: reg32 := reg;
  133. end;
  134. end;
  135. {$else i386}
  136. function reg32(reg: tregister): tregister;
  137. begin
  138. reg32 := reg;
  139. end;
  140. {$endif i386}
  141. procedure assign_regvars(p: tnode);
  142. { register variables }
  143. var
  144. regvarinfo: pregvarinfo;
  145. i: longint;
  146. begin
  147. { max. optimizations }
  148. { only if no asm is used }
  149. { and no try statement }
  150. if (cs_regalloc in aktglobalswitches) and
  151. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  152. begin
  153. new(regvarinfo);
  154. fillchar(regvarinfo^,sizeof(regvarinfo^),0);
  155. aktprocsym^.definition^.regvarinfo := regvarinfo;
  156. if (p.registers32<4) then
  157. begin
  158. parasym:=false;
  159. symtablestack^.foreach({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  160. { copy parameter into a register ? }
  161. parasym:=true;
  162. symtablestack^.next^.foreach({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  163. { hold needed registers free }
  164. for i:=maxvarregs downto maxvarregs-p.registers32+1 do
  165. begin
  166. regvarinfo^.regvars[i]:=nil;
  167. regvarinfo^.regvars_para[i] := false;
  168. end;
  169. { now assign register }
  170. for i:=1 to maxvarregs-p.registers32 do
  171. begin
  172. if assigned(regvarinfo^.regvars[i]) and
  173. (reg_pushes[varregs[i]] < regvarinfo^.regvars[i]^.refs) then
  174. begin
  175. { register is no longer available for }
  176. { expressions }
  177. { search the register which is the most }
  178. { unused }
  179. usableregs:=usableregs-[varregs[i]];
  180. is_reg_var[varregs[i]]:=true;
  181. dec(c_usableregs);
  182. { possibly no 32 bit register are needed }
  183. { call by reference/const ? }
  184. if (regvarinfo^.regvars[i]^.varspez=vs_var) or
  185. ((regvarinfo^.regvars[i]^.varspez=vs_const) and
  186. push_addr_param(regvarinfo^.regvars[i]^.vartype.def)) then
  187. begin
  188. regvarinfo^.regvars[i]^.reg:=varregs[i];
  189. end
  190. else
  191. if (regvarinfo^.regvars[i]^.vartype.def^.deftype in [orddef,enumdef]) and
  192. (porddef(regvarinfo^.regvars[i]^.vartype.def)^.size=1) then
  193. begin
  194. {$ifdef i386}
  195. regvarinfo^.regvars[i]^.reg:=reg32toreg8(varregs[i]);
  196. {$endif}
  197. end
  198. else
  199. if (regvarinfo^.regvars[i]^.vartype.def^.deftype in [orddef,enumdef]) and
  200. (porddef(regvarinfo^.regvars[i]^.vartype.def)^.size=2) then
  201. begin
  202. {$ifdef i386}
  203. regvarinfo^.regvars[i]^.reg:=reg32toreg16(varregs[i]);
  204. {$endif}
  205. end
  206. else
  207. begin
  208. regvarinfo^.regvars[i]^.reg:=varregs[i];
  209. end;
  210. if regvarinfo^.regvars_para[i] then
  211. unused:=unused - [regvarinfo^.regvars[i]^.reg];
  212. { procedure uses this register }
  213. {$ifdef i386}
  214. usedinproc:=usedinproc or ($80 shr byte(varregs[i]));
  215. {$endif i386}
  216. {$ifdef m68k}
  217. usedinproc:=usedinproc or ($800 shr word(varregs[i]));
  218. {$endif m68k}
  219. end
  220. else
  221. begin
  222. regvarinfo^.regvars[i] := nil;
  223. regvarinfo^.regvars_para[i] := false;
  224. end;
  225. end;
  226. end;
  227. if ((p.registersfpu+1)<maxfpuvarregs) then
  228. begin
  229. parasym:=false;
  230. symtablestack^.foreach({$ifdef FPCPROCVAR}@{$endif}searchfpuregvars);
  231. {$ifdef dummy}
  232. { copy parameter into a register ? }
  233. parasym:=true;
  234. symtablestack^.next^.foreach({$ifdef FPCPROCVAR}@{$endif}searchregvars);
  235. {$endif dummy}
  236. { hold needed registers free }
  237. { in non leaf procedures we must be very careful }
  238. { with assigning registers }
  239. if aktmaxfpuregisters=-1 then
  240. begin
  241. if (procinfo^.flags and pi_do_call)<>0 then
  242. begin
  243. for i:=maxfpuvarregs downto 2 do
  244. regvarinfo^.fpuregvars[i]:=nil;
  245. end
  246. else
  247. begin
  248. for i:=maxfpuvarregs downto maxfpuvarregs-p.registersfpu do
  249. regvarinfo^.fpuregvars[i]:=nil;
  250. end;
  251. end
  252. else
  253. begin
  254. for i:=aktmaxfpuregisters+1 to maxfpuvarregs do
  255. regvarinfo^.fpuregvars[i]:=nil;
  256. end;
  257. { now assign register }
  258. for i:=1 to maxfpuvarregs do
  259. begin
  260. if assigned(regvarinfo^.fpuregvars[i]) then
  261. begin
  262. {$ifdef i386}
  263. { reserve place on the FPU stack }
  264. regvarinfo^.fpuregvars[i]^.reg:=correct_fpuregister(R_ST0,i-1);
  265. {$endif i386}
  266. {$ifdef m68k}
  267. regvarinfo^.fpuregvars[i]^.reg:=fpuvarregs[i];
  268. {$endif m68k}
  269. end;
  270. end;
  271. end;
  272. end;
  273. end;
  274. procedure load_regvars(asml: paasmoutput; p: tnode);
  275. var
  276. i: longint;
  277. hr : preference;
  278. regvarinfo: pregvarinfo;
  279. {$ifdef i386}
  280. opsize: topsize;
  281. opcode: tasmop;
  282. signed: boolean;
  283. {$endif i386}
  284. begin
  285. if (cs_regalloc in aktglobalswitches) and
  286. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  287. begin
  288. regvarinfo := pregvarinfo(aktprocsym^.definition^.regvarinfo);
  289. { can happen when inlining assembler procedures (JM) }
  290. if not assigned(regvarinfo) then
  291. exit;
  292. for i:=1 to maxvarregs do
  293. begin
  294. { parameter must be load }
  295. if regvarinfo^.regvars_para[i] then
  296. begin
  297. {$ifdef i386}
  298. asml^.concat(new(pairegalloc,alloc(reg32(regvarinfo^.regvars[i]^.reg))));
  299. {$endif i386}
  300. { procinfo is there actual, }
  301. { because we can't never be in a }
  302. { nested procedure }
  303. { when loading parameter to reg }
  304. new(hr);
  305. reset_reference(hr^);
  306. hr^.offset:=pvarsym(regvarinfo^.regvars[i])^.address+procinfo^.para_offset;
  307. hr^.base:=procinfo^.framepointer;
  308. {$ifdef i386}
  309. { zero the regvars because the upper 48bits must be clear }
  310. { for 8bits vars when using them with btrl (JM) }
  311. signed :=
  312. (pvarsym(regvarinfo^.regvars[i])^.vartype.def^.deftype =
  313. orddef) and
  314. is_signed(pvarsym(regvarinfo^.regvars[i])^.vartype.def);
  315. case regsize(regvarinfo^.regvars[i]^.reg) of
  316. S_L:
  317. begin
  318. opsize := S_L;
  319. opcode := A_MOV;
  320. end;
  321. S_W:
  322. begin
  323. opsize := S_WL;
  324. if signed then
  325. opcode := A_MOVSX
  326. else opcode := A_MOVZX;
  327. end;
  328. S_B:
  329. begin
  330. opsize := S_BL;
  331. if signed then
  332. opcode := A_MOVSX
  333. else opcode := A_MOVZX;
  334. end;
  335. end;
  336. asml^.concat(new(paicpu,op_ref_reg(opcode,opsize,
  337. hr,reg32(regvarinfo^.regvars[i]^.reg))));
  338. {$endif i386}
  339. {$ifdef m68k}
  340. asml^.concat(new(paicpu,op_ref_reg(A_MOVE,regsize(regvarinfo^.regvars[i]^.reg),
  341. hr,regvarinfo^.regvars[i]^.reg)));
  342. {$endif m68k}
  343. end
  344. end;
  345. for i:=1 to maxvarregs do
  346. begin
  347. if assigned(regvarinfo^.regvars[i]) then
  348. begin
  349. {$ifdef i386}
  350. if not(regvarinfo^.regvars_para[i]) then
  351. begin
  352. asml^.concat(new(pairegalloc,alloc(reg32(regvarinfo^.regvars[i]^.reg))));
  353. { zero the regvars because the upper 48bits must be clear }
  354. { for 8bits vars when using them with btrl (JM) }
  355. if (regsize(regvarinfo^.regvars[i]^.reg) in [S_B,S_W]) then
  356. asml^.concat(new(paicpu,op_reg_reg(A_XOR,S_L,
  357. reg32(regvarinfo^.regvars[i]^.reg),
  358. reg32(regvarinfo^.regvars[i]^.reg))));
  359. end;
  360. {$endif i386}
  361. if cs_asm_source in aktglobalswitches then
  362. asml^.insert(new(pai_asm_comment,init(strpnew(regvarinfo^.regvars[i]^.name+
  363. ' with weight '+tostr(regvarinfo^.regvars[i]^.refs)+' assigned to register '+
  364. reg2str(regvarinfo^.regvars[i]^.reg)))));
  365. if (status.verbosity and v_debug)=v_debug then
  366. Message3(cg_d_register_weight,reg2str(regvarinfo^.regvars[i]^.reg),
  367. tostr(regvarinfo^.regvars[i]^.refs),regvarinfo^.regvars[i]^.name);
  368. end;
  369. end;
  370. for i:=1 to maxfpuvarregs do
  371. begin
  372. if assigned(regvarinfo^.fpuregvars[i]) then
  373. begin
  374. {$ifdef i386}
  375. { reserve place on the FPU stack }
  376. regvarinfo^.fpuregvars[i]^.reg:=correct_fpuregister(R_ST0,i-1);
  377. asml^.concat(new(paicpu,op_none(A_FLDZ,S_NO)));
  378. {$endif i386}
  379. {$ifdef dummy}
  380. { parameter must be load }
  381. if regvarinfo^.fpuregvars_para[i] then
  382. begin
  383. { procinfo is there actual, }
  384. { because we can't never be in a }
  385. { nested procedure }
  386. { when loading parameter to reg }
  387. new(hr);
  388. reset_reference(hr^);
  389. hr^.offset:=pvarsym(regvarinfo^.regvars[i])^.address+procinfo^.para_offset;
  390. hr^.base:=procinfo^.framepointer;
  391. {$ifdef i386}
  392. asml^.concat(new(paicpu,op_ref_reg(A_MOV,regsize(regvarinfo^.regvars[i]^.reg),
  393. hr,regvarinfo^.regvars[i]^.reg)));
  394. {$endif i386}
  395. {$ifdef m68k}
  396. asml^.concat(new(paicpu,op_ref_reg(A_MOVE,regsize(regvarinfo^.regvars[i]^.reg),
  397. hr,regvarinfo^.regvars[i]^.reg)));
  398. {$endif m68k}
  399. end;
  400. {$endif dummy}
  401. end;
  402. end;
  403. if assigned(p) then
  404. if cs_asm_source in aktglobalswitches then
  405. asml^.insert(new(pai_asm_comment,init(strpnew(tostr(p.registersfpu)+
  406. ' registers on FPU stack used by temp. expressions'))));
  407. for i:=1 to maxfpuvarregs do
  408. begin
  409. if assigned(regvarinfo^.fpuregvars[i]) then
  410. begin
  411. if cs_asm_source in aktglobalswitches then
  412. asml^.insert(new(pai_asm_comment,init(strpnew(regvarinfo^.fpuregvars[i]^.name+
  413. ' with weight '+tostr(regvarinfo^.fpuregvars[i]^.refs)+' assigned to register '+
  414. reg2str(regvarinfo^.fpuregvars[i]^.reg)))));
  415. if (status.verbosity and v_debug)=v_debug then
  416. Message3(cg_d_register_weight,reg2str(regvarinfo^.fpuregvars[i]^.reg),
  417. tostr(regvarinfo^.fpuregvars[i]^.refs),regvarinfo^.fpuregvars[i]^.name);
  418. end;
  419. end;
  420. if cs_asm_source in aktglobalswitches then
  421. asml^.insert(new(pai_asm_comment,init(strpnew('Register variable assignment:'))));
  422. end;
  423. end;
  424. procedure cleanup_regvars(asml: paasmoutput);
  425. var
  426. i: longint;
  427. begin
  428. {$ifdef i386}
  429. { can happen when inlining assembler procedures (JM) }
  430. if not assigned(aktprocsym^.definition^.regvarinfo) then
  431. exit;
  432. if (cs_regalloc in aktglobalswitches) and
  433. ((procinfo^.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  434. with pregvarinfo(aktprocsym^.definition^.regvarinfo)^ do
  435. begin
  436. for i:=1 to maxfpuvarregs do
  437. if assigned(fpuregvars[i]) then
  438. { ... and clean it up }
  439. asml^.concat(new(paicpu,op_reg(A_FSTP,S_NO,R_ST0)));
  440. for i := 1 to maxvarregs do
  441. if assigned(regvars[i]) then
  442. asml^.concat(new(pairegalloc,dealloc(reg32(regvars[i]^.reg))));
  443. end;
  444. {$endif i386}
  445. end;
  446. end.
  447. {
  448. $Log$
  449. Revision 1.10 2000-10-14 10:14:52 peter
  450. * moehrendorf oct 2000 rewrite
  451. Revision 1.9 2000/10/01 19:48:25 peter
  452. * lot of compile updates for cg11
  453. Revision 1.8 2000/09/30 16:08:45 peter
  454. * more cg11 updates
  455. Revision 1.7 2000/09/30 13:08:16 jonas
  456. * regvars are now zeroed at the start of their life if they contain an 8
  457. or 16bit var/parameter, because the full 32bits are used if they are
  458. necessary for a btrl instruction
  459. Revision 1.6 2000/09/24 15:06:27 peter
  460. * use defines.inc
  461. Revision 1.5 2000/08/27 16:11:52 peter
  462. * moved some util functions from globals,cobjects to cutils
  463. * splitted files into finput,fmodule
  464. Revision 1.4 2000/08/17 11:07:51 jonas
  465. * fixed crash when inlining assembler procedures with -Or
  466. Revision 1.3 2000/08/04 05:52:00 jonas
  467. * correct version (I also had a regvars.pp locally, which was used
  468. instead of the regvars.pas on CVS, so I didn't notice the errors :( )
  469. Revision 1.2 2000/08/03 14:36:47 jonas
  470. * fixed inserting of allocated register for regvars (only those for
  471. parameters were done, and sometimes even the wrong ones)
  472. Revision 1.1 2000/08/03 13:17:25 jonas
  473. + allow regvars to be used inside inlined procs, which required the
  474. following changes:
  475. + load regvars in genentrycode/free them in genexitcode (cgai386)
  476. * moved all regvar related code to new regvars unit
  477. + added pregvarinfo type to hcodegen
  478. + added regvarinfo field to tprocinfo (symdef/symdefh)
  479. * deallocate the regvars of the caller in secondprocinline before
  480. inlining the called procedure and reallocate them afterwards
  481. }