ncgbas.pas 21 KB

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