tgobj.pas 21 KB

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