tgobj.pas 21 KB

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