cgbase.pas 19 KB

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