cgbase.pas 17 KB

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