temp_gen.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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,cobjects,globals,
  23. hcodegen,verbose,fmodule,aasm;
  24. type
  25. ttemptype = (tt_none,tt_free,tt_normal,tt_persistant,tt_ansistring,tt_freeansistring,tt_widestring,tt_freewidestring);
  26. ttemptypeset = set of ttemptype;
  27. ptemprecord = ^ttemprecord;
  28. ttemprecord = record
  29. temptype : ttemptype;
  30. pos : longint;
  31. size : longint;
  32. next : ptemprecord;
  33. nextfree : ptemprecord; { for faster freeblock checking }
  34. {$ifdef EXTDEBUG}
  35. posinfo,
  36. releaseposinfo : tfileposinfo;
  37. {$endif}
  38. end;
  39. var
  40. { contains all temps }
  41. templist : ptemprecord;
  42. { contains all free temps using nextfree links }
  43. tempfreelist : ptemprecord;
  44. { Offsets of the first/last temp }
  45. firsttemp,
  46. lasttemp : longint;
  47. { generates temporary variables }
  48. procedure resettempgen;
  49. procedure setfirsttemp(l : longint);
  50. function gettempsize : longint;
  51. function newtempofsize(size : longint) : longint;
  52. function gettempofsize(size : longint) : longint;
  53. { special call for inlined procedures }
  54. function gettempofsizepersistant(size : longint) : longint;
  55. { for parameter func returns }
  56. procedure normaltemptopersistant(pos : longint);
  57. procedure persistanttemptonormal(pos : longint);
  58. {procedure ungettemp(pos : longint;size : longint);}
  59. procedure ungetpersistanttemp(pos : longint);
  60. procedure gettempofsizereference(l : longint;var ref : treference);
  61. function istemp(const ref : treference) : boolean;
  62. procedure ungetiftemp(const ref : treference);
  63. function ungetiftempansi(const ref : treference) : boolean;
  64. procedure gettempansistringreference(var ref : treference);
  65. implementation
  66. uses
  67. cutils,scanner,systems
  68. {$ifdef i386}
  69. ,cgai386
  70. {$endif i386}
  71. {$ifdef m68k}
  72. ,cga68k
  73. {$endif m68k}
  74. ;
  75. procedure resettempgen;
  76. var
  77. hp : ptemprecord;
  78. begin
  79. { Clear the old templist }
  80. while assigned(templist) do
  81. begin
  82. {$ifdef EXTDEBUG}
  83. case templist^.temptype of
  84. tt_normal,
  85. tt_persistant :
  86. Comment(V_Warning,'temporary assignment of size '+
  87. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  88. ':'+tostr(templist^.posinfo.column)+
  89. ' at pos '+tostr(templist^.pos)+
  90. ' not freed at the end of the procedure');
  91. tt_ansistring :
  92. Comment(V_Warning,'temporary ANSI assignment of size '+
  93. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  94. ':'+tostr(templist^.posinfo.column)+
  95. ' at pos '+tostr(templist^.pos)+
  96. ' not freed at the end of the procedure');
  97. end;
  98. {$endif}
  99. hp:=templist;
  100. templist:=hp^.next;
  101. dispose(hp);
  102. end;
  103. templist:=nil;
  104. tempfreelist:=nil;
  105. firsttemp:=0;
  106. lasttemp:=0;
  107. end;
  108. procedure setfirsttemp(l : longint);
  109. begin
  110. { this is a negative value normally }
  111. if l < 0 then
  112. Begin
  113. if odd(l) then
  114. Dec(l);
  115. end
  116. else
  117. Begin
  118. if odd(l) then
  119. Inc(l);
  120. end;
  121. firsttemp:=l;
  122. lasttemp:=l;
  123. end;
  124. function newtempofsize(size : longint) : longint;
  125. var
  126. tl : ptemprecord;
  127. begin
  128. { Just extend the temp, everything below has been use
  129. already }
  130. dec(lasttemp,size);
  131. { now we can create the templist entry }
  132. new(tl);
  133. tl^.temptype:=tt_normal;
  134. tl^.pos:=lasttemp;
  135. tl^.size:=size;
  136. tl^.next:=templist;
  137. tl^.nextfree:=nil;
  138. templist:=tl;
  139. newtempofsize:=tl^.pos;
  140. end;
  141. const
  142. lasttempofsize : ptemprecord = nil;
  143. function gettempofsize(size : longint) : longint;
  144. var
  145. tl,
  146. bestslot,bestprev,
  147. hprev,hp : ptemprecord;
  148. bestsize,ofs : longint;
  149. begin
  150. bestprev:=nil;
  151. bestslot:=nil;
  152. tl:=nil;
  153. bestsize:=0;
  154. { Align needed size on 4 bytes }
  155. if (size mod 4)<>0 then
  156. size:=size+(4-(size mod 4));
  157. { First check the tmpfreelist }
  158. if assigned(tempfreelist) then
  159. begin
  160. { Check for a slot with the same size first }
  161. hprev:=nil;
  162. hp:=tempfreelist;
  163. while assigned(hp) do
  164. begin
  165. {$ifdef EXTDEBUG}
  166. if hp^.temptype<>tt_free then
  167. Comment(V_Warning,'Temp in freelist is not set to tt_free');
  168. {$endif}
  169. if hp^.size>=size then
  170. begin
  171. { Slot is the same size, then leave immediatly }
  172. if hp^.size=size then
  173. begin
  174. bestprev:=hprev;
  175. bestslot:=hp;
  176. bestsize:=size;
  177. break;
  178. end
  179. else
  180. begin
  181. if (bestsize=0) or (hp^.size<bestsize) then
  182. begin
  183. bestprev:=hprev;
  184. bestslot:=hp;
  185. bestsize:=hp^.size;
  186. end;
  187. end;
  188. end;
  189. hprev:=hp;
  190. hp:=hp^.nextfree;
  191. end;
  192. end;
  193. { Reuse an old temp ? }
  194. if assigned(bestslot) then
  195. begin
  196. if bestsize=size then
  197. begin
  198. bestslot^.temptype:=tt_normal;
  199. ofs:=bestslot^.pos;
  200. tl:=bestslot;
  201. { Remove from the tempfreelist }
  202. if assigned(bestprev) then
  203. bestprev^.nextfree:=bestslot^.nextfree
  204. else
  205. tempfreelist:=bestslot^.nextfree;
  206. end
  207. else
  208. begin
  209. { Resize the old block }
  210. dec(bestslot^.size,size);
  211. { Create new block and link after bestslot }
  212. new(tl);
  213. tl^.temptype:=tt_normal;
  214. tl^.pos:=bestslot^.pos+bestslot^.size;
  215. ofs:=tl^.pos;
  216. tl^.size:=size;
  217. tl^.nextfree:=nil;
  218. { link the new block }
  219. tl^.next:=bestslot^.next;
  220. bestslot^.next:=tl;
  221. end;
  222. end
  223. else
  224. begin
  225. ofs:=newtempofsize(size);
  226. tl:=templist;
  227. end;
  228. lasttempofsize:=tl;
  229. {$ifdef EXTDEBUG}
  230. tl^.posinfo:=aktfilepos;
  231. {$endif}
  232. exprasmlist^.concat(new(paitempalloc,alloc(ofs,size)));
  233. gettempofsize:=ofs;
  234. end;
  235. function gettempofsizepersistant(size : longint) : longint;
  236. var
  237. l : longint;
  238. begin
  239. l:=gettempofsize(size);
  240. lasttempofsize^.temptype:=tt_persistant;
  241. {$ifdef EXTDEBUG}
  242. Comment(V_Debug,'temp managment : call to gettempofsizepersistant()'+
  243. ' with size '+tostr(size)+' returned '+tostr(l));
  244. {$endif}
  245. gettempofsizepersistant:=l;
  246. end;
  247. function gettempsize : longint;
  248. var
  249. _align : longint;
  250. begin
  251. { align to 4 bytes at least
  252. otherwise all those subl $2,%esp are meaningless PM }
  253. _align:=target_os.stackalignment;
  254. if _align<4 then
  255. _align:=4;
  256. gettempsize:=Align(-lasttemp,_align);
  257. end;
  258. procedure gettempofsizereference(l : longint;var ref : treference);
  259. begin
  260. { do a reset, because the reference isn't used }
  261. reset_reference(ref);
  262. ref.offset:=gettempofsize(l);
  263. ref.base:=procinfo^.framepointer;
  264. end;
  265. procedure gettempansistringreference(var ref : treference);
  266. var
  267. foundslot,tl : ptemprecord;
  268. begin
  269. { do a reset, because the reference isn't used }
  270. reset_reference(ref);
  271. ref.base:=procinfo^.framepointer;
  272. { Reuse old ansi slot ? }
  273. foundslot:=nil;
  274. tl:=templist;
  275. while assigned(tl) do
  276. begin
  277. if tl^.temptype=tt_freeansistring then
  278. begin
  279. foundslot:=tl;
  280. {$ifdef EXTDEBUG}
  281. tl^.posinfo:=aktfilepos;
  282. {$endif}
  283. break;
  284. end;
  285. tl:=tl^.next;
  286. end;
  287. if assigned(foundslot) then
  288. begin
  289. foundslot^.temptype:=tt_ansistring;
  290. ref.offset:=foundslot^.pos;
  291. { we're reusing an old slot then set the function result to true
  292. so that we can call a decr_ansistr }
  293. { we never know if a slot was used previously:
  294. imagine a loop: in the first run the slot wasn't used
  295. while in later runs it is reused (FK)
  296. gettempansistringreference:=true;
  297. }
  298. end
  299. else
  300. begin
  301. ref.offset:=newtempofsize(target_os.size_of_pointer);
  302. {$ifdef EXTDEBUG}
  303. templist^.posinfo:=aktfilepos;
  304. {$endif}
  305. templist^.temptype:=tt_ansistring;
  306. { set result to false, we don't need an decr_ansistr
  307. gettempansistringreference:=true;
  308. Not necessary, the above (FK)
  309. }
  310. end;
  311. exprasmlist^.concat(new(paitempalloc,alloc(ref.offset,target_os.size_of_pointer)));
  312. end;
  313. function ungetiftempansi(const ref : treference) : boolean;
  314. var
  315. tl : ptemprecord;
  316. begin
  317. ungetiftempansi:=false;
  318. tl:=templist;
  319. while assigned(tl) do
  320. begin
  321. if tl^.pos=ref.offset then
  322. begin
  323. if tl^.temptype=tt_ansistring then
  324. begin
  325. tl^.temptype:=tt_freeansistring;
  326. ungetiftempansi:=true;
  327. exprasmlist^.concat(new(paitempalloc,dealloc(tl^.pos,tl^.size)));
  328. exit;
  329. {$ifdef EXTDEBUG}
  330. end
  331. else if (tl^.temptype=tt_freeansistring) then
  332. begin
  333. Comment(V_Debug,'temp ansi managment problem : ungetiftempansi()'+
  334. ' at pos '+tostr(ref.offset)+ ' already free !');
  335. {$endif}
  336. end;
  337. end;
  338. tl:=tl^.next;
  339. end;
  340. end;
  341. function istemp(const ref : treference) : boolean;
  342. begin
  343. { ref.index = R_NO was missing
  344. led to problems with local arrays
  345. with lower bound > 0 (PM) }
  346. istemp:=((ref.base=procinfo^.framepointer) and
  347. {$ifndef alpha}
  348. (ref.index=R_NO) and
  349. {$endif}
  350. (ref.offset<firsttemp));
  351. end;
  352. procedure persistanttemptonormal(pos : longint);
  353. var
  354. hp : ptemprecord;
  355. begin
  356. hp:=templist;
  357. while assigned(hp) do
  358. if (hp^.pos=pos) and (hp^.temptype=tt_persistant) then
  359. begin
  360. {$ifdef EXTDEBUG}
  361. Comment(V_Debug,'temp managment : persistanttemptonormal()'+
  362. ' at pos '+tostr(pos)+ ' found !');
  363. {$endif}
  364. hp^.temptype:=tt_normal;
  365. exit;
  366. end
  367. else
  368. hp:=hp^.next;
  369. {$ifdef EXTDEBUG}
  370. Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
  371. ' at pos '+tostr(pos)+ ' not found !');
  372. {$endif}
  373. end;
  374. procedure normaltemptopersistant(pos : longint);
  375. var
  376. hp : ptemprecord;
  377. begin
  378. hp:=templist;
  379. while assigned(hp) do
  380. if (hp^.pos=pos) and (hp^.temptype=tt_normal) then
  381. begin
  382. {$ifdef EXTDEBUG}
  383. Comment(V_Debug,'temp managment : normaltemptopersistant()'+
  384. ' at pos '+tostr(pos)+ ' found !');
  385. {$endif}
  386. hp^.temptype:=tt_persistant;
  387. exit;
  388. end
  389. else
  390. hp:=hp^.next;
  391. {$ifdef EXTDEBUG}
  392. Comment(V_Debug,'temp managment problem : normaltemptopersistant()'+
  393. ' at pos '+tostr(pos)+ ' not found !');
  394. {$endif}
  395. end;
  396. function ungettemp(pos:longint;allowtype:ttemptype):ttemptype;
  397. var
  398. hp,hnext,hprev,hprevfree : ptemprecord;
  399. begin
  400. ungettemp:=tt_none;
  401. hp:=templist;
  402. hprev:=nil;
  403. hprevfree:=nil;
  404. while assigned(hp) do
  405. begin
  406. if (hp^.pos=pos) then
  407. begin
  408. { check type }
  409. ungettemp:=hp^.temptype;
  410. if hp^.temptype<>allowtype then
  411. begin
  412. exit;
  413. end;
  414. exprasmlist^.concat(new(paitempalloc,dealloc(hp^.pos,hp^.size)));
  415. { set this block to free }
  416. hp^.temptype:=tt_free;
  417. { Update tempfreelist }
  418. if assigned(hprevfree) then
  419. begin
  420. { Connect with previous? }
  421. if assigned(hprev) and (hprev^.temptype=tt_free) then
  422. begin
  423. inc(hprev^.size,hp^.size);
  424. hprev^.next:=hp^.next;
  425. dispose(hp);
  426. hp:=hprev;
  427. end
  428. else
  429. hprevfree^.nextfree:=hp;
  430. end
  431. else
  432. begin
  433. hp^.nextfree:=tempfreelist;
  434. tempfreelist:=hp;
  435. end;
  436. { Next block free ? Yes, then concat }
  437. hnext:=hp^.next;
  438. if assigned(hnext) and (hnext^.temptype=tt_free) then
  439. begin
  440. inc(hp^.size,hnext^.size);
  441. hp^.nextfree:=hnext^.nextfree;
  442. hp^.next:=hnext^.next;
  443. dispose(hnext);
  444. end;
  445. exit;
  446. end;
  447. if (hp^.temptype=tt_free) then
  448. hprevfree:=hp;
  449. hprev:=hp;
  450. hp:=hp^.next;
  451. end;
  452. ungettemp:=tt_none;
  453. end;
  454. procedure ungetpersistanttemp(pos : longint);
  455. begin
  456. {$ifdef EXTDEBUG}
  457. if ungettemp(pos,tt_persistant)<>tt_persistant then
  458. Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
  459. ' at pos '+tostr(pos)+ ' not found !');
  460. {$else}
  461. ungettemp(pos,tt_persistant);
  462. {$endif}
  463. end;
  464. procedure ungetiftemp(const ref : treference);
  465. {$ifdef EXTDEBUG}
  466. var
  467. tt : ttemptype;
  468. {$endif}
  469. begin
  470. if istemp(ref) then
  471. begin
  472. { first check if ansistring }
  473. if ungetiftempansi(ref) then
  474. exit;
  475. {$ifndef EXTDEBUG}
  476. ungettemp(ref.offset,tt_normal);
  477. {$else}
  478. tt:=ungettemp(ref.offset,tt_normal);
  479. if tt=tt_persistant then
  480. Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!');
  481. if tt=tt_none then
  482. Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset));
  483. {$endif}
  484. end;
  485. end;
  486. procedure inittemps;
  487. begin
  488. tempfreelist:=nil;
  489. templist:=nil;
  490. end;
  491. begin
  492. InitTemps;
  493. end.
  494. {
  495. $Log$
  496. Revision 1.5 2000-09-30 16:08:45 peter
  497. * more cg11 updates
  498. Revision 1.4 2000/09/24 15:06:31 peter
  499. * use defines.inc
  500. Revision 1.3 2000/08/27 16:11:55 peter
  501. * moved some util functions from globals,cobjects to cutils
  502. * splitted files into finput,fmodule
  503. Revision 1.2 2000/07/13 11:32:52 michael
  504. + removed logs
  505. }