tgobj.pas 21 KB

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