tgobj.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. {
  2. $Id$
  3. Copyright (c) 1993-99 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. unit tgobj;
  19. interface
  20. uses
  21. {$ifdef i386}
  22. i386base,i386asm,
  23. {$else i386}
  24. cpubase,
  25. cpuinfo,
  26. {$endif i386}
  27. cobjects,globals,tree,hcodegen,verbose,files,aasm;
  28. type
  29. tregisterset = set of tregister;
  30. tpushed = array[firstreg..lastreg] of boolean;
  31. tsaved = array[firstreg..lastreg] of longint;
  32. ttemptype = (tt_none,tt_free,tt_normal,tt_persistant,tt_ansistring,tt_freeansistring,tt_widestring,tt_freewidestring);
  33. ttemptypeset = set of ttemptype;
  34. ptemprecord = ^ttemprecord;
  35. ttemprecord = record
  36. temptype : ttemptype;
  37. pos : longint;
  38. size : longint;
  39. next : ptemprecord;
  40. nextfree : ptemprecord; { for faster freeblock checking }
  41. {$ifdef EXTDEBUG}
  42. posinfo,
  43. releaseposinfo : tfileposinfo;
  44. {$endif}
  45. end;
  46. ttgobj = object
  47. unusedregsint,availabletempregsint : tregisterset;
  48. countusableregsint,
  49. countusableregsfpu,
  50. countusableregsmm : byte;
  51. c_countusableregsint,
  52. c_countusableregsfpu,
  53. c_countusableregsmm : byte;
  54. usedinproc : tregisterset;
  55. { contains all temps }
  56. templist : ptemprecord;
  57. { contains all free temps using nextfree links }
  58. tempfreelist : ptemprecord;
  59. { Offsets of the first/last temp }
  60. firsttemp,
  61. lasttemp : longint;
  62. constructor init;
  63. { generates temporary variables }
  64. procedure resettempgen;
  65. procedure setfirsttemp(l : longint);
  66. function gettempsize : longint;
  67. function newtempofsize(size : longint) : longint;
  68. function gettempofsize(size : longint) : longint;
  69. { special call for inlined procedures }
  70. function gettempofsizepersistant(size : longint) : longint;
  71. { for parameter func returns }
  72. procedure normaltemptopersistant(pos : longint);
  73. procedure persistanttemptonormal(pos : longint);
  74. procedure ungetpersistanttemp(pos : longint);
  75. procedure gettempofsizereference(l : longint;var ref : treference);
  76. function istemp(const ref : treference) : boolean;virtual;
  77. procedure ungetiftemp(const ref : treference);
  78. function ungetiftempansi(const ref : treference) : boolean;
  79. function gettempansistringreference(var ref : treference):boolean;
  80. { the following methods must be overriden }
  81. function getregisterint : tregister;virtual;
  82. procedure ungetregisterint(r : tregister);virtual;
  83. { tries to allocate the passed register, if possible }
  84. function getexplicitregisterint(r : tregister) : tregister;virtual;
  85. procedure ungetregister(r : tregister);virtual;
  86. procedure cleartempgen;virtual;
  87. procedure del_reference(const ref : treference);virtual;
  88. procedure del_locref(const location : tlocation);virtual;
  89. procedure del_location(const l : tlocation);virtual;
  90. { pushs and restores registers }
  91. procedure pushusedregisters(var pushed : tpushed;b : byte);virtual;
  92. procedure popusedregisters(const pushed : tpushed);virtual;
  93. { saves and restores used registers to temp. values }
  94. procedure saveusedregisters(var saved : tsaved;b : byte);virtual;
  95. procedure restoreusedregisters(const saved : tsaved);virtual;
  96. procedure clearregistercount;virtual;
  97. procedure resetusableregisters;virtual;
  98. private
  99. function ungettemp(pos:longint;allowtype:ttemptype):ttemptype;
  100. end;
  101. implementation
  102. uses
  103. scanner,systems;
  104. constructor ttgobj.init;
  105. begin
  106. tempfreelist:=nil;
  107. templist:=nil;
  108. end;
  109. procedure ttgobj.resettempgen;
  110. var
  111. hp : ptemprecord;
  112. begin
  113. { Clear the old templist }
  114. while assigned(templist) do
  115. begin
  116. {$ifdef EXTDEBUG}
  117. case templist^.temptype of
  118. tt_normal,
  119. tt_persistant :
  120. Comment(V_Warning,'temporary assignment of size '+
  121. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  122. ':'+tostr(templist^.posinfo.column)+
  123. ' at pos '+tostr(templist^.pos)+
  124. ' not freed at the end of the procedure');
  125. tt_ansistring :
  126. Comment(V_Warning,'temporary ANSI assignment of size '+
  127. tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
  128. ':'+tostr(templist^.posinfo.column)+
  129. ' at pos '+tostr(templist^.pos)+
  130. ' not freed at the end of the procedure');
  131. end;
  132. {$endif}
  133. hp:=templist;
  134. templist:=hp^.next;
  135. dispose(hp);
  136. end;
  137. templist:=nil;
  138. tempfreelist:=nil;
  139. firsttemp:=0;
  140. lasttemp:=0;
  141. end;
  142. procedure ttgobj.setfirsttemp(l : longint);
  143. begin
  144. { this is a negative value normally }
  145. if l < 0 then
  146. Begin
  147. if odd(l) then
  148. Dec(l);
  149. end
  150. else
  151. Begin
  152. if odd(l) then
  153. Inc(l);
  154. end;
  155. firsttemp:=l;
  156. lasttemp:=l;
  157. end;
  158. function ttgobj.newtempofsize(size : longint) : longint;
  159. var
  160. tl : ptemprecord;
  161. begin
  162. { Just extend the temp, everything below has been use
  163. already }
  164. dec(lasttemp,size);
  165. { now we can create the templist entry }
  166. new(tl);
  167. tl^.temptype:=tt_normal;
  168. tl^.pos:=lasttemp;
  169. tl^.size:=size;
  170. tl^.next:=templist;
  171. tl^.nextfree:=nil;
  172. templist:=tl;
  173. newtempofsize:=tl^.pos;
  174. end;
  175. function ttgobj.gettempofsize(size : longint) : longint;
  176. var
  177. tl,
  178. bestslot,bestprev,
  179. hprev,hp : ptemprecord;
  180. bestsize,ofs : longint;
  181. begin
  182. bestprev:=nil;
  183. bestslot:=nil;
  184. tl:=nil;
  185. bestsize:=0;
  186. { Align needed size on 4 bytes }
  187. if (size mod 4)<>0 then
  188. size:=size+(4-(size mod 4));
  189. { First check the tmpfreelist }
  190. if assigned(tempfreelist) then
  191. begin
  192. { Check for a slot with the same size first }
  193. hprev:=nil;
  194. hp:=tempfreelist;
  195. while assigned(hp) do
  196. begin
  197. {$ifdef EXTDEBUG}
  198. if hp^.temptype<>tt_free then
  199. Comment(V_Warning,'Temp in freelist is not set to tt_free');
  200. {$endif}
  201. if hp^.size>=size then
  202. begin
  203. { Slot is the same size, then leave immediatly }
  204. if hp^.size=size then
  205. begin
  206. bestprev:=hprev;
  207. bestslot:=hp;
  208. bestsize:=size;
  209. break;
  210. end
  211. else
  212. begin
  213. if (bestsize=0) or (hp^.size<bestsize) then
  214. begin
  215. bestprev:=hprev;
  216. bestslot:=hp;
  217. bestsize:=hp^.size;
  218. end;
  219. end;
  220. end;
  221. hprev:=hp;
  222. hp:=hp^.nextfree;
  223. end;
  224. end;
  225. { Reuse an old temp ? }
  226. if assigned(bestslot) then
  227. begin
  228. if bestsize=size then
  229. begin
  230. bestslot^.temptype:=tt_normal;
  231. ofs:=bestslot^.pos;
  232. tl:=bestslot;
  233. { Remove from the tempfreelist }
  234. if assigned(bestprev) then
  235. bestprev^.nextfree:=bestslot^.nextfree
  236. else
  237. tempfreelist:=bestslot^.nextfree;
  238. end
  239. else
  240. begin
  241. { Resize the old block }
  242. dec(bestslot^.size,size);
  243. { Create new block and link after bestslot }
  244. new(tl);
  245. tl^.temptype:=tt_normal;
  246. tl^.pos:=bestslot^.pos+bestslot^.size;
  247. ofs:=tl^.pos;
  248. tl^.size:=size;
  249. tl^.nextfree:=nil;
  250. { link the new block }
  251. tl^.next:=bestslot^.next;
  252. bestslot^.next:=tl;
  253. end;
  254. end
  255. else
  256. begin
  257. ofs:=newtempofsize(size);
  258. {$ifdef EXTDEBUG}
  259. tl:=templist;
  260. {$endif}
  261. end;
  262. {$ifdef EXTDEBUG}
  263. tl^.posinfo:=aktfilepos;
  264. {$endif}
  265. exprasmlist^.concat(new(paitempalloc,alloc(ofs,size)));
  266. gettempofsize:=ofs;
  267. end;
  268. function ttgobj.gettempofsizepersistant(size : longint) : longint;
  269. var
  270. l : longint;
  271. begin
  272. l:=gettempofsize(size);
  273. templist^.temptype:=tt_persistant;
  274. {$ifdef EXTDEBUG}
  275. Comment(V_Debug,'temp managment : call to gettempofsizepersistant()'+
  276. ' with size '+tostr(size)+' returned '+tostr(l));
  277. {$endif}
  278. gettempofsizepersistant:=l;
  279. end;
  280. function ttgobj.gettempsize : longint;
  281. begin
  282. gettempsize:=Align(-lasttemp,target_os.stackalignment);
  283. end;
  284. procedure ttgobj.gettempofsizereference(l : longint;var ref : treference);
  285. begin
  286. { do a reset, because the reference isn't used }
  287. reset_reference(ref);
  288. ref.offset:=gettempofsize(l);
  289. ref.base:=procinfo.framepointer;
  290. end;
  291. function ttgobj.gettempansistringreference(var ref : treference):boolean;
  292. var
  293. foundslot,tl : ptemprecord;
  294. begin
  295. { do a reset, because the reference isn't used }
  296. reset_reference(ref);
  297. ref.base:=procinfo.framepointer;
  298. { Reuse old ansi slot ? }
  299. foundslot:=nil;
  300. tl:=templist;
  301. while assigned(tl) do
  302. begin
  303. if tl^.temptype=tt_freeansistring then
  304. begin
  305. foundslot:=tl;
  306. {$ifdef EXTDEBUG}
  307. tl^.posinfo:=aktfilepos;
  308. {$endif}
  309. break;
  310. end;
  311. tl:=tl^.next;
  312. end;
  313. if assigned(foundslot) then
  314. begin
  315. foundslot^.temptype:=tt_ansistring;
  316. ref.offset:=foundslot^.pos;
  317. { we're reusing an old slot then set the function result to true
  318. so that we can call a decr_ansistr }
  319. gettempansistringreference:=true;
  320. end
  321. else
  322. begin
  323. ref.offset:=newtempofsize(target_os.size_of_pointer);
  324. {$ifdef EXTDEBUG}
  325. templist^.posinfo:=aktfilepos;
  326. {$endif}
  327. templist^.temptype:=tt_ansistring;
  328. { set result to false, we don't need an decr_ansistr }
  329. gettempansistringreference:=true;
  330. end;
  331. exprasmlist^.concat(new(paitempalloc,alloc(ref.offset,target_os.size_of_pointer)));
  332. end;
  333. function ttgobj.ungetiftempansi(const ref : treference) : boolean;
  334. var
  335. tl : ptemprecord;
  336. begin
  337. ungetiftempansi:=false;
  338. tl:=templist;
  339. while assigned(tl) do
  340. begin
  341. if tl^.pos=ref.offset then
  342. begin
  343. if tl^.temptype=tt_ansistring then
  344. begin
  345. tl^.temptype:=tt_freeansistring;
  346. ungetiftempansi:=true;
  347. exprasmlist^.concat(new(paitempalloc,dealloc(tl^.pos,tl^.size)));
  348. exit;
  349. {$ifdef EXTDEBUG}
  350. end
  351. else if (tl^.temptype=tt_freeansistring) then
  352. begin
  353. Comment(V_Debug,'temp ansi managment problem : ungetiftempansi()'+
  354. ' at pos '+tostr(ref.offset)+ ' already free !');
  355. {$endif}
  356. end;
  357. end;
  358. tl:=tl^.next;
  359. end;
  360. end;
  361. function ttgobj.istemp(const ref : treference) : boolean;
  362. begin
  363. istemp:=((ref.base=procinfo.framepointer) and
  364. (ref.offset<firsttemp));
  365. end;
  366. procedure ttgobj.persistanttemptonormal(pos : longint);
  367. var
  368. hp : ptemprecord;
  369. begin
  370. hp:=templist;
  371. while assigned(hp) do
  372. if (hp^.pos=pos) and (hp^.temptype=tt_persistant) then
  373. begin
  374. {$ifdef EXTDEBUG}
  375. Comment(V_Debug,'temp managment : persistanttemptonormal()'+
  376. ' at pos '+tostr(pos)+ ' found !');
  377. {$endif}
  378. hp^.temptype:=tt_normal;
  379. exit;
  380. end
  381. else
  382. hp:=hp^.next;
  383. {$ifdef EXTDEBUG}
  384. Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
  385. ' at pos '+tostr(pos)+ ' not found !');
  386. {$endif}
  387. end;
  388. procedure ttgobj.normaltemptopersistant(pos : longint);
  389. var
  390. hp : ptemprecord;
  391. begin
  392. hp:=templist;
  393. while assigned(hp) do
  394. if (hp^.pos=pos) and (hp^.temptype=tt_normal) then
  395. begin
  396. {$ifdef EXTDEBUG}
  397. Comment(V_Debug,'temp managment : normaltemptopersistant()'+
  398. ' at pos '+tostr(pos)+ ' found !');
  399. {$endif}
  400. hp^.temptype:=tt_persistant;
  401. exit;
  402. end
  403. else
  404. hp:=hp^.next;
  405. {$ifdef EXTDEBUG}
  406. Comment(V_Debug,'temp managment problem : normaltemptopersistant()'+
  407. ' at pos '+tostr(pos)+ ' not found !');
  408. {$endif}
  409. end;
  410. function ttgobj.ungettemp(pos:longint;allowtype:ttemptype):ttemptype;
  411. var
  412. hp,hnext,hprev,hprevfree : ptemprecord;
  413. begin
  414. ungettemp:=tt_none;
  415. hp:=templist;
  416. hprev:=nil;
  417. hprevfree:=nil;
  418. while assigned(hp) do
  419. begin
  420. if (hp^.pos=pos) then
  421. begin
  422. { check type }
  423. ungettemp:=hp^.temptype;
  424. if hp^.temptype<>allowtype then
  425. begin
  426. exit;
  427. end;
  428. exprasmlist^.concat(new(paitempalloc,dealloc(hp^.pos,hp^.size)));
  429. { set this block to free }
  430. hp^.temptype:=tt_free;
  431. { Update tempfreelist }
  432. if assigned(hprevfree) then
  433. begin
  434. { Connect with previous? }
  435. if assigned(hprev) and (hprev^.temptype=tt_free) then
  436. begin
  437. inc(hprev^.size,hp^.size);
  438. hprev^.next:=hp^.next;
  439. dispose(hp);
  440. hp:=hprev;
  441. end
  442. else
  443. hprevfree^.nextfree:=hp;
  444. end
  445. else
  446. begin
  447. hp^.nextfree:=tempfreelist;
  448. tempfreelist:=hp;
  449. end;
  450. { Next block free ? Yes, then concat }
  451. hnext:=hp^.next;
  452. if assigned(hnext) and (hnext^.temptype=tt_free) then
  453. begin
  454. inc(hp^.size,hnext^.size);
  455. hp^.nextfree:=hnext^.nextfree;
  456. hp^.next:=hnext^.next;
  457. dispose(hnext);
  458. end;
  459. exit;
  460. end;
  461. if (hp^.temptype=tt_free) then
  462. hprevfree:=hp;
  463. hprev:=hp;
  464. hp:=hp^.next;
  465. end;
  466. ungettemp:=tt_none;
  467. end;
  468. procedure ttgobj.ungetpersistanttemp(pos : longint);
  469. begin
  470. {$ifdef EXTDEBUG}
  471. if ungettemp(pos,tt_persistant)<>tt_persistant then
  472. Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
  473. ' at pos '+tostr(pos)+ ' not found !');
  474. {$else}
  475. ungettemp(pos,tt_persistant);
  476. {$endif}
  477. end;
  478. procedure ttgobj.ungetiftemp(const ref : treference);
  479. var
  480. tt : ttemptype;
  481. begin
  482. if istemp(ref) then
  483. begin
  484. { first check if ansistring }
  485. if ungetiftempansi(ref) then
  486. exit;
  487. tt:=ungettemp(ref.offset,tt_normal);
  488. {$ifdef EXTDEBUG}
  489. if tt=tt_persistant then
  490. Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!');
  491. if tt=tt_none then
  492. Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset));
  493. {$endif}
  494. end;
  495. end;
  496. function ttgobj.getregisterint : tregister;
  497. var
  498. i : tregister;
  499. begin
  500. if countusableregsint=0 then
  501. internalerror(10);
  502. for i:=firstreg to lastreg do
  503. begin
  504. if i in unusedregsint then
  505. begin
  506. exclude(unusedregsint,i);
  507. include(usedinproc,i);
  508. dec(countusableregsint);
  509. exprasmlist^.concat(new(pairegalloc,alloc(i)));
  510. exit;
  511. end;
  512. end;
  513. internalerror(28991);
  514. end;
  515. procedure ttgobj.ungetregisterint(r : tregister);
  516. begin
  517. { takes much time }
  518. if not(r in availabletempregsint) then
  519. exit;
  520. include(unusedregsint,r);
  521. inc(countusableregsint);
  522. exprasmlist^.concat(new(pairegalloc,dealloc(r)));
  523. end;
  524. { tries to allocate the passed register, if possible }
  525. function ttgobj.getexplicitregisterint(r : tregister) : tregister;
  526. begin
  527. if r in unusedregsint then
  528. begin
  529. dec(countusableregsint);
  530. exclude(unusedregsint,r);
  531. include(usedinproc,r);
  532. exprasmlist^.concat(new(pairegalloc,alloc(r)));
  533. getexplicitregisterint:=r;
  534. end
  535. else
  536. getexplicitregisterint:=getregisterint;
  537. end;
  538. procedure ttgobj.ungetregister(r : tregister);
  539. begin
  540. if r in intregs then
  541. ungetregisterint(r)
  542. {!!!!!!!!
  543. else if r in fpuregs then
  544. ungetregisterfpu(r)
  545. else if r in mmregs then
  546. ungetregistermm(r)
  547. }
  548. else internalerror(18);
  549. end;
  550. procedure ttgobj.cleartempgen;
  551. begin
  552. countusableregsint:=c_countusableregsint;
  553. countusableregsfpu:=c_countusableregsfpu;
  554. countusableregsmm:=c_countusableregsmm;
  555. unusedregsint:=availabletempregsint;
  556. {!!!!!!!!
  557. unusedregsfpu:=availabletempregsfpu;
  558. unusedregsmm:=availabletempregsmm;
  559. }
  560. end;
  561. procedure ttgobj.del_reference(const ref : treference);
  562. begin
  563. ungetregister(ref.base);
  564. end;
  565. procedure ttgobj.del_locref(const location : tlocation);
  566. begin
  567. if (location.loc<>LOC_MEM) and (location.loc<>LOC_REFERENCE) then
  568. exit;
  569. del_reference(location.reference);
  570. end;
  571. procedure ttgobj.del_location(const l : tlocation);
  572. begin
  573. case l.loc of
  574. LOC_REGISTER :
  575. ungetregister(l.register);
  576. LOC_MEM,LOC_REFERENCE :
  577. del_reference(l.reference);
  578. end;
  579. end;
  580. { pushs and restores registers }
  581. procedure ttgobj.pushusedregisters(var pushed : tpushed;b : byte);
  582. begin
  583. runerror(255);
  584. end;
  585. procedure ttgobj.popusedregisters(const pushed : tpushed);
  586. begin
  587. runerror(255);
  588. end;
  589. { saves and restores used registers to temp. values }
  590. procedure ttgobj.saveusedregisters(var saved : tsaved;b : byte);
  591. begin
  592. runerror(255);
  593. end;
  594. procedure ttgobj.restoreusedregisters(const saved : tsaved);
  595. begin
  596. runerror(255);
  597. end;
  598. procedure ttgobj.clearregistercount;
  599. begin
  600. runerror(255);
  601. end;
  602. procedure ttgobj.resetusableregisters;
  603. begin
  604. runerror(255);
  605. end;
  606. end.
  607. {
  608. $Log$
  609. Revision 1.1 1999-08-02 17:14:12 florian
  610. + changed the temp. generator to an object
  611. }