temp_gen.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. {
  2. $Id$
  3. Copyright (C) 1993-98 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. interface
  20. uses
  21. cpubase,cpuinfo,cobjects,globals,tree,hcodegen,verbose,files,aasm;
  22. type
  23. ttemptype = (tt_none,tt_free,tt_normal,tt_persistant,tt_ansistring,tt_freeansistring,tt_widestring,tt_freewidestring);
  24. ttemptypeset = set of ttemptype;
  25. ptemprecord = ^ttemprecord;
  26. ttemprecord = record
  27. temptype : ttemptype;
  28. pos : longint;
  29. size : longint;
  30. next : ptemprecord;
  31. nextfree : ptemprecord; { for faster freeblock checking }
  32. {$ifdef EXTDEBUG}
  33. posinfo,
  34. releaseposinfo : tfileposinfo;
  35. {$endif}
  36. end;
  37. var
  38. { contains all temps }
  39. templist : ptemprecord;
  40. { contains all free temps using nextfree links }
  41. tempfreelist : ptemprecord;
  42. { Offsets of the first/last temp }
  43. firsttemp,
  44. lasttemp : longint;
  45. { generates temporary variables }
  46. procedure resettempgen;
  47. procedure setfirsttemp(l : longint);
  48. function gettempsize : longint;
  49. function newtempofsize(size : longint) : longint;
  50. function gettempofsize(size : longint) : longint;
  51. { special call for inlined procedures }
  52. function gettempofsizepersistant(size : longint) : longint;
  53. { for parameter func returns }
  54. procedure normaltemptopersistant(pos : longint);
  55. procedure persistanttemptonormal(pos : longint);
  56. {procedure ungettemp(pos : longint;size : longint);}
  57. procedure ungetpersistanttemp(pos : longint);
  58. procedure gettempofsizereference(l : longint;var ref : treference);
  59. function istemp(const ref : treference) : boolean;
  60. procedure ungetiftemp(const ref : treference);
  61. function ungetiftempansi(const ref : treference) : boolean;
  62. function gettempansistringreference(var ref : treference):boolean;
  63. implementation
  64. uses
  65. scanner,systems
  66. {$ifdef i386}
  67. ,cgai386
  68. {$endif i386}
  69. {$ifdef m68k}
  70. ,cga68k
  71. {$endif m68k}
  72. ;
  73. procedure resettempgen;
  74. var
  75. hp : ptemprecord;
  76. begin
  77. { Clear the old templist }
  78. while assigned(templist) do
  79. begin
  80. {$ifdef EXTDEBUG}
  81. case templist^.temptype of
  82. tt_normal,
  83. tt_persistant :
  84. Comment(V_Warning,'temporary assignment of size '+
  85. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  86. ':'+tostr(templist^.posinfo.column)+
  87. ' at pos '+tostr(templist^.pos)+
  88. ' not freed at the end of the procedure');
  89. tt_ansistring :
  90. Comment(V_Warning,'temporary ANSI assignment of size '+
  91. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  92. ':'+tostr(templist^.posinfo.column)+
  93. ' at pos '+tostr(templist^.pos)+
  94. ' not freed at the end of the procedure');
  95. end;
  96. {$endif}
  97. hp:=templist;
  98. templist:=hp^.next;
  99. dispose(hp);
  100. end;
  101. templist:=nil;
  102. tempfreelist:=nil;
  103. firsttemp:=0;
  104. lasttemp:=0;
  105. end;
  106. procedure setfirsttemp(l : longint);
  107. begin
  108. { this is a negative value normally }
  109. if l < 0 then
  110. Begin
  111. if odd(l) then
  112. Dec(l);
  113. end
  114. else
  115. Begin
  116. if odd(l) then
  117. Inc(l);
  118. end;
  119. firsttemp:=l;
  120. lasttemp:=l;
  121. end;
  122. function newtempofsize(size : longint) : longint;
  123. var
  124. tl : ptemprecord;
  125. begin
  126. { Just extend the temp, everything below has been use
  127. already }
  128. dec(lasttemp,size);
  129. { now we can create the templist entry }
  130. new(tl);
  131. tl^.temptype:=tt_normal;
  132. tl^.pos:=lasttemp;
  133. tl^.size:=size;
  134. tl^.next:=templist;
  135. tl^.nextfree:=nil;
  136. templist:=tl;
  137. newtempofsize:=tl^.pos;
  138. end;
  139. function gettempofsize(size : longint) : longint;
  140. var
  141. tl,
  142. bestslot,bestprev,
  143. hprev,hp : ptemprecord;
  144. bestsize,ofs : longint;
  145. begin
  146. bestprev:=nil;
  147. bestslot:=nil;
  148. tl:=nil;
  149. bestsize:=0;
  150. { Align needed size on 4 bytes }
  151. if (size mod 4)<>0 then
  152. size:=size+(4-(size mod 4));
  153. { First check the tmpfreelist }
  154. if assigned(tempfreelist) then
  155. begin
  156. { Check for a slot with the same size first }
  157. hprev:=nil;
  158. hp:=tempfreelist;
  159. while assigned(hp) do
  160. begin
  161. {$ifdef EXTDEBUG}
  162. if hp^.temptype<>tt_free then
  163. Comment(V_Warning,'Temp in freelist is not set to tt_free');
  164. {$endif}
  165. if hp^.size>=size then
  166. begin
  167. { Slot is the same size, then leave immediatly }
  168. if hp^.size=size then
  169. begin
  170. bestprev:=hprev;
  171. bestslot:=hp;
  172. bestsize:=size;
  173. break;
  174. end
  175. else
  176. begin
  177. if (bestsize=0) or (hp^.size<bestsize) then
  178. begin
  179. bestprev:=hprev;
  180. bestslot:=hp;
  181. bestsize:=hp^.size;
  182. end;
  183. end;
  184. end;
  185. hprev:=hp;
  186. hp:=hp^.nextfree;
  187. end;
  188. end;
  189. { Reuse an old temp ? }
  190. if assigned(bestslot) then
  191. begin
  192. if bestsize=size then
  193. begin
  194. bestslot^.temptype:=tt_normal;
  195. ofs:=bestslot^.pos;
  196. tl:=bestslot;
  197. { Remove from the tempfreelist }
  198. if assigned(bestprev) then
  199. bestprev^.nextfree:=bestslot^.nextfree
  200. else
  201. tempfreelist:=bestslot^.nextfree;
  202. end
  203. else
  204. begin
  205. { Resize the old block }
  206. dec(bestslot^.size,size);
  207. { Create new block and link after bestslot }
  208. new(tl);
  209. tl^.temptype:=tt_normal;
  210. tl^.pos:=bestslot^.pos+bestslot^.size;
  211. ofs:=tl^.pos;
  212. tl^.size:=size;
  213. tl^.nextfree:=nil;
  214. { link the new block }
  215. tl^.next:=bestslot^.next;
  216. bestslot^.next:=tl;
  217. end;
  218. end
  219. else
  220. begin
  221. ofs:=newtempofsize(size);
  222. {$ifdef EXTDEBUG}
  223. tl:=templist;
  224. {$endif}
  225. end;
  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. templist^.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. begin
  246. gettempsize:=Align(-lasttemp,target_os.stackalignment);
  247. end;
  248. procedure gettempofsizereference(l : longint;var ref : treference);
  249. begin
  250. { do a reset, because the reference isn't used }
  251. reset_reference(ref);
  252. ref.offset:=gettempofsize(l);
  253. ref.base:=procinfo.framepointer;
  254. end;
  255. function gettempansistringreference(var ref : treference):boolean;
  256. var
  257. foundslot,tl : ptemprecord;
  258. begin
  259. { do a reset, because the reference isn't used }
  260. reset_reference(ref);
  261. ref.base:=procinfo.framepointer;
  262. { Reuse old ansi slot ? }
  263. foundslot:=nil;
  264. tl:=templist;
  265. while assigned(tl) do
  266. begin
  267. if tl^.temptype=tt_freeansistring then
  268. begin
  269. foundslot:=tl;
  270. {$ifdef EXTDEBUG}
  271. tl^.posinfo:=aktfilepos;
  272. {$endif}
  273. break;
  274. end;
  275. tl:=tl^.next;
  276. end;
  277. if assigned(foundslot) then
  278. begin
  279. foundslot^.temptype:=tt_ansistring;
  280. ref.offset:=foundslot^.pos;
  281. { we're reusing an old slot then set the function result to true
  282. so that we can call a decr_ansistr }
  283. gettempansistringreference:=true;
  284. end
  285. else
  286. begin
  287. ref.offset:=newtempofsize(target_os.size_of_pointer);
  288. {$ifdef EXTDEBUG}
  289. templist^.posinfo:=aktfilepos;
  290. {$endif}
  291. templist^.temptype:=tt_ansistring;
  292. { set result to false, we don't need an decr_ansistr }
  293. gettempansistringreference:=true;
  294. end;
  295. exprasmlist^.concat(new(paitempalloc,alloc(ref.offset,target_os.size_of_pointer)));
  296. end;
  297. function ungetiftempansi(const ref : treference) : boolean;
  298. var
  299. tl : ptemprecord;
  300. begin
  301. ungetiftempansi:=false;
  302. tl:=templist;
  303. while assigned(tl) do
  304. begin
  305. if tl^.pos=ref.offset then
  306. begin
  307. if tl^.temptype=tt_ansistring then
  308. begin
  309. tl^.temptype:=tt_freeansistring;
  310. ungetiftempansi:=true;
  311. exprasmlist^.concat(new(paitempalloc,dealloc(tl^.pos,tl^.size)));
  312. exit;
  313. {$ifdef EXTDEBUG}
  314. end
  315. else if (tl^.temptype=tt_freeansistring) then
  316. begin
  317. Comment(V_Debug,'temp ansi managment problem : ungetiftempansi()'+
  318. ' at pos '+tostr(ref.offset)+ ' already free !');
  319. {$endif}
  320. end;
  321. end;
  322. tl:=tl^.next;
  323. end;
  324. end;
  325. function istemp(const ref : treference) : boolean;
  326. begin
  327. { ref.index = R_NO was missing
  328. led to problems with local arrays
  329. with lower bound > 0 (PM) }
  330. istemp:=((ref.base=procinfo.framepointer) and
  331. {$ifndef alpha}
  332. (ref.index=R_NO) and
  333. {$endif}
  334. (ref.offset<firsttemp));
  335. end;
  336. procedure persistanttemptonormal(pos : longint);
  337. var
  338. hp : ptemprecord;
  339. begin
  340. hp:=templist;
  341. while assigned(hp) do
  342. if (hp^.pos=pos) and (hp^.temptype=tt_persistant) then
  343. begin
  344. {$ifdef EXTDEBUG}
  345. Comment(V_Debug,'temp managment : persistanttemptonormal()'+
  346. ' at pos '+tostr(pos)+ ' found !');
  347. {$endif}
  348. hp^.temptype:=tt_normal;
  349. exit;
  350. end
  351. else
  352. hp:=hp^.next;
  353. {$ifdef EXTDEBUG}
  354. Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
  355. ' at pos '+tostr(pos)+ ' not found !');
  356. {$endif}
  357. end;
  358. procedure normaltemptopersistant(pos : longint);
  359. var
  360. hp : ptemprecord;
  361. begin
  362. hp:=templist;
  363. while assigned(hp) do
  364. if (hp^.pos=pos) and (hp^.temptype=tt_normal) then
  365. begin
  366. {$ifdef EXTDEBUG}
  367. Comment(V_Debug,'temp managment : normaltemptopersistant()'+
  368. ' at pos '+tostr(pos)+ ' found !');
  369. {$endif}
  370. hp^.temptype:=tt_persistant;
  371. exit;
  372. end
  373. else
  374. hp:=hp^.next;
  375. {$ifdef EXTDEBUG}
  376. Comment(V_Debug,'temp managment problem : normaltemptopersistant()'+
  377. ' at pos '+tostr(pos)+ ' not found !');
  378. {$endif}
  379. end;
  380. function ungettemp(pos:longint;allowtype:ttemptype):ttemptype;
  381. var
  382. hp,hnext,hprev,hprevfree : ptemprecord;
  383. begin
  384. ungettemp:=tt_none;
  385. hp:=templist;
  386. hprev:=nil;
  387. hprevfree:=nil;
  388. while assigned(hp) do
  389. begin
  390. if (hp^.pos=pos) then
  391. begin
  392. { check type }
  393. ungettemp:=hp^.temptype;
  394. if hp^.temptype<>allowtype then
  395. begin
  396. exit;
  397. end;
  398. exprasmlist^.concat(new(paitempalloc,dealloc(hp^.pos,hp^.size)));
  399. { set this block to free }
  400. hp^.temptype:=tt_free;
  401. { Update tempfreelist }
  402. if assigned(hprevfree) then
  403. begin
  404. { Connect with previous? }
  405. if assigned(hprev) and (hprev^.temptype=tt_free) then
  406. begin
  407. inc(hprev^.size,hp^.size);
  408. hprev^.next:=hp^.next;
  409. dispose(hp);
  410. hp:=hprev;
  411. end
  412. else
  413. hprevfree^.nextfree:=hp;
  414. end
  415. else
  416. begin
  417. hp^.nextfree:=tempfreelist;
  418. tempfreelist:=hp;
  419. end;
  420. { Next block free ? Yes, then concat }
  421. hnext:=hp^.next;
  422. if assigned(hnext) and (hnext^.temptype=tt_free) then
  423. begin
  424. inc(hp^.size,hnext^.size);
  425. hp^.nextfree:=hnext^.nextfree;
  426. hp^.next:=hnext^.next;
  427. dispose(hnext);
  428. end;
  429. exit;
  430. end;
  431. if (hp^.temptype=tt_free) then
  432. hprevfree:=hp;
  433. hprev:=hp;
  434. hp:=hp^.next;
  435. end;
  436. ungettemp:=tt_none;
  437. end;
  438. procedure ungetpersistanttemp(pos : longint);
  439. begin
  440. {$ifdef EXTDEBUG}
  441. if ungettemp(pos,tt_persistant)<>tt_persistant then
  442. Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
  443. ' at pos '+tostr(pos)+ ' not found !');
  444. {$else}
  445. ungettemp(pos,tt_persistant);
  446. {$endif}
  447. end;
  448. procedure ungetiftemp(const ref : treference);
  449. var
  450. tt : ttemptype;
  451. begin
  452. if istemp(ref) then
  453. begin
  454. { first check if ansistring }
  455. if ungetiftempansi(ref) then
  456. exit;
  457. tt:=ungettemp(ref.offset,tt_normal);
  458. {$ifdef EXTDEBUG}
  459. if tt=tt_persistant then
  460. Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!');
  461. if tt=tt_none then
  462. Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset));
  463. {$endif}
  464. end;
  465. end;
  466. procedure inittemps;
  467. begin
  468. tempfreelist:=nil;
  469. templist:=nil;
  470. end;
  471. begin
  472. InitTemps;
  473. end.
  474. {
  475. $Log$
  476. Revision 1.34 1999-08-04 00:23:46 florian
  477. * renamed i386asm and i386base to cpuasm and cpubase
  478. Revision 1.33 1999/08/02 00:34:06 michael
  479. * alpha has no index
  480. Revision 1.32 1999/06/09 23:00:13 peter
  481. * small ansistring fixes
  482. * val_ansistr_sint destsize changed to longint
  483. * don't write low/hi ascii with -al
  484. Revision 1.31 1999/06/01 22:46:26 pierre
  485. * extdebug wrong warning removed
  486. Revision 1.30 1999/05/31 20:35:47 peter
  487. * ansistring fixes, decr_ansistr called after all temp ansi reuses
  488. Revision 1.29 1999/05/27 19:45:26 peter
  489. * removed oldasm
  490. * plabel -> pasmlabel
  491. * -a switches to source writing automaticly
  492. * assembler readers OOPed
  493. * asmsymbol automaticly external
  494. * jumptables and other label fixes for asm readers
  495. Revision 1.28 1999/05/21 17:23:47 peter
  496. * align tempsize also on stackalignment
  497. Revision 1.27 1999/05/21 11:46:28 pierre
  498. * bestsize bug fixed
  499. Revision 1.26 1999/05/19 11:51:00 pierre
  500. * posinfo was not set for ansitemps !
  501. Revision 1.25 1999/05/17 23:51:47 peter
  502. * with temp vars now use a reference with a persistant temp instead
  503. of setting datasize
  504. Revision 1.24 1999/05/17 21:57:17 florian
  505. * new temporary ansistring handling
  506. Revision 1.23 1999/05/17 12:49:16 pierre
  507. * several problems with EXTDEBUG fixed
  508. Revision 1.22 1999/05/15 21:33:21 peter
  509. * redesigned temp_gen temp allocation so temp allocation for
  510. ansistring works correct. It also does a best fit instead of first fit
  511. Revision 1.21 1999/05/01 13:24:59 peter
  512. * merged nasm compiler
  513. * old asm moved to oldasm/
  514. Revision 1.20 1999/04/19 09:30:48 pierre
  515. + added warning for unreleased ANSI temp
  516. Revision 1.19 1999/04/16 20:44:38 florian
  517. * the boolean operators =;<>;xor with LOC_JUMP and LOC_FLAGS
  518. operands fixed, small things for new ansistring management
  519. Revision 1.18 1999/04/16 14:03:39 pierre
  520. * added paitempalloc for tempansi
  521. Revision 1.17 1999/04/16 11:49:45 peter
  522. + tempalloc
  523. + -at to show temp alloc info in .s file
  524. Revision 1.16 1999/04/14 09:10:46 peter
  525. * fixed tempansi which set wrong pos in free temp
  526. Revision 1.15 1999/04/09 13:05:45 pierre
  527. * Minenumsize=1 under TEST_ENUMSIZE cond because buggy
  528. Revision 1.14 1999/04/09 09:55:20 peter
  529. * typo fixed
  530. Revision 1.13 1999/04/09 08:39:20 peter
  531. * fixed reuse position
  532. Revision 1.12 1999/04/08 23:52:59 pierre
  533. + tempansilist and gettempansistringreference
  534. Revision 1.11 1999/04/08 20:59:44 florian
  535. * fixed problem with default properties which are a class
  536. * case bug (from the mailing list with -O2) fixed, the
  537. distance of the case labels can be greater than the positive
  538. range of a longint => it is now a dword for fpc
  539. Revision 1.10 1999/04/06 11:19:49 peter
  540. * fixed temp reuse
  541. Revision 1.9 1999/02/22 02:15:56 peter
  542. * updates for ag386bin
  543. Revision 1.8 1999/02/11 09:35:19 pierre
  544. * ExtDebug conditionnal infinite loop on temp problem removed
  545. Revision 1.7 1999/02/02 23:52:33 florian
  546. * problem with calls to method pointers in methods fixed
  547. - double ansistrings temp management removed
  548. Revision 1.6 1999/01/15 11:34:23 pierre
  549. + better info for temp allocation debugging
  550. Revision 1.5 1998/11/30 09:43:24 pierre
  551. * some range check bugs fixed (still not working !)
  552. + added DLL writing support for win32 (also accepts variables)
  553. + TempAnsi for code that could be used for Temporary ansi strings
  554. handling
  555. Revision 1.4 1998/10/09 08:56:32 pierre
  556. * several memory leaks fixed
  557. Revision 1.3 1998/07/16 08:01:42 pierre
  558. * small bug correction due to newinput
  559. (only with tempdebug conditionnal)
  560. Revision 1.2 1998/07/10 10:51:05 peter
  561. * m68k updates
  562. Revision 1.1 1998/06/08 16:07:41 pierre
  563. * temp_gen contains all temporary var functions
  564. (processor independent)
  565. }