cgbase.pas 19 KB

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