regvars.pas 18 KB

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