temp_gen.pas 21 KB

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