cgbase.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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.6 2002-03-04 19:10:11 peter
  427. * removed compiler warnings
  428. Revision 1.5 2001/12/30 17:24:48 jonas
  429. * range checking is now processor independent (part in cgobj,
  430. part in cg64f32) and should work correctly again (it needed
  431. some changes after the changes of the low and high of
  432. tordef's to int64)
  433. * maketojumpbool() is now processor independent (in ncgutil)
  434. * getregister32 is now called getregisterint
  435. Revision 1.4 2001/11/06 14:53:48 jonas
  436. * compiles again with -dmemdebug
  437. Revision 1.3 2001/09/29 21:33:47 jonas
  438. * support 64bit operands in def_cgsize()
  439. Revision 1.2 2001/09/28 20:39:33 jonas
  440. * changed all flow control structures (except for exception handling
  441. related things) to processor independent code (in new ncgflw unit)
  442. + generic cgobj unit which contains lots of code generator helpers with
  443. global "cg" class instance variable
  444. + cgcpu unit for i386 (implements processor specific routines of the above
  445. unit)
  446. * updated cgbase and cpubase for the new code generator units
  447. * include ncgflw unit in cpunode unit
  448. Revision 1.1 2001/08/26 13:36:36 florian
  449. * some cg reorganisation
  450. * some PPC updates
  451. Revision 1.11 2001/08/06 21:40:46 peter
  452. * funcret moved from tprocinfo to tprocdef
  453. Revision 1.10 2001/04/13 01:22:07 peter
  454. * symtable change to classes
  455. * range check generation and errors fixed, make cycle DEBUG=1 works
  456. * memory leaks fixed
  457. Revision 1.9 2000/12/25 00:07:26 peter
  458. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  459. tlinkedlist objects)
  460. Revision 1.8 2000/11/30 22:16:49 florian
  461. * moved to i386
  462. Revision 1.7 2000/10/31 22:02:47 peter
  463. * symtable splitted, no real code changes
  464. Revision 1.6 2000/09/24 15:06:17 peter
  465. * use defines.inc
  466. Revision 1.5 2000/08/27 16:11:51 peter
  467. * moved some util functions from globals,cobjects to cutils
  468. * splitted files into finput,fmodule
  469. Revision 1.4 2000/08/12 15:34:22 peter
  470. + usedasmsymbollist to check and reset only the used symbols (merged)
  471. Revision 1.3 2000/08/03 13:17:26 jonas
  472. + allow regvars to be used inside inlined procs, which required the
  473. following changes:
  474. + load regvars in genentrycode/free them in genexitcode (cgai386)
  475. * moved all regvar related code to new regvars unit
  476. + added pregvarinfo type to hcodegen
  477. + added regvarinfo field to tprocinfo (symdef/symdefh)
  478. * deallocate the regvars of the caller in secondprocinline before
  479. inlining the called procedure and reallocate them afterwards
  480. Revision 1.2 2000/07/13 11:32:41 michael
  481. + removed logs
  482. }