cgbase.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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 fpcdefs.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.15 2002-05-16 19:46:35 carl
  450. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  451. + try to fix temp allocation (still in ifdef)
  452. + generic constructor calls
  453. + start of tassembler / tmodulebase class cleanup
  454. Revision 1.13 2002/04/25 20:16:38 peter
  455. * moved more routines from cga/n386util
  456. Revision 1.12 2002/04/21 15:28:06 carl
  457. - remove duplicate constants
  458. - move some constants to cginfo
  459. Revision 1.11 2002/04/20 21:32:23 carl
  460. + generic FPC_CHECKPOINTER
  461. + first parameter offset in stack now portable
  462. * rename some constants
  463. + move some cpu stuff to other units
  464. - remove unused constents
  465. * fix stacksize for some targets
  466. * fix generic size problems which depend now on EXTEND_SIZE constant
  467. Revision 1.10 2002/04/07 09:13:39 carl
  468. + documentation
  469. - remove unused variables
  470. Revision 1.9 2002/04/04 19:05:54 peter
  471. * removed unused units
  472. * use tlocation.size in cg.a_*loc*() routines
  473. Revision 1.8 2002/04/02 17:11:27 peter
  474. * tlocation,treference update
  475. * LOC_CONSTANT added for better constant handling
  476. * secondadd splitted in multiple routines
  477. * location_force_reg added for loading a location to a register
  478. of a specified size
  479. * secondassignment parses now first the right and then the left node
  480. (this is compatible with Kylix). This saves a lot of push/pop especially
  481. with string operations
  482. * adapted some routines to use the new cg methods
  483. Revision 1.7 2002/03/31 20:26:33 jonas
  484. + a_loadfpu_* and a_loadmm_* methods in tcg
  485. * register allocation is now handled by a class and is mostly processor
  486. independent (+rgobj.pas and i386/rgcpu.pas)
  487. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  488. * some small improvements and fixes to the optimizer
  489. * some register allocation fixes
  490. * some fpuvaroffset fixes in the unary minus node
  491. * push/popusedregisters is now called rg.save/restoreusedregisters and
  492. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  493. also better optimizable)
  494. * fixed and optimized register saving/restoring for new/dispose nodes
  495. * LOC_FPU locations now also require their "register" field to be set to
  496. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  497. - list field removed of the tnode class because it's not used currently
  498. and can cause hard-to-find bugs
  499. Revision 1.6 2002/03/04 19:10:11 peter
  500. * removed compiler warnings
  501. Revision 1.5 2001/12/30 17:24:48 jonas
  502. * range checking is now processor independent (part in cgobj,
  503. part in cg64f32) and should work correctly again (it needed
  504. some changes after the changes of the low and high of
  505. tordef's to int64)
  506. * maketojumpbool() is now processor independent (in ncgutil)
  507. * getregister32 is now called getregisterint
  508. Revision 1.4 2001/11/06 14:53:48 jonas
  509. * compiles again with -dmemdebug
  510. Revision 1.3 2001/09/29 21:33:47 jonas
  511. * support 64bit operands in def_cgsize()
  512. Revision 1.2 2001/09/28 20:39:33 jonas
  513. * changed all flow control structures (except for exception handling
  514. related things) to processor independent code (in new ncgflw unit)
  515. + generic cgobj unit which contains lots of code generator helpers with
  516. global "cg" class instance variable
  517. + cgcpu unit for i386 (implements processor specific routines of the above
  518. unit)
  519. * updated cgbase and cpubase for the new code generator units
  520. * include ncgflw unit in cpunode unit
  521. Revision 1.1 2001/08/26 13:36:36 florian
  522. * some cg reorganisation
  523. * some PPC updates
  524. Revision 1.11 2001/08/06 21:40:46 peter
  525. * funcret moved from tprocinfo to tprocdef
  526. Revision 1.10 2001/04/13 01:22:07 peter
  527. * symtable change to classes
  528. * range check generation and errors fixed, make cycle DEBUG=1 works
  529. * memory leaks fixed
  530. Revision 1.9 2000/12/25 00:07:26 peter
  531. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  532. tlinkedlist objects)
  533. Revision 1.8 2000/11/30 22:16:49 florian
  534. * moved to i386
  535. Revision 1.7 2000/10/31 22:02:47 peter
  536. * symtable splitted, no real code changes
  537. Revision 1.6 2000/09/24 15:06:17 peter
  538. * use defines.inc
  539. Revision 1.5 2000/08/27 16:11:51 peter
  540. * moved some util functions from globals,cobjects to cutils
  541. * splitted files into finput,fmodule
  542. Revision 1.4 2000/08/12 15:34:22 peter
  543. + usedasmsymbollist to check and reset only the used symbols (merged)
  544. Revision 1.3 2000/08/03 13:17:26 jonas
  545. + allow regvars to be used inside inlined procs, which required the
  546. following changes:
  547. + load regvars in genentrycode/free them in genexitcode (cgai386)
  548. * moved all regvar related code to new regvars unit
  549. + added pregvarinfo type to hcodegen
  550. + added regvarinfo field to tprocinfo (symdef/symdefh)
  551. * deallocate the regvars of the caller in secondprocinline before
  552. inlining the called procedure and reallocate them afterwards
  553. Revision 1.2 2000/07/13 11:32:41 michael
  554. + removed logs
  555. }