ncgbas.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. This unit implements some basic nodes
  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 ncgbas;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cpubase,
  23. node,nbas;
  24. type
  25. tcgnothingnode = class(tnothingnode)
  26. procedure pass_2;override;
  27. end;
  28. tcgasmnode = class(tasmnode)
  29. procedure pass_2;override;
  30. end;
  31. tcgstatementnode = class(tstatementnode)
  32. procedure pass_2;override;
  33. end;
  34. tcgblocknode = class(tblocknode)
  35. procedure pass_2;override;
  36. end;
  37. tcgtempcreatenode = class(ttempcreatenode)
  38. procedure pass_2;override;
  39. end;
  40. tcgtemprefnode = class(ttemprefnode)
  41. procedure pass_2;override;
  42. { Changes the location of this temp to ref. Useful when assigning }
  43. { another temp to this one. The current location will be freed. }
  44. { Can only be called in pass 2 (since earlier, the temp location }
  45. { isn't known yet) }
  46. procedure changelocation(const ref: treference);
  47. end;
  48. tcgtempdeletenode = class(ttempdeletenode)
  49. procedure pass_2;override;
  50. end;
  51. implementation
  52. uses
  53. globtype,systems,
  54. cutils,verbose,cpuinfo,
  55. aasmbase,aasmtai,aasmcpu,symsym,
  56. defutil,
  57. nflw,pass_2,
  58. cgbase,procinfo,cgobj,tgobj
  59. ;
  60. {*****************************************************************************
  61. TNOTHING
  62. *****************************************************************************}
  63. procedure tcgnothingnode.pass_2;
  64. begin
  65. location_reset(location,LOC_VOID,OS_NO);
  66. { avoid an abstract rte }
  67. end;
  68. {*****************************************************************************
  69. TSTATEMENTNODE
  70. *****************************************************************************}
  71. procedure tcgstatementnode.pass_2;
  72. var
  73. hp : tstatementnode;
  74. begin
  75. location_reset(location,LOC_VOID,OS_NO);
  76. hp:=self;
  77. while assigned(hp) do
  78. begin
  79. if assigned(hp.left) then
  80. begin
  81. secondpass(hp.left);
  82. { Compiler inserted blocks can return values }
  83. location_copy(hp.location,hp.left.location);
  84. end;
  85. hp:=tstatementnode(hp.right);
  86. end;
  87. end;
  88. {*****************************************************************************
  89. TASMNODE
  90. *****************************************************************************}
  91. procedure tcgasmnode.pass_2;
  92. procedure ReLabel(var p:tasmsymbol);
  93. begin
  94. { Only relabel local tasmlabels }
  95. if (p.defbind = AB_LOCAL) and
  96. (p is tasmlabel) then
  97. begin
  98. if not assigned(p.altsymbol) then
  99. objectlibrary.GenerateAltSymbol(p);
  100. p:=p.altsymbol;
  101. p.increfs;
  102. end;
  103. end;
  104. procedure ResolveRef(var op:toper);
  105. var
  106. sym : tvarsym;
  107. getoffset : boolean;
  108. indexreg : tregister;
  109. sofs : longint;
  110. begin
  111. if (op.typ=top_local) then
  112. begin
  113. sofs:=op.localsymofs;
  114. indexreg:=op.localindexreg;
  115. getoffset:=op.localgetoffset;
  116. sym:=tvarsym(pointer(op.localsym));
  117. case sym.localloc.loc of
  118. LOC_REFERENCE :
  119. begin
  120. if getoffset then
  121. begin
  122. if indexreg=NR_NO then
  123. begin
  124. op.typ:=top_const;
  125. op.val:=aword(sym.localloc.reference.offset+sofs);
  126. end
  127. else
  128. begin
  129. op.typ:=top_ref;
  130. new(op.ref);
  131. reference_reset_base(op.ref^,indexreg,
  132. sym.localloc.reference.offset+sofs);
  133. end;
  134. end
  135. else
  136. begin
  137. op.typ:=top_ref;
  138. new(op.ref);
  139. reference_reset_base(op.ref^,sym.localloc.reference.index,
  140. sym.localloc.reference.offset+sofs);
  141. op.ref^.index:=indexreg;
  142. end;
  143. end;
  144. LOC_REGISTER :
  145. begin
  146. if getoffset then
  147. Message(asmr_e_invalid_reference_syntax);
  148. { Subscribed access }
  149. if sofs<>0 then
  150. begin
  151. op.typ:=top_ref;
  152. new(op.ref);
  153. reference_reset_base(op.ref^,sym.localloc.register,sofs);
  154. end
  155. else
  156. begin
  157. op.typ:=top_reg;
  158. op.reg:=sym.localloc.register;
  159. end;
  160. end;
  161. end;
  162. end;
  163. end;
  164. var
  165. hp,hp2 : tai;
  166. i : longint;
  167. skipnode : boolean;
  168. begin
  169. location_reset(location,LOC_VOID,OS_NO);
  170. if getposition then
  171. begin
  172. { Add a marker, to be sure the list is not empty }
  173. exprasmlist.concat(tai_marker.create(marker_position));
  174. currenttai:=tai(exprasmlist.last);
  175. exit;
  176. end;
  177. { Allocate registers used in the assembler block }
  178. cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,used_regs_int);
  179. if (current_procinfo.procdef.proccalloption=pocall_inline) then
  180. begin
  181. objectlibrary.CreateUsedAsmSymbolList;
  182. hp:=tai(p_asm.first);
  183. while assigned(hp) do
  184. begin
  185. hp2:=tai(hp.getcopy);
  186. skipnode:=false;
  187. case hp2.typ of
  188. ait_label :
  189. ReLabel(tasmsymbol(tai_label(hp2).l));
  190. ait_const_rva,
  191. ait_const_symbol :
  192. ReLabel(tai_const_symbol(hp2).sym);
  193. ait_instruction :
  194. begin
  195. { remove cached insentry, because the new code can
  196. require an other less optimized instruction }
  197. {$ifdef i386}
  198. {$ifndef NOAG386BIN}
  199. taicpu(hp2).ResetPass1;
  200. {$endif}
  201. {$endif}
  202. { fixup the references }
  203. for i:=1 to taicpu(hp2).ops do
  204. begin
  205. ResolveRef(taicpu(hp2).oper[i-1]^);
  206. with taicpu(hp2).oper[i-1]^ do
  207. begin
  208. case typ of
  209. top_ref :
  210. if assigned(ref^.symbol) then
  211. ReLabel(ref^.symbol);
  212. top_symbol :
  213. ReLabel(sym);
  214. end;
  215. end;
  216. end;
  217. end;
  218. ait_marker :
  219. begin
  220. { it's not an assembler block anymore }
  221. if (tai_marker(hp2).kind in [AsmBlockStart, AsmBlockEnd]) then
  222. skipnode:=true;
  223. end;
  224. end;
  225. if not skipnode then
  226. exprasmList.concat(hp2)
  227. else
  228. hp2.free;
  229. hp:=tai(hp.next);
  230. end;
  231. { restore used symbols }
  232. objectlibrary.UsedAsmSymbolListResetAltSym;
  233. objectlibrary.DestroyUsedAsmSymbolList;
  234. end
  235. else
  236. begin
  237. hp:=tai(p_asm.first);
  238. while assigned(hp) do
  239. begin
  240. case hp.typ of
  241. ait_instruction :
  242. begin
  243. { remove cached insentry, because the new code can
  244. require an other less optimized instruction }
  245. {$ifdef i386}
  246. {$ifndef NOAG386BIN}
  247. taicpu(hp).ResetPass1;
  248. {$endif}
  249. {$endif}
  250. { fixup the references }
  251. for i:=1 to taicpu(hp).ops do
  252. ResolveRef(taicpu(hp).oper[i-1]^);
  253. end;
  254. end;
  255. hp:=tai(hp.next);
  256. end;
  257. { insert the list }
  258. exprasmList.concatlist(p_asm);
  259. end;
  260. { Release register used in the assembler block }
  261. cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,used_regs_int);
  262. end;
  263. {*****************************************************************************
  264. TBLOCKNODE
  265. *****************************************************************************}
  266. procedure tcgblocknode.pass_2;
  267. var
  268. hp : tstatementnode;
  269. begin
  270. location_reset(location,LOC_VOID,OS_NO);
  271. { do second pass on left node }
  272. if assigned(left) then
  273. begin
  274. hp:=tstatementnode(left);
  275. while assigned(hp) do
  276. begin
  277. if assigned(hp.left) then
  278. begin
  279. secondpass(hp.left);
  280. location_copy(hp.location,hp.left.location);
  281. end;
  282. location_copy(location,hp.location);
  283. hp:=tstatementnode(hp.right);
  284. end;
  285. end;
  286. end;
  287. {*****************************************************************************
  288. TTEMPCREATENODE
  289. *****************************************************************************}
  290. procedure tcgtempcreatenode.pass_2;
  291. begin
  292. location_reset(location,LOC_VOID,OS_NO);
  293. { if we're secondpassing the same tcgtempcreatenode twice, we have a bug }
  294. if tempinfo^.valid then
  295. internalerror(200108222);
  296. { get a (persistent) temp }
  297. tg.GetTemp(exprasmlist,size,tempinfo^.temptype,tempinfo^.ref);
  298. tempinfo^.valid := true;
  299. end;
  300. {*****************************************************************************
  301. TTEMPREFNODE
  302. *****************************************************************************}
  303. procedure tcgtemprefnode.pass_2;
  304. begin
  305. { check if the temp is valid }
  306. if not tempinfo^.valid then
  307. internalerror(200108231);
  308. { set the temp's location }
  309. location_reset(location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def));
  310. location.reference := tempinfo^.ref;
  311. inc(location.reference.offset,offset);
  312. end;
  313. procedure tcgtemprefnode.changelocation(const ref: treference);
  314. begin
  315. { check if the temp is valid }
  316. if not tempinfo^.valid then
  317. internalerror(200306081);
  318. if (tempinfo^.temptype = tt_persistent) then
  319. tg.ChangeTempType(exprasmlist,tempinfo^.ref,tt_normal);
  320. tg.ungettemp(exprasmlist,tempinfo^.ref);
  321. tempinfo^.ref := ref;
  322. tg.ChangeTempType(exprasmlist,tempinfo^.ref,tempinfo^.temptype);
  323. { adapt location }
  324. location.reference := ref;
  325. inc(location.reference.offset,offset);
  326. end;
  327. {*****************************************************************************
  328. TTEMPDELETENODE
  329. *****************************************************************************}
  330. procedure tcgtempdeletenode.pass_2;
  331. begin
  332. location_reset(location,LOC_VOID,OS_NO);
  333. if release_to_normal then
  334. tg.ChangeTempType(exprasmlist,tempinfo^.ref,tt_normal)
  335. else
  336. tg.UnGetTemp(exprasmlist,tempinfo^.ref);
  337. end;
  338. begin
  339. cnothingnode:=tcgnothingnode;
  340. casmnode:=tcgasmnode;
  341. cstatementnode:=tcgstatementnode;
  342. cblocknode:=tcgblocknode;
  343. ctempcreatenode:=tcgtempcreatenode;
  344. ctemprefnode:=tcgtemprefnode;
  345. ctempdeletenode:=tcgtempdeletenode;
  346. end.
  347. {
  348. $Log$
  349. Revision 1.47 2003-10-29 15:40:20 peter
  350. * support indexing and offset retrieval for locals
  351. Revision 1.46 2003/10/24 17:39:41 peter
  352. * asmnode.get_position now inserts a marker
  353. Revision 1.45 2003/10/21 15:15:36 peter
  354. * taicpu_abstract.oper[] changed to pointers
  355. Revision 1.44 2003/10/10 17:48:13 peter
  356. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  357. * tregisteralloctor renamed to trgobj
  358. * removed rgobj from a lot of units
  359. * moved location_* and reference_* to cgobj
  360. * first things for mmx register allocation
  361. Revision 1.43 2003/10/09 21:31:37 daniel
  362. * Register allocator splitted, ans abstract now
  363. Revision 1.42 2003/10/07 18:18:16 peter
  364. * fix register calling for assembler procedures
  365. * fix result loading for assembler procedures
  366. Revision 1.41 2003/10/01 20:34:48 peter
  367. * procinfo unit contains tprocinfo
  368. * cginfo renamed to cgbase
  369. * moved cgmessage to verbose
  370. * fixed ppc and sparc compiles
  371. Revision 1.40 2003/09/23 17:56:05 peter
  372. * locals and paras are allocated in the code generation
  373. * tvarsym.localloc contains the location of para/local when
  374. generating code for the current procedure
  375. Revision 1.39 2003/09/07 22:09:35 peter
  376. * preparations for different default calling conventions
  377. * various RA fixes
  378. Revision 1.38 2003/09/03 15:55:00 peter
  379. * NEWRA branch merged
  380. Revision 1.37.2.1 2003/08/27 20:23:55 peter
  381. * remove old ra code
  382. Revision 1.37 2003/06/13 21:19:30 peter
  383. * current_procdef removed, use current_procinfo.procdef instead
  384. Revision 1.36 2003/06/09 18:26:46 peter
  385. * remove temptype, use tempinfo.temptype instead
  386. Revision 1.35 2003/06/09 12:20:47 peter
  387. * getposition added to retrieve the the current tai item
  388. Revision 1.34 2003/05/17 13:30:08 jonas
  389. * changed tt_persistant to tt_persistent :)
  390. * tempcreatenode now doesn't accept a boolean anymore for persistent
  391. temps, but a ttemptype, so you can also create ansistring temps etc
  392. Revision 1.33 2003/04/27 11:21:33 peter
  393. * aktprocdef renamed to current_procinfo.procdef
  394. * procinfo renamed to current_procinfo
  395. * procinfo will now be stored in current_module so it can be
  396. cleaned up properly
  397. * gen_main_procsym changed to create_main_proc and release_main_proc
  398. to also generate a tprocinfo structure
  399. * fixed unit implicit initfinal
  400. Revision 1.32 2002/04/25 20:15:39 florian
  401. * block nodes within expressions shouldn't release the used registers,
  402. fixed using a flag till the new rg is ready
  403. Revision 1.31 2003/04/22 23:50:22 peter
  404. * firstpass uses expectloc
  405. * checks if there are differences between the expectloc and
  406. location.loc from secondpass in EXTDEBUG
  407. Revision 1.30 2003/04/17 07:50:24 daniel
  408. * Some work on interference graph construction
  409. Revision 1.29 2003/03/28 19:16:56 peter
  410. * generic constructor working for i386
  411. * remove fixed self register
  412. * esi added as address register for i386
  413. Revision 1.28 2002/11/27 15:33:19 peter
  414. * fixed relabeling to relabel only tasmlabel (formerly proclocal)
  415. Revision 1.27 2002/11/27 02:37:13 peter
  416. * case statement inlining added
  417. * fixed inlining of write()
  418. * switched statementnode left and right parts so the statements are
  419. processed in the correct order when getcopy is used. This is
  420. required for tempnodes
  421. Revision 1.26 2002/11/17 16:31:56 carl
  422. * memory optimization (3-4%) : cleanup of tai fields,
  423. cleanup of tdef and tsym fields.
  424. * make it work for m68k
  425. Revision 1.25 2002/11/15 16:29:30 peter
  426. * made tasmsymbol.refs private (merged)
  427. Revision 1.24 2002/11/15 01:58:51 peter
  428. * merged changes from 1.0.7 up to 04-11
  429. - -V option for generating bug report tracing
  430. - more tracing for option parsing
  431. - errors for cdecl and high()
  432. - win32 import stabs
  433. - win32 records<=8 are returned in eax:edx (turned off by default)
  434. - heaptrc update
  435. - more info for temp management in .s file with EXTDEBUG
  436. Revision 1.23 2002/08/23 16:14:48 peter
  437. * tempgen cleanup
  438. * tt_noreuse temp type added that will be used in genentrycode
  439. Revision 1.22 2002/08/11 14:32:26 peter
  440. * renamed current_library to objectlibrary
  441. Revision 1.21 2002/08/11 13:24:11 peter
  442. * saving of asmsymbols in ppu supported
  443. * asmsymbollist global is removed and moved into a new class
  444. tasmlibrarydata that will hold the info of a .a file which
  445. corresponds with a single module. Added librarydata to tmodule
  446. to keep the library info stored for the module. In the future the
  447. objectfiles will also be stored to the tasmlibrarydata class
  448. * all getlabel/newasmsymbol and friends are moved to the new class
  449. Revision 1.20 2002/07/01 18:46:22 peter
  450. * internal linker
  451. * reorganized aasm layer
  452. Revision 1.19 2002/05/18 13:34:09 peter
  453. * readded missing revisions
  454. Revision 1.18 2002/05/16 19:46:37 carl
  455. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  456. + try to fix temp allocation (still in ifdef)
  457. + generic constructor calls
  458. + start of tassembler / tmodulebase class cleanup
  459. Revision 1.16 2002/05/13 19:54:37 peter
  460. * removed n386ld and n386util units
  461. * maybe_save/maybe_restore added instead of the old maybe_push
  462. Revision 1.15 2002/05/12 16:53:07 peter
  463. * moved entry and exitcode to ncgutil and cgobj
  464. * foreach gets extra argument for passing local data to the
  465. iterator function
  466. * -CR checks also class typecasts at runtime by changing them
  467. into as
  468. * fixed compiler to cycle with the -CR option
  469. * fixed stabs with elf writer, finally the global variables can
  470. be watched
  471. * removed a lot of routines from cga unit and replaced them by
  472. calls to cgobj
  473. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  474. u32bit then the other is typecasted also to u32bit without giving
  475. a rangecheck warning/error.
  476. * fixed pascal calling method with reversing also the high tree in
  477. the parast, detected by tcalcst3 test
  478. Revision 1.14 2002/04/23 19:16:34 peter
  479. * add pinline unit that inserts compiler supported functions using
  480. one or more statements
  481. * moved finalize and setlength from ninl to pinline
  482. Revision 1.13 2002/04/21 19:02:03 peter
  483. * removed newn and disposen nodes, the code is now directly
  484. inlined from pexpr
  485. * -an option that will write the secondpass nodes to the .s file, this
  486. requires EXTDEBUG define to actually write the info
  487. * fixed various internal errors and crashes due recent code changes
  488. Revision 1.12 2002/04/04 19:05:57 peter
  489. * removed unused units
  490. * use tlocation.size in cg.a_*loc*() routines
  491. Revision 1.11 2002/03/31 20:26:34 jonas
  492. + a_loadfpu_* and a_loadmm_* methods in tcg
  493. * register allocation is now handled by a class and is mostly processor
  494. independent (+rgobj.pas and i386/rgcpu.pas)
  495. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  496. * some small improvements and fixes to the optimizer
  497. * some register allocation fixes
  498. * some fpuvaroffset fixes in the unary minus node
  499. * push/popusedregisters is now called rg.save/restoreusedregisters and
  500. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  501. also better optimizable)
  502. * fixed and optimized register saving/restoring for new/dispose nodes
  503. * LOC_FPU locations now also require their "register" field to be set to
  504. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  505. - list field removed of the tnode class because it's not used currently
  506. and can cause hard-to-find bugs
  507. }