cgbase.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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. {# Some helpers for the code generator.
  19. }
  20. unit cgbase;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. { common }
  25. cclasses,
  26. { global }
  27. globals,verbose,
  28. { symtable }
  29. symconst,symtype,symdef,symsym,
  30. { aasm }
  31. cpubase,cpuinfo,cginfo,aasmbase,aasmtai
  32. ;
  33. const
  34. {# bitmask indicating if the procedure uses asm }
  35. pi_uses_asm = $1;
  36. {# bitmask indicating if the procedure is exported by an unit }
  37. pi_is_global = $2;
  38. {# bitmask indicating if the procedure does a call }
  39. pi_do_call = $4;
  40. {# bitmask indicating if the procedure is an operator }
  41. pi_operator = $8;
  42. {# bitmask indicating if the procedure is an external C function }
  43. pi_c_import = $10;
  44. {# bitmask indicating if the procedure has a try statement = no register optimization }
  45. pi_uses_exceptions = $20;
  46. {# bitmask indicating if the procedure is declared as @var(assembler), don't optimize}
  47. pi_is_assembler = $40;
  48. {# bitmask indicating if the procedure contains data which needs to be finalized }
  49. pi_needs_implicit_finally = $80;
  50. type
  51. {# This object gives information on the current routine being
  52. compiled.
  53. }
  54. pprocinfo = ^tprocinfo;
  55. tprocinfo = object
  56. {# pointer to parent in nested procedures }
  57. parent : pprocinfo;
  58. {# current class, if we are in a method }
  59. _class : tobjectdef;
  60. {# the definition of the routine itself }
  61. procdef : tprocdef;
  62. {# offset from frame pointer to get parent frame pointer reference
  63. (used in nested routines only)
  64. }
  65. framepointer_offset : longint;
  66. {# offset from frame pointer to get self reference }
  67. selfpointer_offset : longint;
  68. {# result value offset in stack (functions only) }
  69. return_offset : longint;
  70. {# firsttemp position }
  71. firsttemp_offset : longint;
  72. {# offset from frame pointer to parameters }
  73. para_offset : longint;
  74. {# some collected informations about the procedure
  75. see pi_xxxx constants above
  76. }
  77. flags : longint;
  78. {# register used as frame pointer }
  79. framepointer : tregister;
  80. {# true, if the procedure is exported by a unit }
  81. globalsymbol : boolean;
  82. {# true, if the procedure should be exported (only OS/2) }
  83. exported : boolean;
  84. {# true, if we can not use fast exit code }
  85. no_fast_exit : boolean;
  86. {# Holds the environment reference for default exceptions
  87. The exception reference is created when ansistrings
  88. or classes are used. It holds buffer for exception
  89. frames. It is allocted by g_new_exception.
  90. }
  91. exception_env_ref : treference;
  92. {# Holds the environment reference for default exceptions
  93. The exception reference is created when ansistrings
  94. or classes are used. It holds buffer for setjmp
  95. It is allocted by g_new_exception.
  96. }
  97. exception_jmp_ref :treference;
  98. {# Holds the environment reference for default exceptions
  99. The exception reference is created when ansistrings
  100. or classes are used. It holds the location where
  101. temporary storage of the setjmp result is stored.
  102. This reference can be unused, if the result is instead
  103. saved on the stack.
  104. }
  105. exception_result_ref :treference;
  106. { overall size of allocated stack space, currently this is used for the PowerPC only }
  107. localsize : aword;
  108. { max. of space need for parameters, currently used by the PowerPC port only }
  109. maxpushedparasize : aword;
  110. {# Holds the reference used to store alll saved registers.
  111. This is used on systems which do not have direct stack
  112. operations (such as the PowerPC), it is unused on other
  113. systems
  114. }
  115. save_regs_ref : treference;
  116. {# The code for the routine itself, excluding entry and
  117. exit code. This is a linked list of tai classes.
  118. }
  119. aktproccode : taasmoutput;
  120. {# The code for the routine entry code.
  121. }
  122. aktentrycode: taasmoutput;
  123. {# The code for the routine exit code.
  124. }
  125. aktexitcode: taasmoutput;
  126. aktlocaldata : taasmoutput;
  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. {# information about the current sub routine being parsed (@var(pprocinfo))}
  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 keyword or if getmem fails }
  151. faillabel : tasmlabel;
  152. quickexitlabel : tasmlabel;
  153. {# true, if there was an error while code generation occurs }
  154. codegenerror : boolean;
  155. { save the size of pushed parameter, needed for aligning }
  156. pushedparasize : longint;
  157. { message calls with codegenerror support }
  158. procedure cgmessage(t : longint);
  159. procedure cgmessage1(t : longint;const s : string);
  160. procedure cgmessage2(t : longint;const s1,s2 : string);
  161. procedure cgmessage3(t : longint;const s1,s2,s3 : string);
  162. procedure CGMessagePos(const pos:tfileposinfo;t:longint);
  163. procedure CGMessagePos1(const pos:tfileposinfo;t:longint;const s1:string);
  164. procedure CGMessagePos2(const pos:tfileposinfo;t:longint;const s1,s2:string);
  165. procedure CGMessagePos3(const pos:tfileposinfo;t:longint;const s1,s2,s3:string);
  166. { initialize respectively terminates the code generator }
  167. { for a new module or procedure }
  168. procedure codegen_doneprocedure;
  169. procedure codegen_donemodule;
  170. procedure codegen_newmodule;
  171. procedure codegen_newprocedure;
  172. {# From a definition return the abstract code generator size enum. It is
  173. to note that the value returned can be @var(OS_NO) }
  174. function def_cgsize(def: tdef): tcgsize;
  175. {# From a constant numeric value, return the abstract code generator
  176. size.
  177. }
  178. function int_cgsize(const l: aword): tcgsize;
  179. {# return the inverse condition of opcmp }
  180. function inverse_opcmp(opcmp: topcmp): topcmp;
  181. {# return whether op is commutative }
  182. function commutativeop(op: topcg): boolean;
  183. implementation
  184. uses
  185. systems,
  186. cresstr,
  187. rgobj,
  188. defbase,
  189. fmodule
  190. {$ifdef fixLeaksOnError}
  191. ,comphook
  192. {$endif fixLeaksOnError}
  193. ;
  194. {$ifdef fixLeaksOnError}
  195. var procinfoStack: TStack;
  196. hcodegen_old_do_stop: tstopprocedure;
  197. {$endif fixLeaksOnError}
  198. {*****************************************************************************
  199. override the message calls to set codegenerror
  200. *****************************************************************************}
  201. procedure cgmessage(t : longint);
  202. var
  203. olderrorcount : longint;
  204. begin
  205. if not(codegenerror) then
  206. begin
  207. olderrorcount:=Errorcount;
  208. verbose.Message(t);
  209. codegenerror:=olderrorcount<>Errorcount;
  210. end;
  211. end;
  212. procedure cgmessage1(t : longint;const s : string);
  213. var
  214. olderrorcount : longint;
  215. begin
  216. if not(codegenerror) then
  217. begin
  218. olderrorcount:=Errorcount;
  219. verbose.Message1(t,s);
  220. codegenerror:=olderrorcount<>Errorcount;
  221. end;
  222. end;
  223. procedure cgmessage2(t : longint;const s1,s2 : string);
  224. var
  225. olderrorcount : longint;
  226. begin
  227. if not(codegenerror) then
  228. begin
  229. olderrorcount:=Errorcount;
  230. verbose.Message2(t,s1,s2);
  231. codegenerror:=olderrorcount<>Errorcount;
  232. end;
  233. end;
  234. procedure cgmessage3(t : longint;const s1,s2,s3 : string);
  235. var
  236. olderrorcount : longint;
  237. begin
  238. if not(codegenerror) then
  239. begin
  240. olderrorcount:=Errorcount;
  241. verbose.Message3(t,s1,s2,s3);
  242. codegenerror:=olderrorcount<>Errorcount;
  243. end;
  244. end;
  245. procedure cgmessagepos(const pos:tfileposinfo;t : longint);
  246. var
  247. olderrorcount : longint;
  248. begin
  249. if not(codegenerror) then
  250. begin
  251. olderrorcount:=Errorcount;
  252. verbose.MessagePos(pos,t);
  253. codegenerror:=olderrorcount<>Errorcount;
  254. end;
  255. end;
  256. procedure cgmessagepos1(const pos:tfileposinfo;t : longint;const s1 : string);
  257. var
  258. olderrorcount : longint;
  259. begin
  260. if not(codegenerror) then
  261. begin
  262. olderrorcount:=Errorcount;
  263. verbose.MessagePos1(pos,t,s1);
  264. codegenerror:=olderrorcount<>Errorcount;
  265. end;
  266. end;
  267. procedure cgmessagepos2(const pos:tfileposinfo;t : longint;const s1,s2 : string);
  268. var
  269. olderrorcount : longint;
  270. begin
  271. if not(codegenerror) then
  272. begin
  273. olderrorcount:=Errorcount;
  274. verbose.MessagePos2(pos,t,s1,s2);
  275. codegenerror:=olderrorcount<>Errorcount;
  276. end;
  277. end;
  278. procedure cgmessagepos3(const pos:tfileposinfo;t : longint;const s1,s2,s3 : string);
  279. var
  280. olderrorcount : longint;
  281. begin
  282. if not(codegenerror) then
  283. begin
  284. olderrorcount:=Errorcount;
  285. verbose.MessagePos3(pos,t,s1,s2,s3);
  286. codegenerror:=olderrorcount<>Errorcount;
  287. end;
  288. end;
  289. {****************************************************************************
  290. TProcInfo
  291. ****************************************************************************}
  292. constructor tprocinfo.init;
  293. begin
  294. parent:=nil;
  295. _class:=nil;
  296. procdef:=nil;
  297. framepointer_offset:=0;
  298. selfpointer_offset:=0;
  299. return_offset:=0;
  300. firsttemp_offset:=0;
  301. para_offset:=0;
  302. flags:=0;
  303. framepointer:=R_NO;
  304. globalsymbol:=false;
  305. exported:=false;
  306. no_fast_exit:=false;
  307. maxpushedparasize:=0;
  308. localsize:=0;
  309. aktentrycode:=Taasmoutput.Create;
  310. aktexitcode:=Taasmoutput.Create;
  311. aktproccode:=Taasmoutput.Create;
  312. aktlocaldata:=Taasmoutput.Create;
  313. reference_reset(exception_env_ref);
  314. reference_reset(exception_jmp_ref);
  315. reference_reset(exception_result_ref);
  316. end;
  317. destructor tprocinfo.done;
  318. begin
  319. aktentrycode.free;
  320. aktexitcode.free;
  321. aktproccode.free;
  322. aktlocaldata.free;
  323. end;
  324. {*****************************************************************************
  325. initialize/terminate the codegen for procedure and modules
  326. *****************************************************************************}
  327. procedure codegen_newprocedure;
  328. begin
  329. aktbreaklabel:=nil;
  330. aktcontinuelabel:=nil;
  331. { aktexitlabel:=0; is store in oldaktexitlabel
  332. so it must not be reset to zero before this storage !}
  333. { new procinfo }
  334. new(procinfo,init);
  335. {$ifdef fixLeaksOnError}
  336. procinfoStack.push(procinfo);
  337. {$endif fixLeaksOnError}
  338. end;
  339. procedure codegen_doneprocedure;
  340. begin
  341. {$ifdef fixLeaksOnError}
  342. if procinfo <> procinfoStack.pop then
  343. writeln('problem with procinfoStack!');
  344. {$endif fixLeaksOnError}
  345. dispose(procinfo,done);
  346. procinfo:=nil;
  347. end;
  348. procedure codegen_newmodule;
  349. begin
  350. exprasmlist:=taasmoutput.create;
  351. datasegment:=taasmoutput.create;
  352. codesegment:=taasmoutput.create;
  353. bsssegment:=taasmoutput.create;
  354. debuglist:=taasmoutput.create;
  355. withdebuglist:=taasmoutput.create;
  356. consts:=taasmoutput.create;
  357. rttilist:=taasmoutput.create;
  358. ResourceStringList:=Nil;
  359. importssection:=nil;
  360. exportssection:=nil;
  361. resourcesection:=nil;
  362. { resourcestrings }
  363. ResourceStrings:=TResourceStrings.Create;
  364. { use the librarydata from current_module }
  365. objectlibrary:=current_module.librarydata;
  366. end;
  367. procedure codegen_donemodule;
  368. {$ifdef MEMDEBUG}
  369. var
  370. d : tmemdebug;
  371. {$endif}
  372. begin
  373. {$ifdef MEMDEBUG}
  374. d:=tmemdebug.create('asmlist');
  375. {$endif}
  376. exprasmlist.free;
  377. codesegment.free;
  378. bsssegment.free;
  379. datasegment.free;
  380. debuglist.free;
  381. withdebuglist.free;
  382. consts.free;
  383. rttilist.free;
  384. if assigned(ResourceStringList) then
  385. ResourceStringList.free;
  386. if assigned(importssection) then
  387. importssection.free;
  388. if assigned(exportssection) then
  389. exportssection.free;
  390. if assigned(resourcesection) then
  391. resourcesection.free;
  392. {$ifdef MEMDEBUG}
  393. d.free;
  394. {$endif}
  395. { resource strings }
  396. ResourceStrings.free;
  397. objectlibrary:=nil;
  398. end;
  399. function def_cgsize(def: tdef): tcgsize;
  400. begin
  401. case def.deftype of
  402. orddef,
  403. enumdef,
  404. setdef:
  405. begin
  406. result := int_cgsize(def.size);
  407. if is_signed(def) then
  408. result := tcgsize(ord(result)+(ord(OS_S8)-ord(OS_8)));
  409. end;
  410. classrefdef,
  411. pointerdef,
  412. procvardef:
  413. result := OS_ADDR;
  414. stringdef :
  415. begin
  416. if is_ansistring(def) or is_widestring(def) then
  417. result := OS_ADDR
  418. else
  419. result := OS_NO;
  420. end;
  421. objectdef :
  422. begin
  423. if is_class_or_interface(def) then
  424. result := OS_ADDR
  425. else
  426. result := OS_NO;
  427. end;
  428. floatdef:
  429. result := tfloat2tcgsize[tfloatdef(def).typ];
  430. recorddef :
  431. result:=int_cgsize(def.size);
  432. arraydef :
  433. begin
  434. if not is_special_array(def) then
  435. result := int_cgsize(def.size)
  436. else
  437. result := OS_NO;
  438. end;
  439. else
  440. begin
  441. { undefined size }
  442. result:=OS_NO;
  443. end;
  444. end;
  445. end;
  446. function int_cgsize(const l: aword): tcgsize;
  447. begin
  448. case l of
  449. 1 :
  450. result := OS_8;
  451. 2 :
  452. result := OS_16;
  453. 3,4 :
  454. result := OS_32;
  455. 5..8 :
  456. result := OS_64;
  457. else
  458. result:=OS_NO;
  459. end;
  460. end;
  461. function inverse_opcmp(opcmp: topcmp): topcmp;
  462. const
  463. list: array[TOpCmp] of TOpCmp =
  464. (OC_NONE,OC_NE,OC_LTE,OC_GTE,OC_LT,OC_GT,OC_EQ,OC_A,OC_AE,
  465. OC_B,OC_BE);
  466. begin
  467. inverse_opcmp := list[opcmp];
  468. end;
  469. function commutativeop(op: topcg): boolean;
  470. const
  471. list: array[topcg] of boolean =
  472. (true,true,true,false,false,true,true,false,false,
  473. true,false,false,false,false,true);
  474. begin
  475. commutativeop := list[op];
  476. end;
  477. {$ifdef fixLeaksOnError}
  478. procedure hcodegen_do_stop;
  479. var p: pprocinfo;
  480. begin
  481. p := pprocinfo(procinfoStack.pop);
  482. while p <> nil Do
  483. begin
  484. dispose(p,done);
  485. p := pprocinfo(procinfoStack.pop);
  486. end;
  487. procinfoStack.done;
  488. do_stop := hcodegen_old_do_stop;
  489. do_stop{$ifdef FPCPROCVAR}(){$endif};
  490. end;
  491. begin
  492. hcodegen_old_do_stop := do_stop;
  493. do_stop := {$ifdef FPCPROCVAR}@{$endif}hcodegen_do_stop;
  494. procinfoStack.init;
  495. {$endif fixLeaksOnError}
  496. end.
  497. {
  498. $Log$
  499. Revision 1.24 2002-08-11 14:32:26 peter
  500. * renamed current_library to objectlibrary
  501. Revision 1.23 2002/08/11 13:24:11 peter
  502. * saving of asmsymbols in ppu supported
  503. * asmsymbollist global is removed and moved into a new class
  504. tasmlibrarydata that will hold the info of a .a file which
  505. corresponds with a single module. Added librarydata to tmodule
  506. to keep the library info stored for the module. In the future the
  507. objectfiles will also be stored to the tasmlibrarydata class
  508. * all getlabel/newasmsymbol and friends are moved to the new class
  509. Revision 1.22 2002/08/06 20:55:20 florian
  510. * first part of ppc calling conventions fix
  511. Revision 1.21 2002/08/05 18:27:48 carl
  512. + more more more documentation
  513. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  514. Revision 1.20 2002/08/04 19:06:41 carl
  515. + added generic exception support (still does not work!)
  516. + more documentation
  517. Revision 1.19 2002/07/20 11:57:53 florian
  518. * types.pas renamed to defbase.pas because D6 contains a types
  519. unit so this would conflicts if D6 programms are compiled
  520. + Willamette/SSE2 instructions to assembler added
  521. Revision 1.18 2002/07/01 18:46:22 peter
  522. * internal linker
  523. * reorganized aasm layer
  524. Revision 1.17 2002/05/20 13:30:40 carl
  525. * bugfix of hdisponen (base must be set, not index)
  526. * more portability fixes
  527. Revision 1.16 2002/05/18 13:34:05 peter
  528. * readded missing revisions
  529. Revision 1.15 2002/05/16 19:46:35 carl
  530. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  531. + try to fix temp allocation (still in ifdef)
  532. + generic constructor calls
  533. + start of tassembler / tmodulebase class cleanup
  534. Revision 1.13 2002/04/25 20:16:38 peter
  535. * moved more routines from cga/n386util
  536. Revision 1.12 2002/04/21 15:28:06 carl
  537. - remove duplicate constants
  538. - move some constants to cginfo
  539. Revision 1.11 2002/04/20 21:32:23 carl
  540. + generic FPC_CHECKPOINTER
  541. + first parameter offset in stack now portable
  542. * rename some constants
  543. + move some cpu stuff to other units
  544. - remove unused constents
  545. * fix stacksize for some targets
  546. * fix generic size problems which depend now on EXTEND_SIZE constant
  547. Revision 1.10 2002/04/07 09:13:39 carl
  548. + documentation
  549. - remove unused variables
  550. Revision 1.9 2002/04/04 19:05:54 peter
  551. * removed unused units
  552. * use tlocation.size in cg.a_*loc*() routines
  553. Revision 1.8 2002/04/02 17:11:27 peter
  554. * tlocation,treference update
  555. * LOC_CONSTANT added for better constant handling
  556. * secondadd splitted in multiple routines
  557. * location_force_reg added for loading a location to a register
  558. of a specified size
  559. * secondassignment parses now first the right and then the left node
  560. (this is compatible with Kylix). This saves a lot of push/pop especially
  561. with string operations
  562. * adapted some routines to use the new cg methods
  563. Revision 1.7 2002/03/31 20:26:33 jonas
  564. + a_loadfpu_* and a_loadmm_* methods in tcg
  565. * register allocation is now handled by a class and is mostly processor
  566. independent (+rgobj.pas and i386/rgcpu.pas)
  567. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  568. * some small improvements and fixes to the optimizer
  569. * some register allocation fixes
  570. * some fpuvaroffset fixes in the unary minus node
  571. * push/popusedregisters is now called rg.save/restoreusedregisters and
  572. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  573. also better optimizable)
  574. * fixed and optimized register saving/restoring for new/dispose nodes
  575. * LOC_FPU locations now also require their "register" field to be set to
  576. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  577. - list field removed of the tnode class because it's not used currently
  578. and can cause hard-to-find bugs
  579. Revision 1.6 2002/03/04 19:10:11 peter
  580. * removed compiler warnings
  581. }