temp_gen.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. {
  2. $Id$
  3. Copyright (C) 1998-2000 by Florian Klaempfl
  4. This unit handles the temporary variables stuff for i386
  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 temp_gen;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. cpubase,cpuinfo,cobjects,globals,
  23. hcodegen,verbose,fmodule,aasm;
  24. type
  25. ttemptype = (tt_none,tt_free,tt_normal,tt_persistant,
  26. tt_ansistring,tt_freeansistring,tt_widestring,tt_freewidestring,
  27. tt_interfacecom,tt_freeinterfacecom);
  28. ttemptypeset = set of ttemptype;
  29. ptemprecord = ^ttemprecord;
  30. ttemprecord = record
  31. temptype : ttemptype;
  32. pos : longint;
  33. size : longint;
  34. next : ptemprecord;
  35. nextfree : ptemprecord; { for faster freeblock checking }
  36. {$ifdef EXTDEBUG}
  37. posinfo,
  38. releaseposinfo : tfileposinfo;
  39. {$endif}
  40. end;
  41. var
  42. { contains all temps }
  43. templist : ptemprecord;
  44. { contains all free temps using nextfree links }
  45. tempfreelist : ptemprecord;
  46. { Offsets of the first/last temp }
  47. firsttemp,
  48. lasttemp : longint;
  49. { generates temporary variables }
  50. procedure resettempgen;
  51. procedure setfirsttemp(l : longint);
  52. function gettempsize : longint;
  53. function newtempofsize(size : longint) : longint;
  54. function gettempofsize(size : longint) : longint;
  55. { special call for inlined procedures }
  56. function gettempofsizepersistant(size : longint) : longint;
  57. { for parameter func returns }
  58. procedure normaltemptopersistant(pos : longint);
  59. procedure persistanttemptonormal(pos : longint);
  60. {procedure ungettemp(pos : longint;size : longint);}
  61. procedure ungetpersistanttemp(pos : longint);
  62. procedure gettempofsizereference(l : longint;var ref : treference);
  63. function istemp(const ref : treference) : boolean;
  64. procedure ungetiftemp(const ref : treference);
  65. function ungetiftempansi(const ref : treference) : boolean;
  66. procedure gettempansistringreference(var ref : treference);
  67. function ungetiftempintfcom(const ref : treference) : boolean;
  68. procedure gettempintfcomreference(var ref : treference);
  69. implementation
  70. uses
  71. cutils,systems;
  72. procedure resettempgen;
  73. var
  74. hp : ptemprecord;
  75. begin
  76. { Clear the old templist }
  77. while assigned(templist) do
  78. begin
  79. {$ifdef EXTDEBUG}
  80. case templist^.temptype of
  81. tt_normal,
  82. tt_persistant :
  83. Comment(V_Warning,'temporary assignment of size '+
  84. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  85. ':'+tostr(templist^.posinfo.column)+
  86. ' at pos '+tostr(templist^.pos)+
  87. ' not freed at the end of the procedure');
  88. tt_ansistring :
  89. Comment(V_Warning,'temporary ANSI assignment of size '+
  90. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  91. ':'+tostr(templist^.posinfo.column)+
  92. ' at pos '+tostr(templist^.pos)+
  93. ' not freed at the end of the procedure');
  94. end;
  95. {$endif}
  96. hp:=templist;
  97. templist:=hp^.next;
  98. dispose(hp);
  99. end;
  100. templist:=nil;
  101. tempfreelist:=nil;
  102. firsttemp:=0;
  103. lasttemp:=0;
  104. end;
  105. procedure setfirsttemp(l : longint);
  106. begin
  107. { this is a negative value normally }
  108. if l < 0 then
  109. Begin
  110. if odd(l) then
  111. Dec(l);
  112. end
  113. else
  114. Begin
  115. if odd(l) then
  116. Inc(l);
  117. end;
  118. firsttemp:=l;
  119. lasttemp:=l;
  120. end;
  121. function newtempofsize(size : longint) : longint;
  122. var
  123. tl : ptemprecord;
  124. begin
  125. { Just extend the temp, everything below has been use
  126. already }
  127. dec(lasttemp,size);
  128. { now we can create the templist entry }
  129. new(tl);
  130. tl^.temptype:=tt_normal;
  131. tl^.pos:=lasttemp;
  132. tl^.size:=size;
  133. tl^.next:=templist;
  134. tl^.nextfree:=nil;
  135. templist:=tl;
  136. newtempofsize:=tl^.pos;
  137. end;
  138. const
  139. lasttempofsize : ptemprecord = nil;
  140. function gettempofsize(size : longint) : longint;
  141. var
  142. tl,
  143. bestslot,bestprev,
  144. hprev,hp : ptemprecord;
  145. bestsize,ofs : longint;
  146. begin
  147. bestprev:=nil;
  148. bestslot:=nil;
  149. tl:=nil;
  150. bestsize:=0;
  151. { Align needed size on 4 bytes }
  152. if (size mod 4)<>0 then
  153. size:=size+(4-(size mod 4));
  154. { First check the tmpfreelist }
  155. if assigned(tempfreelist) then
  156. begin
  157. { Check for a slot with the same size first }
  158. hprev:=nil;
  159. hp:=tempfreelist;
  160. while assigned(hp) do
  161. begin
  162. {$ifdef EXTDEBUG}
  163. if hp^.temptype<>tt_free then
  164. Comment(V_Warning,'Temp in freelist is not set to tt_free');
  165. {$endif}
  166. if hp^.size>=size then
  167. begin
  168. { Slot is the same size, then leave immediatly }
  169. if hp^.size=size then
  170. begin
  171. bestprev:=hprev;
  172. bestslot:=hp;
  173. bestsize:=size;
  174. break;
  175. end
  176. else
  177. begin
  178. if (bestsize=0) or (hp^.size<bestsize) then
  179. begin
  180. bestprev:=hprev;
  181. bestslot:=hp;
  182. bestsize:=hp^.size;
  183. end;
  184. end;
  185. end;
  186. hprev:=hp;
  187. hp:=hp^.nextfree;
  188. end;
  189. end;
  190. { Reuse an old temp ? }
  191. if assigned(bestslot) then
  192. begin
  193. if bestsize=size then
  194. begin
  195. bestslot^.temptype:=tt_normal;
  196. ofs:=bestslot^.pos;
  197. tl:=bestslot;
  198. { Remove from the tempfreelist }
  199. if assigned(bestprev) then
  200. bestprev^.nextfree:=bestslot^.nextfree
  201. else
  202. tempfreelist:=bestslot^.nextfree;
  203. end
  204. else
  205. begin
  206. { Resize the old block }
  207. dec(bestslot^.size,size);
  208. { Create new block and link after bestslot }
  209. new(tl);
  210. tl^.temptype:=tt_normal;
  211. tl^.pos:=bestslot^.pos+bestslot^.size;
  212. ofs:=tl^.pos;
  213. tl^.size:=size;
  214. tl^.nextfree:=nil;
  215. { link the new block }
  216. tl^.next:=bestslot^.next;
  217. bestslot^.next:=tl;
  218. end;
  219. end
  220. else
  221. begin
  222. ofs:=newtempofsize(size);
  223. tl:=templist;
  224. end;
  225. lasttempofsize:=tl;
  226. {$ifdef EXTDEBUG}
  227. tl^.posinfo:=aktfilepos;
  228. {$endif}
  229. exprasmlist^.concat(new(paitempalloc,alloc(ofs,size)));
  230. gettempofsize:=ofs;
  231. end;
  232. function gettempofsizepersistant(size : longint) : longint;
  233. var
  234. l : longint;
  235. begin
  236. l:=gettempofsize(size);
  237. lasttempofsize^.temptype:=tt_persistant;
  238. {$ifdef EXTDEBUG}
  239. Comment(V_Debug,'temp managment : call to gettempofsizepersistant()'+
  240. ' with size '+tostr(size)+' returned '+tostr(l));
  241. {$endif}
  242. gettempofsizepersistant:=l;
  243. end;
  244. function gettempsize : longint;
  245. var
  246. _align : longint;
  247. begin
  248. { align to 4 bytes at least
  249. otherwise all those subl $2,%esp are meaningless PM }
  250. _align:=target_os.stackalignment;
  251. if _align<4 then
  252. _align:=4;
  253. gettempsize:=Align(-lasttemp,_align);
  254. end;
  255. procedure gettempofsizereference(l : longint;var ref : treference);
  256. begin
  257. { do a reset, because the reference isn't used }
  258. reset_reference(ref);
  259. ref.offset:=gettempofsize(l);
  260. ref.base:=procinfo^.framepointer;
  261. end;
  262. procedure gettemppointerreferencefortype(var ref : treference; const usedtype, freetype: ttemptype);
  263. var
  264. foundslot,tl : ptemprecord;
  265. begin
  266. { do a reset, because the reference isn't used }
  267. reset_reference(ref);
  268. ref.base:=procinfo^.framepointer;
  269. { Reuse old slot ? }
  270. foundslot:=nil;
  271. tl:=templist;
  272. while assigned(tl) do
  273. begin
  274. if tl^.temptype=freetype then
  275. begin
  276. foundslot:=tl;
  277. {$ifdef EXTDEBUG}
  278. tl^.posinfo:=aktfilepos;
  279. {$endif}
  280. break;
  281. end;
  282. tl:=tl^.next;
  283. end;
  284. if assigned(foundslot) then
  285. begin
  286. foundslot^.temptype:=usedtype;
  287. ref.offset:=foundslot^.pos;
  288. end
  289. else
  290. begin
  291. ref.offset:=newtempofsize(target_os.size_of_pointer);
  292. {$ifdef EXTDEBUG}
  293. templist^.posinfo:=aktfilepos;
  294. {$endif}
  295. templist^.temptype:=usedtype;
  296. end;
  297. exprasmlist^.concat(new(paitempalloc,alloc(ref.offset,target_os.size_of_pointer)));
  298. end;
  299. function ungettemppointeriftype(const ref : treference; const usedtype, freetype: ttemptype) : boolean;
  300. var
  301. tl : ptemprecord;
  302. begin
  303. ungettemppointeriftype:=false;
  304. tl:=templist;
  305. while assigned(tl) do
  306. begin
  307. if tl^.pos=ref.offset then
  308. begin
  309. if tl^.temptype=usedtype then
  310. begin
  311. tl^.temptype:=freetype;
  312. ungettemppointeriftype:=true;
  313. exprasmlist^.concat(new(paitempalloc,dealloc(tl^.pos,tl^.size)));
  314. exit;
  315. {$ifdef EXTDEBUG}
  316. end
  317. else if (tl^.temptype=freetype) then
  318. begin
  319. Comment(V_Debug,'temp managment problem : ungettemppointeriftype()'+
  320. ' at pos '+tostr(ref.offset)+ ' already free !');
  321. {$endif}
  322. end;
  323. end;
  324. tl:=tl^.next;
  325. end;
  326. end;
  327. procedure gettempansistringreference(var ref : treference);
  328. begin
  329. gettemppointerreferencefortype(ref,tt_ansistring,tt_freeansistring);
  330. end;
  331. function ungetiftempansi(const ref : treference) : boolean;
  332. begin
  333. ungetiftempansi:=ungettemppointeriftype(ref,tt_ansistring,tt_freeansistring);
  334. end;
  335. procedure gettempintfcomreference(var ref : treference);
  336. begin
  337. gettemppointerreferencefortype(ref,tt_interfacecom,tt_freeinterfacecom);
  338. end;
  339. function ungetiftempintfcom(const ref : treference) : boolean;
  340. begin
  341. ungetiftempintfcom:=ungettemppointeriftype(ref,tt_ansistring,tt_freeansistring);
  342. end;
  343. function istemp(const ref : treference) : boolean;
  344. begin
  345. { ref.index = R_NO was missing
  346. led to problems with local arrays
  347. with lower bound > 0 (PM) }
  348. istemp:=((ref.base=procinfo^.framepointer) and
  349. {$ifndef alpha}
  350. (ref.index=R_NO) and
  351. {$endif}
  352. (ref.offset<firsttemp));
  353. end;
  354. procedure persistanttemptonormal(pos : longint);
  355. var
  356. hp : ptemprecord;
  357. begin
  358. hp:=templist;
  359. while assigned(hp) do
  360. if (hp^.pos=pos) and (hp^.temptype=tt_persistant) then
  361. begin
  362. {$ifdef EXTDEBUG}
  363. Comment(V_Debug,'temp managment : persistanttemptonormal()'+
  364. ' at pos '+tostr(pos)+ ' found !');
  365. {$endif}
  366. hp^.temptype:=tt_normal;
  367. exit;
  368. end
  369. else
  370. hp:=hp^.next;
  371. {$ifdef EXTDEBUG}
  372. Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
  373. ' at pos '+tostr(pos)+ ' not found !');
  374. {$endif}
  375. end;
  376. procedure normaltemptopersistant(pos : longint);
  377. var
  378. hp : ptemprecord;
  379. begin
  380. hp:=templist;
  381. while assigned(hp) do
  382. if (hp^.pos=pos) and (hp^.temptype=tt_normal) then
  383. begin
  384. {$ifdef EXTDEBUG}
  385. Comment(V_Debug,'temp managment : normaltemptopersistant()'+
  386. ' at pos '+tostr(pos)+ ' found !');
  387. {$endif}
  388. hp^.temptype:=tt_persistant;
  389. exit;
  390. end
  391. else
  392. hp:=hp^.next;
  393. {$ifdef EXTDEBUG}
  394. Comment(V_Debug,'temp managment problem : normaltemptopersistant()'+
  395. ' at pos '+tostr(pos)+ ' not found !');
  396. {$endif}
  397. end;
  398. function ungettemp(pos:longint;allowtype:ttemptype):ttemptype;
  399. var
  400. hp,hnext,hprev,hprevfree : ptemprecord;
  401. begin
  402. ungettemp:=tt_none;
  403. hp:=templist;
  404. hprev:=nil;
  405. hprevfree:=nil;
  406. while assigned(hp) do
  407. begin
  408. if (hp^.pos=pos) then
  409. begin
  410. { check type }
  411. ungettemp:=hp^.temptype;
  412. if hp^.temptype<>allowtype then
  413. begin
  414. exit;
  415. end;
  416. exprasmlist^.concat(new(paitempalloc,dealloc(hp^.pos,hp^.size)));
  417. { set this block to free }
  418. hp^.temptype:=tt_free;
  419. { Update tempfreelist }
  420. if assigned(hprevfree) then
  421. begin
  422. { Connect with previous? }
  423. if assigned(hprev) and (hprev^.temptype=tt_free) then
  424. begin
  425. inc(hprev^.size,hp^.size);
  426. hprev^.next:=hp^.next;
  427. dispose(hp);
  428. hp:=hprev;
  429. end
  430. else
  431. hprevfree^.nextfree:=hp;
  432. end
  433. else
  434. begin
  435. hp^.nextfree:=tempfreelist;
  436. tempfreelist:=hp;
  437. end;
  438. { Next block free ? Yes, then concat }
  439. hnext:=hp^.next;
  440. if assigned(hnext) and (hnext^.temptype=tt_free) then
  441. begin
  442. inc(hp^.size,hnext^.size);
  443. hp^.nextfree:=hnext^.nextfree;
  444. hp^.next:=hnext^.next;
  445. dispose(hnext);
  446. end;
  447. exit;
  448. end;
  449. if (hp^.temptype=tt_free) then
  450. hprevfree:=hp;
  451. hprev:=hp;
  452. hp:=hp^.next;
  453. end;
  454. ungettemp:=tt_none;
  455. end;
  456. procedure ungetpersistanttemp(pos : longint);
  457. begin
  458. {$ifdef EXTDEBUG}
  459. if ungettemp(pos,tt_persistant)<>tt_persistant then
  460. Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
  461. ' at pos '+tostr(pos)+ ' not found !');
  462. {$else}
  463. ungettemp(pos,tt_persistant);
  464. {$endif}
  465. end;
  466. procedure ungetiftemp(const ref : treference);
  467. {$ifdef EXTDEBUG}
  468. var
  469. tt : ttemptype;
  470. {$endif}
  471. begin
  472. if istemp(ref) then
  473. begin
  474. { first check if ansistring }
  475. if ungetiftempansi(ref) then
  476. exit;
  477. {$ifndef EXTDEBUG}
  478. ungettemp(ref.offset,tt_normal);
  479. {$else}
  480. tt:=ungettemp(ref.offset,tt_normal);
  481. if tt=tt_persistant then
  482. Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!');
  483. if tt=tt_none then
  484. Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset));
  485. {$endif}
  486. end;
  487. end;
  488. procedure inittemps;
  489. begin
  490. tempfreelist:=nil;
  491. templist:=nil;
  492. end;
  493. begin
  494. InitTemps;
  495. end.
  496. {
  497. $Log$
  498. Revision 1.7 2000-11-29 00:30:42 florian
  499. * unused units removed from uses clause
  500. * some changes for widestrings
  501. Revision 1.6 2000/11/04 14:25:22 florian
  502. + merged Attila's changes for interfaces, not tested yet
  503. Revision 1.5 2000/09/30 16:08:45 peter
  504. * more cg11 updates
  505. Revision 1.4 2000/09/24 15:06:31 peter
  506. * use defines.inc
  507. Revision 1.3 2000/08/27 16:11:55 peter
  508. * moved some util functions from globals,cobjects to cutils
  509. * splitted files into finput,fmodule
  510. Revision 1.2 2000/07/13 11:32:52 michael
  511. + removed logs
  512. }