cgbase.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This units implements some code generator helper routines
  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 cgbase;
  19. interface
  20. uses
  21. globtype,cobjects,aasm,symconst,symtable,verbose,tree,
  22. cpuasm,cpubase
  23. {$IFDEF NEWST}
  24. ,defs,symbols
  25. {$ENDIF NEWST};
  26. const
  27. pi_uses_asm = $1; { set, if the procedure uses asm }
  28. pi_is_global = $2; { set, if the procedure is exported by an unit }
  29. pi_do_call = $4; { set, if the procedure does a call }
  30. pi_operator = $8; { set, if the procedure is an operator }
  31. pi_C_import = $10; { set, if the procedure is an external C function }
  32. pi_uses_exceptions = $20;{ set, if the procedure has a try statement => }
  33. { no register variables }
  34. pi_is_assembler = $40; { set if the procedure is declared as ASSEMBLER
  35. => don't optimize}
  36. pi_needs_implicit_finally = $80; { set, if the procedure contains data which }
  37. { needs to be finalized }
  38. type
  39. TOpCg = (OP_ADD,OP_AND,OP_DIV,OP_IDIV,OP_IMUL,OP_MUL,OP_NEG,OP_NOT,
  40. OP_OR,OP_SAR,OP_SHL,OP_SHR,OP_SUB,OP_XOR);
  41. TOpCmp = (OC_NONE,OC_EQ,OC_GT,OC_LT,OC_GTE,OC_LTE,OC_NE,OC_BE,OC_B,
  42. OC_AE,OC_A);
  43. TCgSize = (OS_NO,OS_8,OS_16,OS_32,OS_64);
  44. pprocinfo = ^tprocinfo;
  45. tprocinfo = object
  46. { pointer to parent in nested procedures }
  47. parent : pprocinfo;
  48. { current class, if we are in a method }
  49. _class : pobjectdef;
  50. { return type }
  51. {$IFDEF NEWST}
  52. retdef:Pdef;
  53. {$ELSE}
  54. returntype : ttype;
  55. {$ENDIF NEWST}
  56. { symbol of the function, and the sym for result variable }
  57. resultfuncretsym,
  58. funcretsym : pfuncretsym;
  59. funcret_state : tvarstate;
  60. { the definition of the proc itself }
  61. def : pprocdef;
  62. sym : pprocsym;
  63. { frame pointer offset }
  64. framepointer_offset : longint;
  65. { self pointer offset }
  66. selfpointer_offset : longint;
  67. { result value offset }
  68. return_offset : longint;
  69. { firsttemp position }
  70. firsttemp_offset : longint;
  71. { parameter offset }
  72. para_offset : longint;
  73. { every register which must be saved by the entry code }
  74. { (and restored by the exit code) must be in that set }
  75. registerstosave : tregisterset;
  76. { some collected informations about the procedure }
  77. { see pi_xxxx above }
  78. flags : longint;
  79. { register used as frame pointer }
  80. framepointer : tregister;
  81. { true, if the procedure is exported by an unit }
  82. globalsymbol : boolean;
  83. { true, if the procedure should be exported (only OS/2) }
  84. exported : boolean;
  85. { true, if we can not use fast exit code }
  86. no_fast_exit : boolean;
  87. { code for the current procedure }
  88. aktproccode,aktentrycode,
  89. aktexitcode,aktlocaldata : paasmoutput;
  90. { local data is used for smartlink }
  91. constructor init;
  92. destructor done;
  93. end;
  94. { some kind of temp. types needs to be destructed }
  95. { for example ansistring, this is done using this }
  96. { list }
  97. ptemptodestroy = ^ttemptodestroy;
  98. ttemptodestroy = object(tlinkedlist_item)
  99. typ : pdef;
  100. address : treference;
  101. constructor init(const a : treference;p : pdef);
  102. end;
  103. const
  104. { defines the default address size for a processor }
  105. { and defines the natural int size for a processor }
  106. {$ifdef i386}
  107. OS_ADDR = OS_32;
  108. OS_INT = OS_32;
  109. {$endif i386}
  110. {$ifdef alpha}
  111. OS_ADDR = OS_64;
  112. OS_INT = OS_64;
  113. {$endif alpha}
  114. {$ifdef powerpc}
  115. OS_ADDR = OS_32;
  116. OS_INT = OS_32;
  117. {$endif powercc}
  118. var
  119. { info about the current sub routine }
  120. procinfo : pprocinfo;
  121. { labels for BREAK and CONTINUE }
  122. aktbreaklabel,aktcontinuelabel : pasmlabel;
  123. { label when the result is true or false }
  124. truelabel,falselabel : pasmlabel;
  125. { label to leave the sub routine }
  126. aktexitlabel : pasmlabel;
  127. { also an exit label, only used we need to clear only the stack }
  128. aktexit2label : pasmlabel;
  129. { only used in constructor for fail or if getmem fails }
  130. faillabel,quickexitlabel : pasmlabel;
  131. { Boolean, wenn eine loadn kein Assembler erzeugt hat }
  132. simple_loadn : boolean;
  133. { tries to hold the amount of times which the current tree is processed }
  134. t_times : longint;
  135. { true, if an error while code generation occurs }
  136. codegenerror : boolean;
  137. { this is for open arrays and strings }
  138. { but be careful, this data is in the }
  139. { generated code destroyed quick, and also }
  140. { the next call of secondload destroys this }
  141. { data }
  142. { So be careful using the informations }
  143. { provided by this variables }
  144. highframepointer : tregister;
  145. highoffset : longint;
  146. make_const_global : boolean;
  147. temptoremove : plinkedlist;
  148. { message calls with codegenerror support }
  149. procedure cgmessage(const t : tmsgconst);
  150. procedure cgmessage1(const t : tmsgconst;const s : string);
  151. procedure cgmessage2(const t : tmsgconst;const s1,s2 : string);
  152. procedure cgmessage3(const t : tmsgconst;const s1,s2,s3 : string);
  153. procedure CGMessagePos(const pos:tfileposinfo;t:tmsgconst);
  154. procedure CGMessagePos1(const pos:tfileposinfo;t:tmsgconst;const s1:string);
  155. procedure CGMessagePos2(const pos:tfileposinfo;t:tmsgconst;const s1,s2:string);
  156. procedure CGMessagePos3(const pos:tfileposinfo;t:tmsgconst;const s1,s2,s3:string);
  157. { initialize respectively terminates the code generator }
  158. { for a new module or procedure }
  159. procedure codegen_doneprocedure;
  160. procedure codegen_donemodule;
  161. procedure codegen_newmodule;
  162. procedure codegen_newprocedure;
  163. { counts the labels }
  164. function case_count_labels(root : pcaserecord) : longint;
  165. { searches the highest label }
  166. function case_get_max(root : pcaserecord) : longint;
  167. { searches the lowest label }
  168. function case_get_min(root : pcaserecord) : longint;
  169. { clears a location record }
  170. procedure clear_location(var loc : tlocation);
  171. { copies a location, takes care of the symbol }
  172. procedure set_location(var destloc,sourceloc : tlocation);
  173. { swaps two locations }
  174. procedure swap_location(var destloc,sourceloc : tlocation);
  175. implementation
  176. uses
  177. comphook;
  178. {*****************************************************************************
  179. override the message calls to set codegenerror
  180. *****************************************************************************}
  181. procedure cgmessage(const t : tmsgconst);
  182. var
  183. olderrorcount : longint;
  184. begin
  185. if not(codegenerror) then
  186. begin
  187. olderrorcount:=status.errorcount;
  188. verbose.Message(t);
  189. codegenerror:=olderrorcount<>status.errorcount;
  190. end;
  191. end;
  192. procedure cgmessage1(const t : tmsgconst;const s : string);
  193. var
  194. olderrorcount : longint;
  195. begin
  196. if not(codegenerror) then
  197. begin
  198. olderrorcount:=status.errorcount;
  199. verbose.Message1(t,s);
  200. codegenerror:=olderrorcount<>status.errorcount;
  201. end;
  202. end;
  203. procedure cgmessage2(const t : tmsgconst;const s1,s2 : string);
  204. var
  205. olderrorcount : longint;
  206. begin
  207. if not(codegenerror) then
  208. begin
  209. olderrorcount:=status.errorcount;
  210. verbose.Message2(t,s1,s2);
  211. codegenerror:=olderrorcount<>status.errorcount;
  212. end;
  213. end;
  214. procedure cgmessage3(const t : tmsgconst;const s1,s2,s3 : string);
  215. var
  216. olderrorcount : longint;
  217. begin
  218. if not(codegenerror) then
  219. begin
  220. olderrorcount:=status.errorcount;
  221. verbose.Message3(t,s1,s2,s3);
  222. codegenerror:=olderrorcount<>status.errorcount;
  223. end;
  224. end;
  225. procedure cgmessagepos(const pos:tfileposinfo;t : tmsgconst);
  226. var
  227. olderrorcount : longint;
  228. begin
  229. if not(codegenerror) then
  230. begin
  231. olderrorcount:=Errorcount;
  232. verbose.MessagePos(pos,t);
  233. codegenerror:=olderrorcount<>Errorcount;
  234. end;
  235. end;
  236. procedure cgmessagepos1(const pos:tfileposinfo;t : tmsgconst;const s1 : string);
  237. var
  238. olderrorcount : longint;
  239. begin
  240. if not(codegenerror) then
  241. begin
  242. olderrorcount:=Errorcount;
  243. verbose.MessagePos1(pos,t,s1);
  244. codegenerror:=olderrorcount<>Errorcount;
  245. end;
  246. end;
  247. procedure cgmessagepos2(const pos:tfileposinfo;t : tmsgconst;const s1,s2 : string);
  248. var
  249. olderrorcount : longint;
  250. begin
  251. if not(codegenerror) then
  252. begin
  253. olderrorcount:=Errorcount;
  254. verbose.MessagePos2(pos,t,s1,s2);
  255. codegenerror:=olderrorcount<>Errorcount;
  256. end;
  257. end;
  258. procedure cgmessagepos3(const pos:tfileposinfo;t : tmsgconst;const s1,s2,s3 : string);
  259. var
  260. olderrorcount : longint;
  261. begin
  262. if not(codegenerror) then
  263. begin
  264. olderrorcount:=Errorcount;
  265. verbose.MessagePos3(pos,t,s1,s2,s3);
  266. codegenerror:=olderrorcount<>Errorcount;
  267. end;
  268. end;
  269. {****************************************************************************
  270. TProcInfo
  271. ****************************************************************************}
  272. constructor tprocinfo.init;
  273. begin
  274. parent:=nil;
  275. _class:=nil;
  276. {$IFNDEF NEWST}
  277. returntype.reset;
  278. {$ENDIF NEWST}
  279. resultfuncretsym:=nil;
  280. funcretsym:=nil;
  281. funcret_state:=vs_none;
  282. def:=nil;
  283. sym:=nil;
  284. framepointer_offset:=0;
  285. selfpointer_offset:=0;
  286. return_offset:=0;
  287. firsttemp_offset:=0;
  288. para_offset:=0;
  289. registerstosave:=[];
  290. flags:=0;
  291. framepointer:=R_NO;
  292. globalsymbol:=false;
  293. exported:=false;
  294. aktentrycode:=new(paasmoutput,init);
  295. aktexitcode:=new(paasmoutput,init);
  296. aktproccode:=new(paasmoutput,init);
  297. aktlocaldata:=new(paasmoutput,init);
  298. end;
  299. destructor tprocinfo.done;
  300. begin
  301. dispose(aktentrycode,done);
  302. dispose(aktexitcode,done);
  303. dispose(aktproccode,done);
  304. dispose(aktlocaldata,done);
  305. end;
  306. {*****************************************************************************
  307. initialize/terminate the codegen for procedure and modules
  308. *****************************************************************************}
  309. procedure codegen_newprocedure;
  310. begin
  311. aktbreaklabel:=nil;
  312. aktcontinuelabel:=nil;
  313. new(procinfo,init);
  314. { aktexitlabel:=0; is store in oldaktexitlabel
  315. so it must not be reset to zero before this storage !}
  316. end;
  317. procedure codegen_doneprocedure;
  318. begin
  319. dispose(procinfo,done);
  320. procinfo:=nil;
  321. end;
  322. procedure codegen_newmodule;
  323. begin
  324. exprasmlist:=new(paasmoutput,init);
  325. datasegment:=new(paasmoutput,init);
  326. codesegment:=new(paasmoutput,init);
  327. bsssegment:=new(paasmoutput,init);
  328. debuglist:=new(paasmoutput,init);
  329. consts:=new(paasmoutput,init);
  330. rttilist:=new(paasmoutput,init);
  331. importssection:=nil;
  332. exportssection:=nil;
  333. resourcesection:=nil;
  334. asmsymbollist:=new(pasmsymbollist,init);
  335. asmsymbollist^.usehash;
  336. end;
  337. procedure codegen_donemodule;
  338. begin
  339. dispose(exprasmlist,done);
  340. dispose(codesegment,done);
  341. dispose(bsssegment,done);
  342. dispose(datasegment,done);
  343. dispose(debuglist,done);
  344. dispose(consts,done);
  345. dispose(rttilist,done);
  346. if assigned(importssection) then
  347. dispose(importssection,done);
  348. if assigned(exportssection) then
  349. dispose(exportssection,done);
  350. if assigned(resourcesection) then
  351. dispose(resourcesection,done);
  352. if assigned(resourcestringlist) then
  353. dispose(resourcestringlist,done);
  354. dispose(asmsymbollist,done);
  355. end;
  356. {*****************************************************************************
  357. Case Helpers
  358. *****************************************************************************}
  359. function case_count_labels(root : pcaserecord) : longint;
  360. var
  361. _l : longint;
  362. procedure count(p : pcaserecord);
  363. begin
  364. inc(_l);
  365. if assigned(p^.less) then
  366. count(p^.less);
  367. if assigned(p^.greater) then
  368. count(p^.greater);
  369. end;
  370. begin
  371. _l:=0;
  372. count(root);
  373. case_count_labels:=_l;
  374. end;
  375. function case_get_max(root : pcaserecord) : longint;
  376. var
  377. hp : pcaserecord;
  378. begin
  379. hp:=root;
  380. while assigned(hp^.greater) do
  381. hp:=hp^.greater;
  382. case_get_max:=hp^._high;
  383. end;
  384. function case_get_min(root : pcaserecord) : longint;
  385. var
  386. hp : pcaserecord;
  387. begin
  388. hp:=root;
  389. while assigned(hp^.less) do
  390. hp:=hp^.less;
  391. case_get_min:=hp^._low;
  392. end;
  393. {*****************************************************************************
  394. TTempToDestroy
  395. *****************************************************************************}
  396. constructor ttemptodestroy.init(const a : treference;p : pdef);
  397. begin
  398. inherited init;
  399. address:=a;
  400. typ:=p;
  401. end;
  402. {*****************************************************************************
  403. some helper routines to handle locations
  404. *****************************************************************************}
  405. procedure clear_location(var loc : tlocation);
  406. begin
  407. if ((loc.loc=LOC_MEM) or (loc.loc=LOC_REFERENCE)) and
  408. assigned(loc.reference.symbol) then
  409. dispose(loc.reference.symbol,done);
  410. loc.loc:=LOC_INVALID;
  411. end;
  412. procedure set_location(var destloc,sourceloc : tlocation);
  413. begin
  414. { this is needed if you want to be able to delete }
  415. { the string with the nodes }
  416. if assigned(destloc.reference.symbol) then
  417. dispose(destloc.reference.symbol,done);
  418. destloc:= sourceloc;
  419. if sourceloc.loc in [LOC_MEM,LOC_REFERENCE] then
  420. begin
  421. if assigned(sourceloc.reference.symbol) then
  422. destloc.reference.symbol:=
  423. sourceloc.reference.symbol;
  424. end
  425. else
  426. destloc.reference.symbol:=nil;
  427. end;
  428. procedure swap_location(var destloc,sourceloc : tlocation);
  429. var
  430. swapl : tlocation;
  431. begin
  432. swapl:=destloc;
  433. destloc:=sourceloc;
  434. sourceloc:=swapl;
  435. end;
  436. end.
  437. {
  438. $Log$
  439. Revision 1.1 2000-07-13 06:30:07 michael
  440. + Initial import
  441. Revision 1.19 2000/03/11 21:11:24 daniel
  442. * Ported hcgdata to new symtable.
  443. * Alignment code changed as suggested by Peter
  444. + Usage of my is operator replacement, is_object
  445. Revision 1.18 2000/02/28 17:23:58 daniel
  446. * Current work of symtable integration committed. The symtable can be
  447. activated by defining 'newst', but doesn't compile yet. Changes in type
  448. checking and oop are completed. What is left is to write a new
  449. symtablestack and adapt the parser to use it.
  450. Revision 1.17 2000/02/20 20:49:46 florian
  451. * newcg is compiling
  452. * fixed the dup id problem reported by Paul Y.
  453. Revision 1.16 2000/02/17 14:48:36 florian
  454. * updated to use old firstpass
  455. Revision 1.15 2000/01/07 01:14:52 peter
  456. * updated copyright to 2000
  457. Revision 1.14 1999/12/24 22:47:42 jonas
  458. * added OC_NONE to the compare forms (to allow unconditional jumps)
  459. Revision 1.13 1999/12/01 12:42:33 peter
  460. * fixed bug 698
  461. * removed some notes about unused vars
  462. Revision 1.12 1999/11/05 13:15:00 florian
  463. * some fixes to get the new cg compiling again
  464. Revision 1.11 1999/10/14 14:57:54 florian
  465. - removed the hcodegen use in the new cg, use cgbase instead
  466. Revision 1.10 1999/10/12 21:20:46 florian
  467. * new codegenerator compiles again
  468. Revision 1.9 1999/09/10 18:48:11 florian
  469. * some bug fixes (e.g. must_be_valid and procinfo.funcret_is_valid)
  470. * most things for stored properties fixed
  471. Revision 1.8 1999/08/06 13:26:49 florian
  472. * more changes ...
  473. Revision 1.7 1999/08/05 14:58:10 florian
  474. * some fixes for the floating point registers
  475. * more things for the new code generator
  476. Revision 1.6 1999/08/04 00:23:51 florian
  477. * renamed i386asm and i386base to cpuasm and cpubase
  478. Revision 1.5 1999/08/01 18:22:32 florian
  479. * made it again compilable
  480. Revision 1.4 1999/01/23 23:29:45 florian
  481. * first running version of the new code generator
  482. * when compiling exceptions under Linux fixed
  483. Revision 1.3 1999/01/06 22:58:48 florian
  484. + some stuff for the new code generator
  485. Revision 1.2 1998/12/26 15:20:28 florian
  486. + more changes for the new version
  487. Revision 1.1 1998/12/15 22:18:55 florian
  488. * some code added
  489. }