tgobj.pas 23 KB

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