temp_gen.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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.alignment.localalignmin;
  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.16 2001-07-01 20:16:18 peter
  554. * alignmentinfo record added
  555. * -Oa argument supports more alignment settings that can be specified
  556. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  557. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  558. required alignment and the maximum usefull alignment. The final
  559. alignment will be choosen per variable size dependent on these
  560. settings
  561. Revision 1.15 2001/06/02 19:20:10 peter
  562. * allocate at least 4 bytes, also for 0 byte temps. Give a warning
  563. with extdebug
  564. Revision 1.14 2001/05/27 14:30:55 florian
  565. + some widestring stuff added
  566. Revision 1.13 2001/04/18 22:02:00 peter
  567. * registration of targets and assemblers
  568. Revision 1.12 2001/04/13 01:22:17 peter
  569. * symtable change to classes
  570. * range check generation and errors fixed, make cycle DEBUG=1 works
  571. * memory leaks fixed
  572. Revision 1.11 2001/01/05 17:36:58 florian
  573. * the info about exception frames is stored now on the stack
  574. instead on the heap
  575. Revision 1.10 2000/12/31 11:04:43 jonas
  576. + sizeoftemp() function
  577. Revision 1.9 2000/12/25 00:07:30 peter
  578. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  579. tlinkedlist objects)
  580. Revision 1.8 2000/11/30 22:16:50 florian
  581. * moved to i386
  582. Revision 1.7 2000/11/29 00:30:42 florian
  583. * unused units removed from uses clause
  584. * some changes for widestrings
  585. Revision 1.6 2000/11/04 14:25:22 florian
  586. + merged Attila's changes for interfaces, not tested yet
  587. Revision 1.5 2000/09/30 16:08:45 peter
  588. * more cg11 updates
  589. Revision 1.4 2000/09/24 15:06:31 peter
  590. * use defines.inc
  591. Revision 1.3 2000/08/27 16:11:55 peter
  592. * moved some util functions from globals,cobjects to cutils
  593. * splitted files into finput,fmodule
  594. Revision 1.2 2000/07/13 11:32:52 michael
  595. + removed logs
  596. }