temp_gen.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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. procedure gettempansistringreference(var ref : treference);
  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. procedure gettempansistringreference(var ref : treference);
  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. { we never know if a slot was used previously:
  284. imagine a loop: in the first run the slot wasn't used
  285. while in later runs it is reused (FK)
  286. gettempansistringreference:=true;
  287. }
  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:=tt_ansistring;
  296. { set result to false, we don't need an decr_ansistr
  297. gettempansistringreference:=true;
  298. Not necessary, the above (FK)
  299. }
  300. end;
  301. exprasmlist^.concat(new(paitempalloc,alloc(ref.offset,target_os.size_of_pointer)));
  302. end;
  303. function ungetiftempansi(const ref : treference) : boolean;
  304. var
  305. tl : ptemprecord;
  306. begin
  307. ungetiftempansi:=false;
  308. tl:=templist;
  309. while assigned(tl) do
  310. begin
  311. if tl^.pos=ref.offset then
  312. begin
  313. if tl^.temptype=tt_ansistring then
  314. begin
  315. tl^.temptype:=tt_freeansistring;
  316. ungetiftempansi:=true;
  317. exprasmlist^.concat(new(paitempalloc,dealloc(tl^.pos,tl^.size)));
  318. exit;
  319. {$ifdef EXTDEBUG}
  320. end
  321. else if (tl^.temptype=tt_freeansistring) then
  322. begin
  323. Comment(V_Debug,'temp ansi managment problem : ungetiftempansi()'+
  324. ' at pos '+tostr(ref.offset)+ ' already free !');
  325. {$endif}
  326. end;
  327. end;
  328. tl:=tl^.next;
  329. end;
  330. end;
  331. function istemp(const ref : treference) : boolean;
  332. begin
  333. { ref.index = R_NO was missing
  334. led to problems with local arrays
  335. with lower bound > 0 (PM) }
  336. istemp:=((ref.base=procinfo^.framepointer) and
  337. {$ifndef alpha}
  338. (ref.index=R_NO) and
  339. {$endif}
  340. (ref.offset<firsttemp));
  341. end;
  342. procedure persistanttemptonormal(pos : longint);
  343. var
  344. hp : ptemprecord;
  345. begin
  346. hp:=templist;
  347. while assigned(hp) do
  348. if (hp^.pos=pos) and (hp^.temptype=tt_persistant) then
  349. begin
  350. {$ifdef EXTDEBUG}
  351. Comment(V_Debug,'temp managment : persistanttemptonormal()'+
  352. ' at pos '+tostr(pos)+ ' found !');
  353. {$endif}
  354. hp^.temptype:=tt_normal;
  355. exit;
  356. end
  357. else
  358. hp:=hp^.next;
  359. {$ifdef EXTDEBUG}
  360. Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
  361. ' at pos '+tostr(pos)+ ' not found !');
  362. {$endif}
  363. end;
  364. procedure normaltemptopersistant(pos : longint);
  365. var
  366. hp : ptemprecord;
  367. begin
  368. hp:=templist;
  369. while assigned(hp) do
  370. if (hp^.pos=pos) and (hp^.temptype=tt_normal) then
  371. begin
  372. {$ifdef EXTDEBUG}
  373. Comment(V_Debug,'temp managment : normaltemptopersistant()'+
  374. ' at pos '+tostr(pos)+ ' found !');
  375. {$endif}
  376. hp^.temptype:=tt_persistant;
  377. exit;
  378. end
  379. else
  380. hp:=hp^.next;
  381. {$ifdef EXTDEBUG}
  382. Comment(V_Debug,'temp managment problem : normaltemptopersistant()'+
  383. ' at pos '+tostr(pos)+ ' not found !');
  384. {$endif}
  385. end;
  386. function ungettemp(pos:longint;allowtype:ttemptype):ttemptype;
  387. var
  388. hp,hnext,hprev,hprevfree : ptemprecord;
  389. begin
  390. ungettemp:=tt_none;
  391. hp:=templist;
  392. hprev:=nil;
  393. hprevfree:=nil;
  394. while assigned(hp) do
  395. begin
  396. if (hp^.pos=pos) then
  397. begin
  398. { check type }
  399. ungettemp:=hp^.temptype;
  400. if hp^.temptype<>allowtype then
  401. begin
  402. exit;
  403. end;
  404. exprasmlist^.concat(new(paitempalloc,dealloc(hp^.pos,hp^.size)));
  405. { set this block to free }
  406. hp^.temptype:=tt_free;
  407. { Update tempfreelist }
  408. if assigned(hprevfree) then
  409. begin
  410. { Connect with previous? }
  411. if assigned(hprev) and (hprev^.temptype=tt_free) then
  412. begin
  413. inc(hprev^.size,hp^.size);
  414. hprev^.next:=hp^.next;
  415. dispose(hp);
  416. hp:=hprev;
  417. end
  418. else
  419. hprevfree^.nextfree:=hp;
  420. end
  421. else
  422. begin
  423. hp^.nextfree:=tempfreelist;
  424. tempfreelist:=hp;
  425. end;
  426. { Next block free ? Yes, then concat }
  427. hnext:=hp^.next;
  428. if assigned(hnext) and (hnext^.temptype=tt_free) then
  429. begin
  430. inc(hp^.size,hnext^.size);
  431. hp^.nextfree:=hnext^.nextfree;
  432. hp^.next:=hnext^.next;
  433. dispose(hnext);
  434. end;
  435. exit;
  436. end;
  437. if (hp^.temptype=tt_free) then
  438. hprevfree:=hp;
  439. hprev:=hp;
  440. hp:=hp^.next;
  441. end;
  442. ungettemp:=tt_none;
  443. end;
  444. procedure ungetpersistanttemp(pos : longint);
  445. begin
  446. {$ifdef EXTDEBUG}
  447. if ungettemp(pos,tt_persistant)<>tt_persistant then
  448. Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
  449. ' at pos '+tostr(pos)+ ' not found !');
  450. {$else}
  451. ungettemp(pos,tt_persistant);
  452. {$endif}
  453. end;
  454. procedure ungetiftemp(const ref : treference);
  455. {$ifdef EXTDEBUG}
  456. var
  457. tt : ttemptype;
  458. {$endif}
  459. begin
  460. if istemp(ref) then
  461. begin
  462. { first check if ansistring }
  463. if ungetiftempansi(ref) then
  464. exit;
  465. {$ifndef EXTDEBUG}
  466. ungettemp(ref.offset,tt_normal);
  467. {$else}
  468. tt:=ungettemp(ref.offset,tt_normal);
  469. if tt=tt_persistant then
  470. Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!');
  471. if tt=tt_none then
  472. Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset));
  473. {$endif}
  474. end;
  475. end;
  476. procedure inittemps;
  477. begin
  478. tempfreelist:=nil;
  479. templist:=nil;
  480. end;
  481. begin
  482. InitTemps;
  483. end.
  484. {
  485. $Log$
  486. Revision 1.39 1999-12-01 12:42:33 peter
  487. * fixed bug 698
  488. * removed some notes about unused vars
  489. Revision 1.38 1999/11/06 14:34:31 peter
  490. * truncated log to 20 revs
  491. Revision 1.37 1999/09/27 23:45:02 peter
  492. * procinfo is now a pointer
  493. * support for result setting in sub procedure
  494. Revision 1.36 1999/09/26 13:26:08 florian
  495. * exception patch of Romio nevertheless the excpetion handling
  496. needs some corections regarding register saving
  497. * gettempansistring is again a procedure
  498. Revision 1.35 1999/09/16 11:34:59 pierre
  499. * typo correction
  500. Revision 1.34 1999/08/04 00:23:46 florian
  501. * renamed i386asm and i386base to cpuasm and cpubase
  502. Revision 1.33 1999/08/02 00:34:06 michael
  503. * alpha has no index
  504. Revision 1.32 1999/06/09 23:00:13 peter
  505. * small ansistring fixes
  506. * val_ansistr_sint destsize changed to longint
  507. * don't write low/hi ascii with -al
  508. Revision 1.31 1999/06/01 22:46:26 pierre
  509. * extdebug wrong warning removed
  510. Revision 1.30 1999/05/31 20:35:47 peter
  511. * ansistring fixes, decr_ansistr called after all temp ansi reuses
  512. Revision 1.29 1999/05/27 19:45:26 peter
  513. * removed oldasm
  514. * plabel -> pasmlabel
  515. * -a switches to source writing automaticly
  516. * assembler readers OOPed
  517. * asmsymbol automaticly external
  518. * jumptables and other label fixes for asm readers
  519. Revision 1.28 1999/05/21 17:23:47 peter
  520. * align tempsize also on stackalignment
  521. Revision 1.27 1999/05/21 11:46:28 pierre
  522. * bestsize bug fixed
  523. Revision 1.26 1999/05/19 11:51:00 pierre
  524. * posinfo was not set for ansitemps !
  525. Revision 1.25 1999/05/17 23:51:47 peter
  526. * with temp vars now use a reference with a persistant temp instead
  527. of setting datasize
  528. Revision 1.24 1999/05/17 21:57:17 florian
  529. * new temporary ansistring handling
  530. Revision 1.23 1999/05/17 12:49:16 pierre
  531. * several problems with EXTDEBUG fixed
  532. Revision 1.22 1999/05/15 21:33:21 peter
  533. * redesigned temp_gen temp allocation so temp allocation for
  534. ansistring works correct. It also does a best fit instead of first fit
  535. Revision 1.21 1999/05/01 13:24:59 peter
  536. * merged nasm compiler
  537. * old asm moved to oldasm/
  538. Revision 1.20 1999/04/19 09:30:48 pierre
  539. + added warning for unreleased ANSI temp
  540. Revision 1.19 1999/04/16 20:44:38 florian
  541. * the boolean operators =;<>;xor with LOC_JUMP and LOC_FLAGS
  542. operands fixed, small things for new ansistring management
  543. Revision 1.18 1999/04/16 14:03:39 pierre
  544. * added paitempalloc for tempansi
  545. }