cgbase.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This unit exports some help routines for the code generation
  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. {$i defines.inc}
  20. interface
  21. uses
  22. { common }
  23. cclasses,
  24. { global }
  25. globals,verbose,
  26. { symtable }
  27. symconst,symtype,symdef,symsym,
  28. { aasm }
  29. aasm,cpubase,cpuinfo,cginfo
  30. ;
  31. const
  32. {# bitmask indicating if the procedure uses asm }
  33. pi_uses_asm = $1;
  34. {# bitmask indicating if the procedure is exported by an unit }
  35. pi_is_global = $2;
  36. {# bitmask indicating if the procedure does a call }
  37. pi_do_call = $4;
  38. {# bitmask indicating if the procedure is an operator }
  39. pi_operator = $8;
  40. {# bitmask indicating if the procedure is an external C function }
  41. pi_c_import = $10;
  42. {# bitmask indicating if the procedure has a try statement = no register optimization }
  43. pi_uses_exceptions = $20;
  44. {# bitmask indicating if the procedure is declared as @var(assembler), don't optimize}
  45. pi_is_assembler = $40;
  46. {# bitmask indicating if the procedure contains data which needs to be finalized }
  47. pi_needs_implicit_finally = $80;
  48. type
  49. pprocinfo = ^tprocinfo;
  50. tprocinfo = object
  51. {# pointer to parent in nested procedures }
  52. parent : pprocinfo;
  53. {# current class, if we are in a method }
  54. _class : tobjectdef;
  55. {# the definition of the routine itself }
  56. procdef : tprocdef;
  57. {# frame pointer offset??? }
  58. framepointer_offset : longint;
  59. { self pointer offset???? }
  60. selfpointer_offset : longint;
  61. {# result value offset in stack (functions only) }
  62. return_offset : longint;
  63. {# firsttemp position }
  64. firsttemp_offset : longint;
  65. {# parameter offset in stack }
  66. para_offset : longint;
  67. {# some collected informations about the procedure
  68. see pi_xxxx above }
  69. flags : longint;
  70. {# register used as frame pointer }
  71. framepointer : tregister;
  72. {# true, if the procedure is exported by a unit }
  73. globalsymbol : boolean;
  74. {# true, if the procedure should be exported (only OS/2) }
  75. exported : boolean;
  76. {# true, if we can not use fast exit code }
  77. no_fast_exit : boolean;
  78. aktproccode,aktentrycode,
  79. aktexitcode,aktlocaldata : taasmoutput;
  80. constructor init;
  81. destructor done;
  82. end;
  83. pregvarinfo = ^tregvarinfo;
  84. tregvarinfo = record
  85. regvars : array[1..maxvarregs] of tvarsym;
  86. regvars_para : array[1..maxvarregs] of boolean;
  87. regvars_refs : array[1..maxvarregs] of longint;
  88. fpuregvars : array[1..maxfpuvarregs] of tvarsym;
  89. fpuregvars_para : array[1..maxfpuvarregs] of boolean;
  90. fpuregvars_refs : array[1..maxfpuvarregs] of longint;
  91. end;
  92. var
  93. {# information about the current sub routine being parsed (@var(pprocinfo))}
  94. procinfo : pprocinfo;
  95. { labels for BREAK and CONTINUE }
  96. aktbreaklabel,aktcontinuelabel : tasmlabel;
  97. { label when the result is true or false }
  98. truelabel,falselabel : tasmlabel;
  99. { label to leave the sub routine }
  100. aktexitlabel : tasmlabel;
  101. { also an exit label, only used we need to clear only the stack }
  102. aktexit2label : tasmlabel;
  103. { only used in constructor for fail or if getmem fails }
  104. faillabel,quickexitlabel : tasmlabel;
  105. {# true, if there was an error while code generation occurs }
  106. codegenerror : boolean;
  107. { save the size of pushed parameter, needed for aligning }
  108. pushedparasize : longint;
  109. { message calls with codegenerror support }
  110. procedure cgmessage(t : longint);
  111. procedure cgmessage1(t : longint;const s : string);
  112. procedure cgmessage2(t : longint;const s1,s2 : string);
  113. procedure cgmessage3(t : longint;const s1,s2,s3 : string);
  114. procedure CGMessagePos(const pos:tfileposinfo;t:longint);
  115. procedure CGMessagePos1(const pos:tfileposinfo;t:longint;const s1:string);
  116. procedure CGMessagePos2(const pos:tfileposinfo;t:longint;const s1,s2:string);
  117. procedure CGMessagePos3(const pos:tfileposinfo;t:longint;const s1,s2,s3:string);
  118. { initialize respectively terminates the code generator }
  119. { for a new module or procedure }
  120. procedure codegen_doneprocedure;
  121. procedure codegen_donemodule;
  122. procedure codegen_newmodule;
  123. procedure codegen_newprocedure;
  124. {# From a definition return the abstract code generator size (@var(tcgsize) enum). It is
  125. to note that the value returned can be @var(OS_NO) }
  126. function def_cgsize(def: tdef): tcgsize;
  127. function int_cgsize(const l: aword): tcgsize;
  128. {# return the inverse condition of opcmp }
  129. function inverse_opcmp(opcmp: topcmp): topcmp;
  130. {# return whether op is commutative }
  131. function commutativeop(op: topcg): boolean;
  132. implementation
  133. uses
  134. systems,
  135. cresstr,
  136. types
  137. {$ifdef fixLeaksOnError}
  138. ,comphook
  139. {$endif fixLeaksOnError}
  140. ;
  141. {$ifdef fixLeaksOnError}
  142. var procinfoStack: TStack;
  143. hcodegen_old_do_stop: tstopprocedure;
  144. {$endif fixLeaksOnError}
  145. {*****************************************************************************
  146. override the message calls to set codegenerror
  147. *****************************************************************************}
  148. procedure cgmessage(t : longint);
  149. var
  150. olderrorcount : longint;
  151. begin
  152. if not(codegenerror) then
  153. begin
  154. olderrorcount:=Errorcount;
  155. verbose.Message(t);
  156. codegenerror:=olderrorcount<>Errorcount;
  157. end;
  158. end;
  159. procedure cgmessage1(t : longint;const s : string);
  160. var
  161. olderrorcount : longint;
  162. begin
  163. if not(codegenerror) then
  164. begin
  165. olderrorcount:=Errorcount;
  166. verbose.Message1(t,s);
  167. codegenerror:=olderrorcount<>Errorcount;
  168. end;
  169. end;
  170. procedure cgmessage2(t : longint;const s1,s2 : string);
  171. var
  172. olderrorcount : longint;
  173. begin
  174. if not(codegenerror) then
  175. begin
  176. olderrorcount:=Errorcount;
  177. verbose.Message2(t,s1,s2);
  178. codegenerror:=olderrorcount<>Errorcount;
  179. end;
  180. end;
  181. procedure cgmessage3(t : longint;const s1,s2,s3 : string);
  182. var
  183. olderrorcount : longint;
  184. begin
  185. if not(codegenerror) then
  186. begin
  187. olderrorcount:=Errorcount;
  188. verbose.Message3(t,s1,s2,s3);
  189. codegenerror:=olderrorcount<>Errorcount;
  190. end;
  191. end;
  192. procedure cgmessagepos(const pos:tfileposinfo;t : longint);
  193. var
  194. olderrorcount : longint;
  195. begin
  196. if not(codegenerror) then
  197. begin
  198. olderrorcount:=Errorcount;
  199. verbose.MessagePos(pos,t);
  200. codegenerror:=olderrorcount<>Errorcount;
  201. end;
  202. end;
  203. procedure cgmessagepos1(const pos:tfileposinfo;t : longint;const s1 : string);
  204. var
  205. olderrorcount : longint;
  206. begin
  207. if not(codegenerror) then
  208. begin
  209. olderrorcount:=Errorcount;
  210. verbose.MessagePos1(pos,t,s1);
  211. codegenerror:=olderrorcount<>Errorcount;
  212. end;
  213. end;
  214. procedure cgmessagepos2(const pos:tfileposinfo;t : longint;const s1,s2 : string);
  215. var
  216. olderrorcount : longint;
  217. begin
  218. if not(codegenerror) then
  219. begin
  220. olderrorcount:=Errorcount;
  221. verbose.MessagePos2(pos,t,s1,s2);
  222. codegenerror:=olderrorcount<>Errorcount;
  223. end;
  224. end;
  225. procedure cgmessagepos3(const pos:tfileposinfo;t : longint;const s1,s2,s3 : string);
  226. var
  227. olderrorcount : longint;
  228. begin
  229. if not(codegenerror) then
  230. begin
  231. olderrorcount:=Errorcount;
  232. verbose.MessagePos3(pos,t,s1,s2,s3);
  233. codegenerror:=olderrorcount<>Errorcount;
  234. end;
  235. end;
  236. {****************************************************************************
  237. TProcInfo
  238. ****************************************************************************}
  239. constructor tprocinfo.init;
  240. begin
  241. parent:=nil;
  242. _class:=nil;
  243. procdef:=nil;
  244. framepointer_offset:=0;
  245. selfpointer_offset:=0;
  246. return_offset:=0;
  247. firsttemp_offset:=0;
  248. para_offset:=0;
  249. flags:=0;
  250. framepointer:=R_NO;
  251. globalsymbol:=false;
  252. exported:=false;
  253. no_fast_exit:=false;
  254. aktentrycode:=Taasmoutput.Create;
  255. aktexitcode:=Taasmoutput.Create;
  256. aktproccode:=Taasmoutput.Create;
  257. aktlocaldata:=Taasmoutput.Create;
  258. end;
  259. destructor tprocinfo.done;
  260. begin
  261. aktentrycode.free;
  262. aktexitcode.free;
  263. aktproccode.free;
  264. aktlocaldata.free;
  265. end;
  266. {*****************************************************************************
  267. initialize/terminate the codegen for procedure and modules
  268. *****************************************************************************}
  269. procedure codegen_newprocedure;
  270. begin
  271. aktbreaklabel:=nil;
  272. aktcontinuelabel:=nil;
  273. { aktexitlabel:=0; is store in oldaktexitlabel
  274. so it must not be reset to zero before this storage !}
  275. { new procinfo }
  276. new(procinfo,init);
  277. {$ifdef fixLeaksOnError}
  278. procinfoStack.push(procinfo);
  279. {$endif fixLeaksOnError}
  280. end;
  281. procedure codegen_doneprocedure;
  282. begin
  283. {$ifdef fixLeaksOnError}
  284. if procinfo <> procinfoStack.pop then
  285. writeln('problem with procinfoStack!');
  286. {$endif fixLeaksOnError}
  287. dispose(procinfo,done);
  288. procinfo:=nil;
  289. end;
  290. procedure codegen_newmodule;
  291. begin
  292. exprasmlist:=taasmoutput.create;
  293. datasegment:=taasmoutput.create;
  294. codesegment:=taasmoutput.create;
  295. bsssegment:=taasmoutput.create;
  296. debuglist:=taasmoutput.create;
  297. withdebuglist:=taasmoutput.create;
  298. consts:=taasmoutput.create;
  299. rttilist:=taasmoutput.create;
  300. ResourceStringList:=Nil;
  301. importssection:=nil;
  302. exportssection:=nil;
  303. resourcesection:=nil;
  304. { assembler symbols }
  305. asmsymbollist:=tdictionary.create;
  306. asmsymbollist.usehash;
  307. { resourcestrings }
  308. ResourceStrings:=TResourceStrings.Create;
  309. end;
  310. procedure codegen_donemodule;
  311. {$ifdef MEMDEBUG}
  312. var
  313. d : tmemdebug;
  314. {$endif}
  315. begin
  316. {$ifdef MEMDEBUG}
  317. d:=tmemdebug.create('asmlist');
  318. {$endif}
  319. exprasmlist.free;
  320. codesegment.free;
  321. bsssegment.free;
  322. datasegment.free;
  323. debuglist.free;
  324. withdebuglist.free;
  325. consts.free;
  326. rttilist.free;
  327. if assigned(ResourceStringList) then
  328. ResourceStringList.free;
  329. if assigned(importssection) then
  330. importssection.free;
  331. if assigned(exportssection) then
  332. exportssection.free;
  333. if assigned(resourcesection) then
  334. resourcesection.free;
  335. {$ifdef MEMDEBUG}
  336. d.free;
  337. {$endif}
  338. { assembler symbols }
  339. {$ifdef MEMDEBUG}
  340. d:=tmemdebug.create('asmsymbol');
  341. {$endif}
  342. asmsymbollist.free;
  343. {$ifdef MEMDEBUG}
  344. d.free;
  345. {$endif}
  346. { resource strings }
  347. ResourceStrings.free;
  348. end;
  349. function def_cgsize(def: tdef): tcgsize;
  350. begin
  351. case def.deftype of
  352. orddef,
  353. enumdef,
  354. setdef:
  355. begin
  356. result := int_cgsize(def.size);
  357. if is_signed(def) then
  358. result := tcgsize(ord(result)+(ord(OS_S8)-ord(OS_8)));
  359. end;
  360. classrefdef,
  361. pointerdef,
  362. procvardef:
  363. result := OS_ADDR;
  364. stringdef :
  365. begin
  366. if is_ansistring(def) or is_widestring(def) then
  367. result := OS_ADDR
  368. else
  369. result := OS_NO;
  370. end;
  371. objectdef :
  372. begin
  373. if is_class_or_interface(def) then
  374. result := OS_ADDR
  375. else
  376. result := OS_NO;
  377. end;
  378. floatdef:
  379. result := tfloat2tcgsize[tfloatdef(def).typ];
  380. recorddef :
  381. result:=int_cgsize(def.size);
  382. arraydef :
  383. begin
  384. if not is_special_array(def) then
  385. result := int_cgsize(def.size)
  386. else
  387. result := OS_NO;
  388. end;
  389. else
  390. begin
  391. { undefined size }
  392. result:=OS_NO;
  393. end;
  394. end;
  395. end;
  396. function int_cgsize(const l: aword): tcgsize;
  397. begin
  398. case l of
  399. 1 :
  400. result := OS_8;
  401. 2 :
  402. result := OS_16;
  403. 3,4 :
  404. result := OS_32;
  405. 5..8 :
  406. result := OS_64;
  407. else
  408. result:=OS_NO;
  409. end;
  410. end;
  411. function inverse_opcmp(opcmp: topcmp): topcmp;
  412. const
  413. list: array[TOpCmp] of TOpCmp =
  414. (OC_NONE,OC_NE,OC_LTE,OC_GTE,OC_LT,OC_GT,OC_EQ,OC_A,OC_AE,
  415. OC_B,OC_BE);
  416. begin
  417. inverse_opcmp := list[opcmp];
  418. end;
  419. function commutativeop(op: topcg): boolean;
  420. const
  421. list: array[topcg] of boolean =
  422. (true,true,true,false,false,true,true,false,false,
  423. true,false,false,false,false,true);
  424. begin
  425. commutativeop := list[op];
  426. end;
  427. {$ifdef fixLeaksOnError}
  428. procedure hcodegen_do_stop;
  429. var p: pprocinfo;
  430. begin
  431. p := pprocinfo(procinfoStack.pop);
  432. while p <> nil Do
  433. begin
  434. dispose(p,done);
  435. p := pprocinfo(procinfoStack.pop);
  436. end;
  437. procinfoStack.done;
  438. do_stop := hcodegen_old_do_stop;
  439. do_stop{$ifdef FPCPROCVAR}(){$endif};
  440. end;
  441. begin
  442. hcodegen_old_do_stop := do_stop;
  443. do_stop := {$ifdef FPCPROCVAR}@{$endif}hcodegen_do_stop;
  444. procinfoStack.init;
  445. {$endif fixLeaksOnError}
  446. end.
  447. {
  448. $Log$
  449. Revision 1.13 2002-04-25 20:16:38 peter
  450. * moved more routines from cga/n386util
  451. Revision 1.12 2002/04/21 15:28:06 carl
  452. - remove duplicate constants
  453. - move some constants to cginfo
  454. Revision 1.11 2002/04/20 21:32:23 carl
  455. + generic FPC_CHECKPOINTER
  456. + first parameter offset in stack now portable
  457. * rename some constants
  458. + move some cpu stuff to other units
  459. - remove unused constents
  460. * fix stacksize for some targets
  461. * fix generic size problems which depend now on EXTEND_SIZE constant
  462. Revision 1.10 2002/04/07 09:13:39 carl
  463. + documentation
  464. - remove unused variables
  465. Revision 1.9 2002/04/04 19:05:54 peter
  466. * removed unused units
  467. * use tlocation.size in cg.a_*loc*() routines
  468. Revision 1.8 2002/04/02 17:11:27 peter
  469. * tlocation,treference update
  470. * LOC_CONSTANT added for better constant handling
  471. * secondadd splitted in multiple routines
  472. * location_force_reg added for loading a location to a register
  473. of a specified size
  474. * secondassignment parses now first the right and then the left node
  475. (this is compatible with Kylix). This saves a lot of push/pop especially
  476. with string operations
  477. * adapted some routines to use the new cg methods
  478. Revision 1.7 2002/03/31 20:26:33 jonas
  479. + a_loadfpu_* and a_loadmm_* methods in tcg
  480. * register allocation is now handled by a class and is mostly processor
  481. independent (+rgobj.pas and i386/rgcpu.pas)
  482. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  483. * some small improvements and fixes to the optimizer
  484. * some register allocation fixes
  485. * some fpuvaroffset fixes in the unary minus node
  486. * push/popusedregisters is now called rg.save/restoreusedregisters and
  487. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  488. also better optimizable)
  489. * fixed and optimized register saving/restoring for new/dispose nodes
  490. * LOC_FPU locations now also require their "register" field to be set to
  491. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  492. - list field removed of the tnode class because it's not used currently
  493. and can cause hard-to-find bugs
  494. Revision 1.6 2002/03/04 19:10:11 peter
  495. * removed compiler warnings
  496. Revision 1.5 2001/12/30 17:24:48 jonas
  497. * range checking is now processor independent (part in cgobj,
  498. part in cg64f32) and should work correctly again (it needed
  499. some changes after the changes of the low and high of
  500. tordef's to int64)
  501. * maketojumpbool() is now processor independent (in ncgutil)
  502. * getregister32 is now called getregisterint
  503. Revision 1.4 2001/11/06 14:53:48 jonas
  504. * compiles again with -dmemdebug
  505. Revision 1.3 2001/09/29 21:33:47 jonas
  506. * support 64bit operands in def_cgsize()
  507. Revision 1.2 2001/09/28 20:39:33 jonas
  508. * changed all flow control structures (except for exception handling
  509. related things) to processor independent code (in new ncgflw unit)
  510. + generic cgobj unit which contains lots of code generator helpers with
  511. global "cg" class instance variable
  512. + cgcpu unit for i386 (implements processor specific routines of the above
  513. unit)
  514. * updated cgbase and cpubase for the new code generator units
  515. * include ncgflw unit in cpunode unit
  516. Revision 1.1 2001/08/26 13:36:36 florian
  517. * some cg reorganisation
  518. * some PPC updates
  519. Revision 1.11 2001/08/06 21:40:46 peter
  520. * funcret moved from tprocinfo to tprocdef
  521. Revision 1.10 2001/04/13 01:22:07 peter
  522. * symtable change to classes
  523. * range check generation and errors fixed, make cycle DEBUG=1 works
  524. * memory leaks fixed
  525. Revision 1.9 2000/12/25 00:07:26 peter
  526. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  527. tlinkedlist objects)
  528. Revision 1.8 2000/11/30 22:16:49 florian
  529. * moved to i386
  530. Revision 1.7 2000/10/31 22:02:47 peter
  531. * symtable splitted, no real code changes
  532. Revision 1.6 2000/09/24 15:06:17 peter
  533. * use defines.inc
  534. Revision 1.5 2000/08/27 16:11:51 peter
  535. * moved some util functions from globals,cobjects to cutils
  536. * splitted files into finput,fmodule
  537. Revision 1.4 2000/08/12 15:34:22 peter
  538. + usedasmsymbollist to check and reset only the used symbols (merged)
  539. Revision 1.3 2000/08/03 13:17:26 jonas
  540. + allow regvars to be used inside inlined procs, which required the
  541. following changes:
  542. + load regvars in genentrycode/free them in genexitcode (cgai386)
  543. * moved all regvar related code to new regvars unit
  544. + added pregvarinfo type to hcodegen
  545. + added regvarinfo field to tprocinfo (symdef/symdefh)
  546. * deallocate the regvars of the caller in secondprocinline before
  547. inlining the called procedure and reallocate them afterwards
  548. Revision 1.2 2000/07/13 11:32:41 michael
  549. + removed logs
  550. }