tgobj.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the base object for temp. generator
  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. {#@abstract(Temporary reference allocator unit)
  19. Temporary reference allocator unit. This unit contains
  20. all which is related to allocating temporary memory
  21. space on the stack, as required, by the code generator.
  22. }
  23. unit tgobj;
  24. {$i fpcdefs.inc}
  25. interface
  26. uses
  27. cclasses,
  28. globals,globtype,
  29. symtype,
  30. cpubase,cpuinfo,cgbase,
  31. aasmbase,aasmtai;
  32. type
  33. ttemptypeset = set of ttemptype;
  34. ptemprecord = ^ttemprecord;
  35. ttemprecord = record
  36. temptype : ttemptype;
  37. pos : longint;
  38. size : longint;
  39. def : tdef;
  40. next : ptemprecord;
  41. nextfree : ptemprecord; { for faster freeblock checking }
  42. {$ifdef EXTDEBUG}
  43. posinfo,
  44. releaseposinfo : tfileposinfo;
  45. {$endif}
  46. end;
  47. {# Generates temporary variables }
  48. ttgobj = class
  49. private
  50. { contains all free temps using nextfree links }
  51. tempfreelist : ptemprecord;
  52. function alloctemp(list: taasmoutput; size,alignment : longint; temptype : ttemptype; def:tdef) : longint;
  53. procedure freetemp(list: taasmoutput; pos:longint;temptypes:ttemptypeset);
  54. public
  55. { contains all temps }
  56. templist : ptemprecord;
  57. { Offsets of the first/last temp }
  58. firsttemp,
  59. lasttemp : longint;
  60. direction : shortint;
  61. constructor create;
  62. {# Clear and free the complete linked list of temporary memory
  63. locations. The list is set to nil.}
  64. procedure resettempgen;
  65. {# Sets the first offset from the frame pointer or stack pointer where
  66. the temporary references will be allocated. It is to note that this
  67. value should always be negative.
  68. @param(l start offset where temps will start in stack)
  69. }
  70. procedure setfirsttemp(l : longint);
  71. procedure gettemp(list: taasmoutput; size : longint;temptype:ttemptype;var ref : treference);
  72. procedure gettemptyped(list: taasmoutput; def:tdef;temptype:ttemptype;var ref : treference);
  73. procedure ungettemp(list: taasmoutput; const ref : treference);
  74. function sizeoftemp(list: taasmoutput; const ref: treference): longint;
  75. function changetemptype(list: taasmoutput; const ref:treference;temptype:ttemptype):boolean;
  76. {# Returns TRUE if the reference ref is allocated in temporary volatile memory space,
  77. otherwise returns FALSE.
  78. @param(ref reference to verify)
  79. }
  80. function istemp(const ref : treference) : boolean;
  81. {# Frees a reference @var(ref) which was allocated in the volatile temporary memory space.
  82. The freed space can later be reallocated and reused. If this reference
  83. is not in the temporary memory, it is simply not freed.
  84. }
  85. procedure ungetiftemp(list: taasmoutput; const ref : treference);
  86. { Allocate space for a local }
  87. procedure getlocal(list: taasmoutput; size : longint;def:tdef;var ref : treference);
  88. procedure UnGetLocal(list: taasmoutput; const ref : treference);
  89. end;
  90. var
  91. tg: ttgobj;
  92. implementation
  93. uses
  94. cutils,
  95. systems,verbose,
  96. procinfo
  97. ;
  98. const
  99. FreeTempTypes = [tt_free,tt_freenoreuse];
  100. {$ifdef EXTDEBUG}
  101. TempTypeStr : array[ttemptype] of string[18] = (
  102. '<none>',
  103. 'free','normal','persistant',
  104. 'noreuse','freenoreuse'
  105. );
  106. {$endif EXTDEBUG}
  107. Used2Free : array[ttemptype] of ttemptype = (
  108. tt_none,
  109. tt_none,tt_free,tt_free,
  110. tt_freenoreuse,tt_none
  111. );
  112. {*****************************************************************************
  113. TTGOBJ
  114. *****************************************************************************}
  115. constructor ttgobj.create;
  116. begin
  117. tempfreelist:=nil;
  118. templist:=nil;
  119. { we could create a new child class for this but I don't if it is worth the effort (FK) }
  120. {$ifdef powerpc}
  121. direction:=1;
  122. {$else powerpc}
  123. direction:=-1;
  124. {$endif powerpc}
  125. end;
  126. procedure ttgobj.resettempgen;
  127. var
  128. hp : ptemprecord;
  129. {$ifdef EXTDEBUG}
  130. currpos,
  131. lastpos : longint;
  132. {$endif EXTDEBUG}
  133. begin
  134. {$ifdef EXTDEBUG}
  135. lastpos:=lasttemp;
  136. {$endif EXTDEBUG}
  137. { Clear the old templist }
  138. while assigned(templist) do
  139. begin
  140. {$ifdef EXTDEBUG}
  141. if not(templist^.temptype in FreeTempTypes) then
  142. begin
  143. Comment(V_Warning,'tgobj: (ResetTempgen) temp at pos '+tostr(templist^.pos)+
  144. ' with size '+tostr(templist^.size)+' and type '+TempTypeStr[templist^.temptype]+
  145. ' from pos '+tostr(templist^.posinfo.line)+':'+tostr(templist^.posinfo.column)+
  146. ' not freed at the end of the procedure');
  147. end;
  148. if direction=1 then
  149. currpos:=templist^.pos+templist^.size
  150. else
  151. currpos:=templist^.pos;
  152. if currpos<>lastpos then
  153. begin
  154. Comment(V_Warning,'tgobj: (ResetTempgen) temp at pos '+tostr(templist^.pos)+
  155. ' with size '+tostr(templist^.size)+' and type '+TempTypeStr[templist^.temptype]+
  156. ' from pos '+tostr(templist^.posinfo.line)+':'+tostr(templist^.posinfo.column)+
  157. ' was expected at position '+tostr(lastpos));
  158. end;
  159. if direction=1 then
  160. lastpos:=templist^.pos
  161. else
  162. lastpos:=templist^.pos+templist^.size;
  163. {$endif EXTDEBUG}
  164. hp:=templist;
  165. templist:=hp^.next;
  166. dispose(hp);
  167. end;
  168. templist:=nil;
  169. tempfreelist:=nil;
  170. firsttemp:=0;
  171. lasttemp:=0;
  172. end;
  173. procedure ttgobj.setfirsttemp(l : longint);
  174. begin
  175. { this is a negative value normally }
  176. if l*direction>=0 then
  177. begin
  178. if odd(l) then
  179. inc(l,direction);
  180. end
  181. else
  182. internalerror(200204221);
  183. firsttemp:=l;
  184. lasttemp:=l;
  185. end;
  186. function ttgobj.AllocTemp(list: taasmoutput; size,alignment : longint; temptype : ttemptype;def : tdef) : longint;
  187. var
  188. tl,htl,
  189. bestslot,bestprev,
  190. hprev,hp : ptemprecord;
  191. bestsize : longint;
  192. freetype : ttemptype;
  193. begin
  194. AllocTemp:=0;
  195. bestprev:=nil;
  196. bestslot:=nil;
  197. tl:=nil;
  198. bestsize:=0;
  199. if size=0 then
  200. begin
  201. {$ifdef EXTDEBUG}
  202. Comment(V_Warning,'tgobj: (AllocTemp) temp of size 0 requested, allocating 4 bytes');
  203. {$endif}
  204. size:=4;
  205. end;
  206. freetype:=Used2Free[temptype];
  207. if freetype=tt_none then
  208. internalerror(200208201);
  209. size:=align(size,alignment);
  210. { First check the tmpfreelist, but not when
  211. we don't want to reuse an already allocated block }
  212. if assigned(tempfreelist) and
  213. (temptype<>tt_noreuse) then
  214. begin
  215. hprev:=nil;
  216. hp:=tempfreelist;
  217. while assigned(hp) do
  218. begin
  219. {$ifdef EXTDEBUG}
  220. if not(hp^.temptype in FreeTempTypes) then
  221. Comment(V_Warning,'tgobj: (AllocTemp) temp at pos '+tostr(hp^.pos)+ ' in freelist is not set to tt_free !');
  222. {$endif}
  223. { Check only slots that are
  224. - free
  225. - share the same type
  226. - contain enough space
  227. - has a correct alignment }
  228. if (hp^.temptype=freetype) and
  229. (hp^.def=def) and
  230. (hp^.size>=size) and
  231. (hp^.pos=align(hp^.pos,alignment)) then
  232. begin
  233. { Slot is the same size then leave immediatly }
  234. if (hp^.size=size) then
  235. begin
  236. bestprev:=hprev;
  237. bestslot:=hp;
  238. bestsize:=size;
  239. break;
  240. end
  241. else
  242. begin
  243. if (bestsize=0) or (hp^.size<bestsize) then
  244. begin
  245. bestprev:=hprev;
  246. bestslot:=hp;
  247. bestsize:=hp^.size;
  248. end;
  249. end;
  250. end;
  251. hprev:=hp;
  252. hp:=hp^.nextfree;
  253. end;
  254. end;
  255. { Reuse an old temp ? }
  256. if assigned(bestslot) then
  257. begin
  258. if bestsize=size then
  259. begin
  260. tl:=bestslot;
  261. { Remove from the tempfreelist }
  262. if assigned(bestprev) then
  263. bestprev^.nextfree:=tl^.nextfree
  264. else
  265. tempfreelist:=tl^.nextfree;
  266. end
  267. else
  268. begin
  269. { Duplicate bestlost and the block in the list }
  270. new(tl);
  271. move(bestslot^,tl^,sizeof(ttemprecord));
  272. tl^.next:=bestslot^.next;
  273. bestslot^.next:=tl;
  274. { Now we split the block in 2 parts. Depending on the direction
  275. we need to resize the newly inserted block or the old reused block.
  276. For direction=1 we can use tl for the new block. For direction=-1 we
  277. will be reusing bestslot and resize the new block, that means we need
  278. to swap the pointers }
  279. if direction=-1 then
  280. begin
  281. htl:=tl;
  282. tl:=bestslot;
  283. bestslot:=htl;
  284. { Update the tempfreelist to point to the new block }
  285. if assigned(bestprev) then
  286. bestprev^.nextfree:=bestslot
  287. else
  288. tempfreelist:=bestslot;
  289. end;
  290. { Create new block and resize the old block }
  291. tl^.size:=size;
  292. tl^.nextfree:=nil;
  293. { Resize the old block }
  294. dec(bestslot^.size,size);
  295. inc(bestslot^.pos,size);
  296. end;
  297. tl^.temptype:=temptype;
  298. tl^.def:=def;
  299. tl^.nextfree:=nil;
  300. end
  301. else
  302. begin
  303. { create a new temp, we need to allocate at least a minimum of
  304. 4 bytes, else we get two temps at the same position resulting
  305. in problems when finding the corresponding temprecord }
  306. if size<4 then
  307. size:=4;
  308. { now we can create the templist entry }
  309. new(tl);
  310. tl^.temptype:=temptype;
  311. tl^.def:=def;
  312. { Extend the temp }
  313. if direction=-1 then
  314. begin
  315. lasttemp:=(-align(-lasttemp,alignment))-size;
  316. tl^.pos:=lasttemp;
  317. end
  318. else
  319. begin
  320. tl^.pos:=align(lasttemp,alignment);
  321. lasttemp:=tl^.pos+size;
  322. end;
  323. tl^.size:=size;
  324. tl^.next:=templist;
  325. tl^.nextfree:=nil;
  326. templist:=tl;
  327. end;
  328. {$ifdef EXTDEBUG}
  329. tl^.posinfo:=aktfilepos;
  330. if assigned(tl^.def) then
  331. list.concat(tai_tempalloc.allocinfo(tl^.pos,tl^.size,'allocated with type '+TempTypeStr[tl^.temptype]+' for def '+tl^.def.typename))
  332. else
  333. list.concat(tai_tempalloc.allocinfo(tl^.pos,tl^.size,'allocated with type '+TempTypeStr[tl^.temptype]));
  334. {$else}
  335. list.concat(tai_tempalloc.alloc(tl^.pos,tl^.size));
  336. {$endif}
  337. AllocTemp:=tl^.pos;
  338. end;
  339. procedure ttgobj.FreeTemp(list: taasmoutput; pos:longint;temptypes:ttemptypeset);
  340. var
  341. hp,hnext,hprev,hprevfree : ptemprecord;
  342. begin
  343. hp:=templist;
  344. hprev:=nil;
  345. hprevfree:=nil;
  346. while assigned(hp) do
  347. begin
  348. if (hp^.pos=pos) then
  349. begin
  350. { check if already freed }
  351. if hp^.temptype in FreeTempTypes then
  352. begin
  353. {$ifdef EXTDEBUG}
  354. Comment(V_Warning,'tgobj: (FreeTemp) temp at pos '+tostr(pos)+ ' is already free !');
  355. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'temp is already freed'));
  356. {$endif}
  357. exit;
  358. end;
  359. { check type that are allowed to be released }
  360. if not(hp^.temptype in temptypes) then
  361. begin
  362. {$ifdef EXTDEBUG}
  363. Comment(V_Debug,'tgobj: (Freetemp) temp at pos '+tostr(pos)+ ' has different type ('+TempTypeStr[hp^.temptype]+'), not releasing');
  364. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'temp has wrong type ('+TempTypeStr[hp^.temptype]+') not releasing'));
  365. {$endif}
  366. exit;
  367. end;
  368. list.concat(tai_tempalloc.dealloc(hp^.pos,hp^.size));
  369. { set this block to free }
  370. hp^.temptype:=Used2Free[hp^.temptype];
  371. { Update tempfreelist }
  372. if assigned(hprevfree) then
  373. begin
  374. { Concat blocks when the previous block is free and
  375. there is no block assigned for a tdef }
  376. if assigned(hprev) and
  377. (hp^.temptype=tt_free) and
  378. not assigned(hp^.def) and
  379. (hprev^.temptype=tt_free) and
  380. not assigned(hprev^.def) then
  381. begin
  382. inc(hprev^.size,hp^.size);
  383. if direction=1 then
  384. hprev^.pos:=hp^.pos;
  385. hprev^.next:=hp^.next;
  386. dispose(hp);
  387. hp:=hprev;
  388. end
  389. else
  390. hprevfree^.nextfree:=hp;
  391. end
  392. else
  393. begin
  394. hp^.nextfree:=tempfreelist;
  395. tempfreelist:=hp;
  396. end;
  397. { Concat blocks when the next block is free and
  398. there is no block assigned for a tdef }
  399. hnext:=hp^.next;
  400. if assigned(hnext) and
  401. (hp^.temptype=tt_free) and
  402. not assigned(hp^.def) and
  403. (hnext^.temptype=tt_free) and
  404. not assigned(hnext^.def) then
  405. begin
  406. inc(hp^.size,hnext^.size);
  407. if direction=1 then
  408. hp^.pos:=hnext^.pos;
  409. hp^.nextfree:=hnext^.nextfree;
  410. hp^.next:=hnext^.next;
  411. dispose(hnext);
  412. end;
  413. { Stop }
  414. exit;
  415. end;
  416. if (hp^.temptype=tt_free) then
  417. hprevfree:=hp;
  418. hprev:=hp;
  419. hp:=hp^.next;
  420. end;
  421. end;
  422. procedure ttgobj.gettemp(list: taasmoutput; size : longint;temptype:ttemptype;var ref : treference);
  423. var
  424. varalign : longint;
  425. begin
  426. varalign:=size_2_align(size);
  427. varalign:=used_align(varalign,aktalignment.localalignmin,aktalignment.localalignmax);
  428. { can't use reference_reset_base, because that will let tgobj depend
  429. on cgobj (PFV) }
  430. fillchar(ref,sizeof(ref),0);
  431. ref.base:=current_procinfo.framepointer;
  432. ref.offset:=alloctemp(list,size,varalign,temptype,nil);
  433. end;
  434. procedure ttgobj.gettemptyped(list: taasmoutput; def:tdef;temptype:ttemptype;var ref : treference);
  435. var
  436. varalign : longint;
  437. begin
  438. varalign:=def.alignment;
  439. varalign:=used_align(varalign,aktalignment.localalignmin,aktalignment.localalignmax);
  440. { can't use reference_reset_base, because that will let tgobj depend
  441. on cgobj (PFV) }
  442. fillchar(ref,sizeof(ref),0);
  443. ref.base:=current_procinfo.framepointer;
  444. ref.offset:=alloctemp(list,def.size,varalign,temptype,def);
  445. end;
  446. function ttgobj.istemp(const ref : treference) : boolean;
  447. begin
  448. { ref.index = R_NO was missing
  449. led to problems with local arrays
  450. with lower bound > 0 (PM) }
  451. if direction = 1 then
  452. begin
  453. istemp:=(ref.base=current_procinfo.framepointer) and
  454. (ref.index=NR_NO) and
  455. (ref.offset>=firsttemp);
  456. end
  457. else
  458. begin
  459. istemp:=(ref.base=current_procinfo.framepointer) and
  460. (ref.index=NR_NO) and
  461. (ref.offset<firsttemp);
  462. end;
  463. end;
  464. function ttgobj.sizeoftemp(list: taasmoutput; const ref: treference): longint;
  465. var
  466. hp : ptemprecord;
  467. begin
  468. SizeOfTemp := -1;
  469. hp:=templist;
  470. while assigned(hp) do
  471. begin
  472. if (hp^.pos=ref.offset) then
  473. begin
  474. sizeoftemp := hp^.size;
  475. exit;
  476. end;
  477. hp := hp^.next;
  478. end;
  479. {$ifdef EXTDEBUG}
  480. comment(v_debug,'tgobj: (SizeOfTemp) temp at pos '+tostr(ref.offset)+' not found !');
  481. list.concat(tai_tempalloc.allocinfo(ref.offset,0,'temp not found'));
  482. {$endif}
  483. end;
  484. function ttgobj.ChangeTempType(list: taasmoutput; const ref:treference;temptype:ttemptype):boolean;
  485. var
  486. hp : ptemprecord;
  487. begin
  488. ChangeTempType:=false;
  489. hp:=templist;
  490. while assigned(hp) do
  491. begin
  492. if (hp^.pos=ref.offset) then
  493. begin
  494. if hp^.temptype<>tt_free then
  495. begin
  496. {$ifdef EXTDEBUG}
  497. if hp^.temptype=temptype then
  498. Comment(V_Warning,'tgobj: (ChangeTempType) temp'+
  499. ' at pos '+tostr(ref.offset)+ ' is already of the correct type !');
  500. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'type changed to '+TempTypeStr[temptype]));
  501. {$endif}
  502. ChangeTempType:=true;
  503. hp^.temptype:=temptype;
  504. end
  505. else
  506. begin
  507. {$ifdef EXTDEBUG}
  508. Comment(V_Warning,'tgobj: (ChangeTempType) temp'+
  509. ' at pos '+tostr(ref.offset)+ ' is already freed !');
  510. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'temp is already freed'));
  511. {$endif}
  512. end;
  513. exit;
  514. end;
  515. hp:=hp^.next;
  516. end;
  517. {$ifdef EXTDEBUG}
  518. Comment(V_Warning,'tgobj: (ChangeTempType) temp'+
  519. ' at pos '+tostr(ref.offset)+ ' not found !');
  520. list.concat(tai_tempalloc.allocinfo(ref.offset,0,'temp not found'));
  521. {$endif}
  522. end;
  523. procedure ttgobj.UnGetTemp(list: taasmoutput; const ref : treference);
  524. begin
  525. FreeTemp(list,ref.offset,[tt_normal,tt_noreuse,tt_persistent]);
  526. end;
  527. procedure ttgobj.UnGetIfTemp(list: taasmoutput; const ref : treference);
  528. begin
  529. if istemp(ref) then
  530. FreeTemp(list,ref.offset,[tt_normal]);
  531. end;
  532. procedure ttgobj.getlocal(list: taasmoutput; size : longint;def:tdef;var ref : treference);
  533. var
  534. varalign : longint;
  535. begin
  536. varalign:=def.alignment;
  537. varalign:=used_align(varalign,aktalignment.localalignmin,aktalignment.localalignmax);
  538. { can't use reference_reset_base, because that will let tgobj depend
  539. on cgobj (PFV) }
  540. fillchar(ref,sizeof(ref),0);
  541. ref.base:=current_procinfo.framepointer;
  542. ref.offset:=alloctemp(list,size,varalign,tt_persistent,nil);
  543. end;
  544. procedure ttgobj.UnGetLocal(list: taasmoutput; const ref : treference);
  545. begin
  546. FreeTemp(list,ref.offset,[tt_persistent]);
  547. end;
  548. end.
  549. {
  550. $Log$
  551. Revision 1.48 2004-09-21 17:25:12 peter
  552. * paraloc branch merged
  553. Revision 1.47 2004/09/20 15:40:21 peter
  554. * make it compile with main branch
  555. Revision 1.46 2004/09/20 07:32:02 jonas
  556. * fixed crashes on direction=1 systems (mainly by Peter)
  557. Revision 1.45.4.2 2004/09/07 20:52:10 peter
  558. * fix resizing of bestslot to preserve alignment for the returned
  559. block
  560. Revision 1.45.4.1 2004/08/31 20:43:06 peter
  561. * paraloc patch
  562. Revision 1.45 2004/06/20 08:55:30 florian
  563. * logs truncated
  564. Revision 1.44 2004/06/16 20:07:10 florian
  565. * dwarf branch merged
  566. Revision 1.43.2.1 2004/05/01 16:02:09 peter
  567. * POINTER_SIZE replaced with sizeof(aint)
  568. * aint,aword,tconst*int moved to globtype
  569. Revision 1.43 2004/01/12 22:11:38 peter
  570. * use localalign info for alignment for locals and temps
  571. * sparc fpu flags branching added
  572. * moved powerpc copy_valye_openarray to generic
  573. }