tgobj.pas 21 KB

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