ncgbas.pas 21 KB

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