tgobj.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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. globals,
  28. cpubase,
  29. cpuinfo,
  30. cclasses,globtype,cgbase,aasmbase,aasmtai,aasmcpu;
  31. type
  32. ttemptype = (tt_none,
  33. tt_free,tt_normal,tt_persistant,
  34. tt_noreuse,tt_freenoreuse,
  35. tt_ansistring,tt_freeansistring,
  36. tt_widestring,tt_freewidestring,
  37. tt_interfacecom,tt_freeinterfacecom);
  38. ttemptypeset = set of ttemptype;
  39. ptemprecord = ^ttemprecord;
  40. ttemprecord = record
  41. temptype : ttemptype;
  42. pos : longint;
  43. size : longint;
  44. next : ptemprecord;
  45. nextfree : ptemprecord; { for faster freeblock checking }
  46. {$ifdef EXTDEBUG}
  47. posinfo,
  48. releaseposinfo : tfileposinfo;
  49. {$endif}
  50. end;
  51. {# Generates temporary variables }
  52. ttgobj = class
  53. private
  54. { contains all free temps using nextfree links }
  55. tempfreelist : ptemprecord;
  56. function AllocTemp(list: taasmoutput; size : longint; temptype : ttemptype) : longint;
  57. procedure FreeTemp(list: taasmoutput; pos:longint;temptypes:ttemptypeset);
  58. public
  59. { contains all temps }
  60. templist : ptemprecord;
  61. { Offsets of the first/last temp }
  62. firsttemp,
  63. lasttemp : longint;
  64. constructor create;
  65. {# Clear and free the complete linked list of temporary memory
  66. locations. The list is set to nil.}
  67. procedure resettempgen;
  68. {# Sets the first offset from the frame pointer or stack pointer where
  69. the temporary references will be allocated. It is to note that this
  70. value should always be negative.
  71. @param(l start offset where temps will start in stack)
  72. }
  73. procedure setfirsttemp(l : longint);
  74. function gettempsize : longint;
  75. procedure GetTemp(list: taasmoutput; size : longint;temptype:ttemptype;var ref : treference);
  76. procedure UnGetTemp(list: taasmoutput; const ref : treference);
  77. function SizeOfTemp(const ref: treference): longint;
  78. procedure ChangeTempType(const ref:treference;temptype:ttemptype);
  79. {# Returns TRUE if the reference ref is allocated in temporary volatile memory space,
  80. otherwise returns FALSE.
  81. @param(ref reference to verify)
  82. }
  83. function istemp(const ref : treference) : boolean;
  84. {# Frees a reference @var(ref) which was allocated in the volatile temporary memory space.
  85. The freed space can later be reallocated and reused. If this reference
  86. is not in the temporary memory, it is simply not freed.
  87. }
  88. procedure ungetiftemp(list: taasmoutput; const ref : treference);
  89. end;
  90. var
  91. tg: ttgobj;
  92. implementation
  93. uses
  94. systems,
  95. verbose,cutils;
  96. const
  97. FreeTempTypes = [tt_free,tt_freenoreuse,tt_freeansistring,
  98. tt_freewidestring,tt_freeinterfacecom];
  99. {$ifdef EXTDEBUG}
  100. TempTypeStr : array[ttemptype] of string[18] = (
  101. '<none>',
  102. 'free','normal','persistant',
  103. 'noreuse','freenoreuse',
  104. 'ansistring','freeansistring',
  105. 'widestring','freewidestring',
  106. 'interfacecom','freeinterfacecom'
  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. tt_freeansistring,tt_none,
  114. tt_freewidestring,tt_none,
  115. tt_freeinterfacecom,tt_none);
  116. {*****************************************************************************
  117. TTGOBJ
  118. *****************************************************************************}
  119. constructor ttgobj.create;
  120. begin
  121. tempfreelist:=nil;
  122. templist:=nil;
  123. end;
  124. procedure ttgobj.resettempgen;
  125. var
  126. hp : ptemprecord;
  127. begin
  128. { Clear the old templist }
  129. while assigned(templist) do
  130. begin
  131. {$ifdef EXTDEBUG}
  132. if not(templist^.temptype in FreeTempTypes) then
  133. begin
  134. Comment(V_Warning,'temp at pos '+tostr(templist^.pos)+
  135. ' with size '+tostr(templist^.size)+' and type '+TempTypeStr[templist^.temptype]+
  136. ' from pos '+tostr(templist^.posinfo.line)+':'+tostr(templist^.posinfo.column)+
  137. ' not freed at the end of the procedure');
  138. end;
  139. {$endif}
  140. hp:=templist;
  141. templist:=hp^.next;
  142. dispose(hp);
  143. end;
  144. templist:=nil;
  145. tempfreelist:=nil;
  146. firsttemp:=0;
  147. lasttemp:=0;
  148. end;
  149. procedure ttgobj.setfirsttemp(l : longint);
  150. begin
  151. { this is a negative value normally }
  152. if l <= 0 then
  153. begin
  154. if odd(l) then
  155. dec(l);
  156. end
  157. else
  158. internalerror(200204221);
  159. firsttemp:=l;
  160. lasttemp:=l;
  161. end;
  162. function ttgobj.gettempsize : longint;
  163. var
  164. _align : longint;
  165. begin
  166. { align to 4 bytes at least
  167. otherwise all those subl $2,%esp are meaningless PM }
  168. _align:=target_info.alignment.localalignmin;
  169. if _align<4 then
  170. _align:=4;
  171. {$ifdef testtemp}
  172. if firsttemp <> lasttemp then
  173. gettempsize:=Align(-(lasttemp-firsttemp),_align)
  174. else
  175. gettempsize := 0;
  176. {$else}
  177. gettempsize:=Align(-lasttemp,_align);
  178. {$endif}
  179. end;
  180. function ttgobj.AllocTemp(list: taasmoutput; size : longint; temptype : ttemptype) : longint;
  181. var
  182. tl,
  183. bestslot,bestprev,
  184. hprev,hp : ptemprecord;
  185. bestsize : longint;
  186. freetype : ttemptype;
  187. begin
  188. AllocTemp:=0;
  189. bestprev:=nil;
  190. bestslot:=nil;
  191. tl:=nil;
  192. bestsize:=0;
  193. {$ifdef EXTDEBUG}
  194. if size=0 then
  195. begin
  196. Comment(V_Warning,'Temp of size 0 requested');
  197. size:=4;
  198. end;
  199. {$endif}
  200. freetype:=Used2Free[temptype];
  201. if freetype=tt_none then
  202. internalerror(200208201);
  203. { Align needed size on 4 bytes }
  204. size:=Align(size,4);
  205. { First check the tmpfreelist, but not when
  206. we don't want to reuse an already allocated block }
  207. if assigned(tempfreelist) and
  208. (temptype<>tt_noreuse) then
  209. begin
  210. { Check for a slot with the same size first }
  211. hprev:=nil;
  212. hp:=tempfreelist;
  213. while assigned(hp) do
  214. begin
  215. {$ifdef EXTDEBUG}
  216. if not(hp^.temptype in FreeTempTypes) then
  217. Comment(V_Warning,'Temp in freelist is not set to tt_free');
  218. {$endif}
  219. if (hp^.temptype=freetype) and
  220. (hp^.size>=size) then
  221. begin
  222. { Slot is the same size, then leave immediatly }
  223. if hp^.size=size then
  224. begin
  225. bestprev:=hprev;
  226. bestslot:=hp;
  227. bestsize:=size;
  228. break;
  229. end
  230. else
  231. begin
  232. if (bestsize=0) or (hp^.size<bestsize) then
  233. begin
  234. bestprev:=hprev;
  235. bestslot:=hp;
  236. bestsize:=hp^.size;
  237. end;
  238. end;
  239. end;
  240. hprev:=hp;
  241. hp:=hp^.nextfree;
  242. end;
  243. end;
  244. { Reuse an old temp ? }
  245. if assigned(bestslot) then
  246. begin
  247. if bestsize=size then
  248. begin
  249. tl:=bestslot;
  250. tl^.temptype:=temptype;
  251. { Remove from the tempfreelist }
  252. if assigned(bestprev) then
  253. bestprev^.nextfree:=tl^.nextfree
  254. else
  255. tempfreelist:=tl^.nextfree;
  256. tl^.nextfree:=nil;
  257. end
  258. else
  259. begin
  260. { Resize the old block }
  261. dec(bestslot^.size,size);
  262. { Create new block and link after bestslot }
  263. new(tl);
  264. tl^.temptype:=temptype;
  265. tl^.pos:=bestslot^.pos+bestslot^.size;
  266. tl^.size:=size;
  267. tl^.nextfree:=nil;
  268. { link the new block }
  269. tl^.next:=bestslot^.next;
  270. bestslot^.next:=tl;
  271. end;
  272. end
  273. else
  274. begin
  275. { create a new temp, we need to allocate at least a minimum of
  276. 4 bytes, else we get two temps at the same position resulting
  277. in problems when finding the corresponding temprecord }
  278. if size<4 then
  279. size:=4;
  280. { Extend the temp }
  281. dec(lasttemp,size);
  282. { now we can create the templist entry }
  283. new(tl);
  284. tl^.temptype:=temptype;
  285. tl^.pos:=lasttemp;
  286. tl^.size:=size;
  287. tl^.next:=templist;
  288. tl^.nextfree:=nil;
  289. templist:=tl;
  290. end;
  291. {$ifdef EXTDEBUG}
  292. tl^.posinfo:=aktfilepos;
  293. {$endif}
  294. list.concat(tai_tempalloc.alloc(tl^.pos,tl^.size));
  295. AllocTemp:=tl^.pos;
  296. end;
  297. procedure ttgobj.FreeTemp(list: taasmoutput; pos:longint;temptypes:ttemptypeset);
  298. var
  299. hp,hnext,hprev,hprevfree : ptemprecord;
  300. begin
  301. hp:=templist;
  302. hprev:=nil;
  303. hprevfree:=nil;
  304. while assigned(hp) do
  305. begin
  306. if (hp^.pos=pos) then
  307. begin
  308. { check if already freed }
  309. if hp^.temptype in FreeTempTypes then
  310. begin
  311. {$ifdef EXTDEBUG}
  312. Comment(V_Warning,'temp managment : (FreeTemp) temp at pos '+tostr(pos)+ ' is already free !');
  313. {$endif}
  314. exit;
  315. end;
  316. { check type that are allowed to be released }
  317. if not(hp^.temptype in temptypes) then
  318. begin
  319. {$ifdef EXTDEBUG}
  320. Comment(V_Debug,'temp managment : (Freetemp) temp at pos '+tostr(pos)+ ' has different type, not releasing');
  321. {$endif}
  322. exit;
  323. end;
  324. list.concat(tai_tempalloc.dealloc(hp^.pos,hp^.size));
  325. { set this block to free }
  326. hp^.temptype:=Used2Free[hp^.temptype];
  327. { Update tempfreelist }
  328. if assigned(hprevfree) then
  329. begin
  330. { Connect With previous tt_free block? }
  331. if assigned(hprev) and
  332. (hp^.temptype=tt_free) and
  333. (hprev^.temptype=tt_free) then
  334. begin
  335. inc(hprev^.size,hp^.size);
  336. hprev^.next:=hp^.next;
  337. dispose(hp);
  338. hp:=hprev;
  339. end
  340. else
  341. hprevfree^.nextfree:=hp;
  342. end
  343. else
  344. begin
  345. hp^.nextfree:=tempfreelist;
  346. tempfreelist:=hp;
  347. end;
  348. { Next block tt_free ? Yes, then concat }
  349. hnext:=hp^.next;
  350. if assigned(hnext) and
  351. (hp^.temptype=tt_free) and
  352. (hnext^.temptype=tt_free) then
  353. begin
  354. inc(hp^.size,hnext^.size);
  355. hp^.nextfree:=hnext^.nextfree;
  356. hp^.next:=hnext^.next;
  357. dispose(hnext);
  358. end;
  359. { Stop }
  360. exit;
  361. end;
  362. if (hp^.temptype=tt_free) then
  363. hprevfree:=hp;
  364. hprev:=hp;
  365. hp:=hp^.next;
  366. end;
  367. end;
  368. procedure ttgobj.GetTemp(list: taasmoutput; size : longint;temptype:ttemptype;var ref : treference);
  369. begin
  370. FillChar(ref,sizeof(treference),0);
  371. ref.base:=procinfo.framepointer;
  372. ref.offset:=AllocTemp(list,size,temptype);
  373. end;
  374. function ttgobj.istemp(const ref : treference) : boolean;
  375. begin
  376. { ref.index = R_NO was missing
  377. led to problems with local arrays
  378. with lower bound > 0 (PM) }
  379. istemp:=((ref.base=procinfo.framepointer) and
  380. (ref.index=R_NO) and
  381. (ref.offset<firsttemp));
  382. end;
  383. function ttgobj.SizeOfTemp(const ref: treference): longint;
  384. var
  385. hp : ptemprecord;
  386. begin
  387. SizeOfTemp := -1;
  388. hp:=templist;
  389. while assigned(hp) do
  390. begin
  391. if (hp^.pos=ref.offset) then
  392. begin
  393. SizeOfTemp := hp^.size;
  394. exit;
  395. end;
  396. hp := hp^.next;
  397. end;
  398. {$ifdef EXTDEBUG}
  399. Comment(V_Debug,'temp managment : SizeOfTemp temp at pos '+tostr(ref.offset)+ ' not found !');
  400. {$endif}
  401. end;
  402. procedure ttgobj.ChangeTempType(const ref:treference;temptype:ttemptype);
  403. var
  404. hp : ptemprecord;
  405. begin
  406. hp:=templist;
  407. while assigned(hp) do
  408. begin
  409. if (hp^.pos=ref.offset) then
  410. begin
  411. if not(hp^.temptype in [tt_free,tt_freeansistring,tt_freewidestring,tt_freeinterfacecom]) then
  412. begin
  413. {$ifdef EXTDEBUG}
  414. if hp^.temptype=temptype then
  415. Comment(V_Warning,'temp managment : ChangeTempType temp'+
  416. ' at pos '+tostr(ref.offset)+ ' is already of the correct type !');
  417. {$endif}
  418. hp^.temptype:=temptype;
  419. end
  420. else
  421. begin
  422. {$ifdef EXTDEBUG}
  423. Comment(V_Warning,'temp managment : ChangeTempType temp'+
  424. ' at pos '+tostr(ref.offset)+ ' is already freed !');
  425. {$endif}
  426. end;
  427. exit;
  428. end;
  429. hp:=hp^.next;
  430. end;
  431. {$ifdef EXTDEBUG}
  432. Comment(V_Warning,'temp managment : ChangeTempType temp'+
  433. ' at pos '+tostr(ref.offset)+ ' not found !');
  434. {$endif}
  435. end;
  436. procedure ttgobj.UnGetTemp(list: taasmoutput; const ref : treference);
  437. begin
  438. FreeTemp(list,ref.offset,[tt_normal,tt_noreuse,tt_persistant,tt_ansistring,tt_widestring,tt_interfacecom]);
  439. end;
  440. procedure ttgobj.UnGetIfTemp(list: taasmoutput; const ref : treference);
  441. begin
  442. if istemp(ref) then
  443. FreeTemp(list,ref.offset,[tt_normal,tt_ansistring,tt_widestring,tt_interfacecom]);
  444. end;
  445. initialization
  446. tg := ttgobj.create;
  447. finalization
  448. tg.free;
  449. end.
  450. {
  451. $Log$
  452. Revision 1.15 2002-09-01 18:42:50 peter
  453. * reduced level of comment that type is wrong for release
  454. Revision 1.14 2002/09/01 12:14:53 peter
  455. * fixed some wrong levels in extdebug comments
  456. Revision 1.13 2002/08/24 18:35:04 peter
  457. * when reusing a block also update the temptype instead of forcing it
  458. to tt_normal
  459. Revision 1.12 2002/08/23 16:14:49 peter
  460. * tempgen cleanup
  461. * tt_noreuse temp type added that will be used in genentrycode
  462. Revision 1.11 2002/08/17 09:23:44 florian
  463. * first part of procinfo rewrite
  464. Revision 1.10 2002/07/01 18:46:29 peter
  465. * internal linker
  466. * reorganized aasm layer
  467. Revision 1.9 2002/05/18 13:34:21 peter
  468. * readded missing revisions
  469. Revision 1.8 2002/05/16 19:46:45 carl
  470. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  471. + try to fix temp allocation (still in ifdef)
  472. + generic constructor calls
  473. + start of tassembler / tmodulebase class cleanup
  474. Revision 1.7 2002/05/14 19:34:52 peter
  475. * removed old logs and updated copyright year
  476. Revision 1.6 2002/04/15 19:08:22 carl
  477. + target_info.size_of_pointer -> pointer_size
  478. + some cleanup of unused types/variables
  479. Revision 1.5 2002/04/07 13:38:48 carl
  480. + update documentation
  481. Revision 1.4 2002/04/07 09:17:17 carl
  482. + documentation
  483. - clean-up
  484. Revision 1.3 2002/04/04 19:06:06 peter
  485. * removed unused units
  486. * use tlocation.size in cg.a_*loc*() routines
  487. Revision 1.2 2002/04/02 17:11:32 peter
  488. * tlocation,treference update
  489. * LOC_CONSTANT added for better constant handling
  490. * secondadd splitted in multiple routines
  491. * location_force_reg added for loading a location to a register
  492. of a specified size
  493. * secondassignment parses now first the right and then the left node
  494. (this is compatible with Kylix). This saves a lot of push/pop especially
  495. with string operations
  496. * adapted some routines to use the new cg methods
  497. Revision 1.1 2002/03/31 20:26:37 jonas
  498. + a_loadfpu_* and a_loadmm_* methods in tcg
  499. * register allocation is now handled by a class and is mostly processor
  500. independent (+rgobj.pas and i386/rgcpu.pas)
  501. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  502. * some small improvements and fixes to the optimizer
  503. * some register allocation fixes
  504. * some fpuvaroffset fixes in the unary minus node
  505. * push/popusedregisters is now called rg.save/restoreusedregisters and
  506. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  507. also better optimizable)
  508. * fixed and optimized register saving/restoring for new/dispose nodes
  509. * LOC_FPU locations now also require their "register" field to be set to
  510. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  511. - list field removed of the tnode class because it's not used currently
  512. and can cause hard-to-find bugs
  513. }