temp_gen.pas 20 KB

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