tgobj.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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 : tparareference);
  88. procedure UnGetLocal(list: taasmoutput; const ref : tparareference);
  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. begin
  130. { Clear the old templist }
  131. while assigned(templist) do
  132. begin
  133. {$ifdef EXTDEBUG}
  134. if not(templist^.temptype in FreeTempTypes) then
  135. begin
  136. Comment(V_Warning,'tgobj: (ResetTempgen) temp at pos '+tostr(templist^.pos)+
  137. ' with size '+tostr(templist^.size)+' and type '+TempTypeStr[templist^.temptype]+
  138. ' from pos '+tostr(templist^.posinfo.line)+':'+tostr(templist^.posinfo.column)+
  139. ' not freed at the end of the procedure');
  140. end;
  141. {$endif}
  142. hp:=templist;
  143. templist:=hp^.next;
  144. dispose(hp);
  145. end;
  146. templist:=nil;
  147. tempfreelist:=nil;
  148. firsttemp:=0;
  149. lasttemp:=0;
  150. end;
  151. procedure ttgobj.setfirsttemp(l : longint);
  152. begin
  153. { this is a negative value normally }
  154. if l*direction>=0 then
  155. begin
  156. if odd(l) then
  157. inc(l,direction);
  158. end
  159. else
  160. internalerror(200204221);
  161. firsttemp:=l;
  162. lasttemp:=l;
  163. end;
  164. function ttgobj.AllocTemp(list: taasmoutput; size,alignment : longint; temptype : ttemptype;def : tdef) : longint;
  165. var
  166. tl,
  167. bestslot,bestprev,
  168. hprev,hp : ptemprecord;
  169. bestsize : longint;
  170. freetype : ttemptype;
  171. begin
  172. AllocTemp:=0;
  173. bestprev:=nil;
  174. bestslot:=nil;
  175. tl:=nil;
  176. bestsize:=0;
  177. if size=0 then
  178. begin
  179. {$ifdef EXTDEBUG}
  180. Comment(V_Warning,'tgobj: (AllocTemp) temp of size 0 requested, allocating 4 bytes');
  181. {$endif}
  182. size:=4;
  183. end;
  184. freetype:=Used2Free[temptype];
  185. if freetype=tt_none then
  186. internalerror(200208201);
  187. size:=align(size,alignment);
  188. { First check the tmpfreelist, but not when
  189. we don't want to reuse an already allocated block }
  190. if assigned(tempfreelist) and
  191. (temptype<>tt_noreuse) then
  192. begin
  193. hprev:=nil;
  194. hp:=tempfreelist;
  195. while assigned(hp) do
  196. begin
  197. {$ifdef EXTDEBUG}
  198. if not(hp^.temptype in FreeTempTypes) then
  199. Comment(V_Warning,'tgobj: (AllocTemp) temp at pos '+tostr(hp^.pos)+ ' in freelist is not set to tt_free !');
  200. {$endif}
  201. { Check only slots that are
  202. - free
  203. - share the same type
  204. - contain enough space
  205. - has a correct alignment }
  206. if (hp^.temptype=freetype) and
  207. (hp^.def=def) and
  208. (hp^.size>=size) and
  209. (hp^.pos=align(hp^.pos,alignment)) then
  210. begin
  211. { Slot is the same size then leave immediatly }
  212. if (hp^.size=size) then
  213. begin
  214. bestprev:=hprev;
  215. bestslot:=hp;
  216. bestsize:=size;
  217. break;
  218. end
  219. else
  220. begin
  221. if (bestsize=0) or (hp^.size<bestsize) then
  222. begin
  223. bestprev:=hprev;
  224. bestslot:=hp;
  225. bestsize:=hp^.size;
  226. end;
  227. end;
  228. end;
  229. hprev:=hp;
  230. hp:=hp^.nextfree;
  231. end;
  232. end;
  233. { Reuse an old temp ? }
  234. if assigned(bestslot) then
  235. begin
  236. if bestsize=size then
  237. begin
  238. tl:=bestslot;
  239. tl^.temptype:=temptype;
  240. tl^.def:=def;
  241. { Remove from the tempfreelist }
  242. if assigned(bestprev) then
  243. bestprev^.nextfree:=tl^.nextfree
  244. else
  245. tempfreelist:=tl^.nextfree;
  246. tl^.nextfree:=nil;
  247. end
  248. else
  249. begin
  250. { Resize the old block }
  251. dec(bestslot^.size,size);
  252. { Create new block and link after bestslot }
  253. new(tl);
  254. tl^.temptype:=temptype;
  255. tl^.def:=def;
  256. if direction=1 then
  257. begin
  258. tl^.pos:=bestslot^.pos;
  259. inc(bestslot^.pos,size);
  260. end
  261. else
  262. tl^.pos:=bestslot^.pos+bestslot^.size;
  263. tl^.size:=size;
  264. tl^.nextfree:=nil;
  265. { link the new block }
  266. tl^.next:=bestslot^.next;
  267. bestslot^.next:=tl;
  268. end;
  269. end
  270. else
  271. begin
  272. { create a new temp, we need to allocate at least a minimum of
  273. 4 bytes, else we get two temps at the same position resulting
  274. in problems when finding the corresponding temprecord }
  275. if size<4 then
  276. size:=4;
  277. { now we can create the templist entry }
  278. new(tl);
  279. tl^.temptype:=temptype;
  280. tl^.def:=def;
  281. { Extend the temp }
  282. if direction=-1 then
  283. begin
  284. lasttemp:=(-align(-lasttemp,alignment))-size;
  285. tl^.pos:=lasttemp;
  286. end
  287. else
  288. begin
  289. tl^.pos:=align(lasttemp,alignment);
  290. lasttemp:=tl^.pos+size;
  291. end;
  292. tl^.size:=size;
  293. tl^.next:=templist;
  294. tl^.nextfree:=nil;
  295. templist:=tl;
  296. end;
  297. {$ifdef EXTDEBUG}
  298. tl^.posinfo:=aktfilepos;
  299. if assigned(tl^.def) then
  300. list.concat(tai_tempalloc.allocinfo(tl^.pos,tl^.size,'allocated with type '+TempTypeStr[tl^.temptype]+' for def '+tl^.def.typename))
  301. else
  302. list.concat(tai_tempalloc.allocinfo(tl^.pos,tl^.size,'allocated with type '+TempTypeStr[tl^.temptype]));
  303. {$else}
  304. list.concat(tai_tempalloc.alloc(tl^.pos,tl^.size));
  305. {$endif}
  306. AllocTemp:=tl^.pos;
  307. end;
  308. procedure ttgobj.FreeTemp(list: taasmoutput; pos:longint;temptypes:ttemptypeset);
  309. var
  310. hp,hnext,hprev,hprevfree : ptemprecord;
  311. begin
  312. hp:=templist;
  313. hprev:=nil;
  314. hprevfree:=nil;
  315. while assigned(hp) do
  316. begin
  317. if (hp^.pos=pos) then
  318. begin
  319. { check if already freed }
  320. if hp^.temptype in FreeTempTypes then
  321. begin
  322. {$ifdef EXTDEBUG}
  323. Comment(V_Warning,'tgobj: (FreeTemp) temp at pos '+tostr(pos)+ ' is already free !');
  324. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'temp is already freed'));
  325. {$endif}
  326. exit;
  327. end;
  328. { check type that are allowed to be released }
  329. if not(hp^.temptype in temptypes) then
  330. begin
  331. {$ifdef EXTDEBUG}
  332. Comment(V_Debug,'tgobj: (Freetemp) temp at pos '+tostr(pos)+ ' has different type ('+TempTypeStr[hp^.temptype]+'), not releasing');
  333. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'temp has wrong type ('+TempTypeStr[hp^.temptype]+') not releasing'));
  334. {$endif}
  335. exit;
  336. end;
  337. list.concat(tai_tempalloc.dealloc(hp^.pos,hp^.size));
  338. { set this block to free }
  339. hp^.temptype:=Used2Free[hp^.temptype];
  340. { Update tempfreelist }
  341. if assigned(hprevfree) then
  342. begin
  343. { Concat blocks when the previous block is free and
  344. there is no block assigned for a tdef }
  345. if assigned(hprev) and
  346. (hp^.temptype=tt_free) and
  347. not assigned(hp^.def) and
  348. (hprev^.temptype=tt_free) and
  349. not assigned(hprev^.def) then
  350. begin
  351. inc(hprev^.size,hp^.size);
  352. if direction=1 then
  353. hprev^.pos:=hp^.pos;
  354. hprev^.next:=hp^.next;
  355. dispose(hp);
  356. hp:=hprev;
  357. end
  358. else
  359. hprevfree^.nextfree:=hp;
  360. end
  361. else
  362. begin
  363. hp^.nextfree:=tempfreelist;
  364. tempfreelist:=hp;
  365. end;
  366. { Concat blocks when the next block is free and
  367. there is no block assigned for a tdef }
  368. hnext:=hp^.next;
  369. if assigned(hnext) and
  370. (hp^.temptype=tt_free) and
  371. not assigned(hp^.def) and
  372. (hnext^.temptype=tt_free) and
  373. not assigned(hnext^.def) then
  374. begin
  375. inc(hp^.size,hnext^.size);
  376. if direction=1 then
  377. hp^.pos:=hnext^.pos;
  378. hp^.nextfree:=hnext^.nextfree;
  379. hp^.next:=hnext^.next;
  380. dispose(hnext);
  381. end;
  382. { Stop }
  383. exit;
  384. end;
  385. if (hp^.temptype=tt_free) then
  386. hprevfree:=hp;
  387. hprev:=hp;
  388. hp:=hp^.next;
  389. end;
  390. end;
  391. procedure ttgobj.gettemp(list: taasmoutput; size : longint;temptype:ttemptype;var ref : treference);
  392. var
  393. varalign : longint;
  394. begin
  395. varalign:=size_2_align(size);
  396. varalign:=used_align(varalign,aktalignment.localalignmin,aktalignment.localalignmax);
  397. { can't use reference_reset_base, because that will let tgobj depend
  398. on cgobj (PFV) }
  399. fillchar(ref,sizeof(ref),0);
  400. ref.base:=current_procinfo.framepointer;
  401. ref.offset:=alloctemp(list,size,varalign,temptype,nil);
  402. end;
  403. procedure ttgobj.gettemptyped(list: taasmoutput; def:tdef;temptype:ttemptype;var ref : treference);
  404. var
  405. varalign : longint;
  406. begin
  407. varalign:=def.alignment;
  408. varalign:=used_align(varalign,aktalignment.localalignmin,aktalignment.localalignmax);
  409. { can't use reference_reset_base, because that will let tgobj depend
  410. on cgobj (PFV) }
  411. fillchar(ref,sizeof(ref),0);
  412. ref.base:=current_procinfo.framepointer;
  413. ref.offset:=alloctemp(list,def.size,varalign,temptype,def);
  414. end;
  415. function ttgobj.istemp(const ref : treference) : boolean;
  416. begin
  417. { ref.index = R_NO was missing
  418. led to problems with local arrays
  419. with lower bound > 0 (PM) }
  420. if direction = 1 then
  421. begin
  422. istemp:=(ref.base=current_procinfo.framepointer) and
  423. (ref.index=NR_NO) and
  424. (ref.offset>=firsttemp);
  425. end
  426. else
  427. begin
  428. istemp:=(ref.base=current_procinfo.framepointer) and
  429. (ref.index=NR_NO) and
  430. (ref.offset<firsttemp);
  431. end;
  432. end;
  433. function ttgobj.sizeoftemp(list: taasmoutput; const ref: treference): longint;
  434. var
  435. hp : ptemprecord;
  436. begin
  437. SizeOfTemp := -1;
  438. hp:=templist;
  439. while assigned(hp) do
  440. begin
  441. if (hp^.pos=ref.offset) then
  442. begin
  443. sizeoftemp := hp^.size;
  444. exit;
  445. end;
  446. hp := hp^.next;
  447. end;
  448. {$ifdef EXTDEBUG}
  449. comment(v_debug,'tgobj: (SizeOfTemp) temp at pos '+tostr(ref.offset)+' not found !');
  450. list.concat(tai_tempalloc.allocinfo(ref.offset,0,'temp not found'));
  451. {$endif}
  452. end;
  453. function ttgobj.ChangeTempType(list: taasmoutput; const ref:treference;temptype:ttemptype):boolean;
  454. var
  455. hp : ptemprecord;
  456. begin
  457. ChangeTempType:=false;
  458. hp:=templist;
  459. while assigned(hp) do
  460. begin
  461. if (hp^.pos=ref.offset) then
  462. begin
  463. if hp^.temptype<>tt_free then
  464. begin
  465. {$ifdef EXTDEBUG}
  466. if hp^.temptype=temptype then
  467. Comment(V_Warning,'tgobj: (ChangeTempType) temp'+
  468. ' at pos '+tostr(ref.offset)+ ' is already of the correct type !');
  469. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'type changed to '+TempTypeStr[temptype]));
  470. {$endif}
  471. ChangeTempType:=true;
  472. hp^.temptype:=temptype;
  473. end
  474. else
  475. begin
  476. {$ifdef EXTDEBUG}
  477. Comment(V_Warning,'tgobj: (ChangeTempType) temp'+
  478. ' at pos '+tostr(ref.offset)+ ' is already freed !');
  479. list.concat(tai_tempalloc.allocinfo(hp^.pos,hp^.size,'temp is already freed'));
  480. {$endif}
  481. end;
  482. exit;
  483. end;
  484. hp:=hp^.next;
  485. end;
  486. {$ifdef EXTDEBUG}
  487. Comment(V_Warning,'tgobj: (ChangeTempType) temp'+
  488. ' at pos '+tostr(ref.offset)+ ' not found !');
  489. list.concat(tai_tempalloc.allocinfo(ref.offset,0,'temp not found'));
  490. {$endif}
  491. end;
  492. procedure ttgobj.UnGetTemp(list: taasmoutput; const ref : treference);
  493. begin
  494. FreeTemp(list,ref.offset,[tt_normal,tt_noreuse,tt_persistent]);
  495. end;
  496. procedure ttgobj.UnGetIfTemp(list: taasmoutput; const ref : treference);
  497. begin
  498. if istemp(ref) then
  499. FreeTemp(list,ref.offset,[tt_normal]);
  500. end;
  501. procedure ttgobj.getlocal(list: taasmoutput; size : longint;def:tdef;var ref : tparareference);
  502. var
  503. varalign : longint;
  504. begin
  505. varalign:=def.alignment;
  506. varalign:=used_align(varalign,aktalignment.localalignmin,aktalignment.localalignmax);
  507. ref.index:=current_procinfo.framepointer;
  508. ref.offset:=alloctemp(list,size,varalign,tt_persistent,nil);
  509. end;
  510. procedure ttgobj.UnGetLocal(list: taasmoutput; const ref : tparareference);
  511. begin
  512. FreeTemp(list,ref.offset,[tt_persistent]);
  513. end;
  514. end.
  515. {
  516. $Log$
  517. Revision 1.45 2004-06-20 08:55:30 florian
  518. * logs truncated
  519. Revision 1.44 2004/06/16 20:07:10 florian
  520. * dwarf branch merged
  521. Revision 1.43.2.1 2004/05/01 16:02:09 peter
  522. * POINTER_SIZE replaced with sizeof(aint)
  523. * aint,aword,tconst*int moved to globtype
  524. Revision 1.43 2004/01/12 22:11:38 peter
  525. * use localalign info for alignment for locals and temps
  526. * sparc fpu flags branching added
  527. * moved powerpc copy_valye_openarray to generic
  528. }