ncgmem.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate assembler for memory related nodes which are
  5. the same for all (most?) processors
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. { This unit generate assembler for memory related nodes.
  20. }
  21. unit ncgmem;
  22. {$i fpcdefs.inc}
  23. interface
  24. uses
  25. node,nmem,cpuinfo;
  26. type
  27. tcgloadvmtnode = class(tloadvmtnode)
  28. procedure pass_2;override;
  29. end;
  30. tcghnewnode = class(thnewnode)
  31. procedure pass_2;override;
  32. end;
  33. tcghdisposenode = class(thdisposenode)
  34. procedure pass_2;override;
  35. end;
  36. tcgaddrnode = class(taddrnode)
  37. procedure pass_2;override;
  38. end;
  39. tcgdoubleaddrnode = class(tdoubleaddrnode)
  40. procedure pass_2;override;
  41. end;
  42. tcgderefnode = class(tderefnode)
  43. procedure pass_2;override;
  44. end;
  45. tcgsubscriptnode = class(tsubscriptnode)
  46. procedure pass_2;override;
  47. end;
  48. tcgselfnode = class(tselfnode)
  49. procedure pass_2;override;
  50. end;
  51. tcgwithnode = class(twithnode)
  52. procedure pass_2;override;
  53. end;
  54. tcgvecnode = class(tvecnode)
  55. function get_mul_size : aword;
  56. procedure second_wideansistring;virtual;
  57. procedure second_dynamicarray;virtual;
  58. procedure pass_2;override;
  59. end;
  60. implementation
  61. uses
  62. globtype,systems,
  63. cutils,verbose,globals,
  64. symconst,symdef,symsym,paramgr,
  65. aasmbase,aasmtai,aasmcpu,
  66. cgbase,pass_2,
  67. nld,ncon,nadd,
  68. cpubase,cpupara,
  69. cgobj,cgcpu,
  70. tgobj,rgobj
  71. {$ifdef GDB}
  72. {$ifdef delphi}
  73. ,sysutils
  74. {$else}
  75. ,strings
  76. {$endif}
  77. ,symbase
  78. ,gdb
  79. {$endif GDB}
  80. ;
  81. {*****************************************************************************
  82. TCGLOADNODE
  83. *****************************************************************************}
  84. procedure tcgloadvmtnode.pass_2;
  85. begin
  86. location_reset(location,LOC_REGISTER,OS_ADDR);
  87. location.register:=rg.getregisterint(exprasmlist);
  88. cg.a_load_sym_ofs_reg(exprasmlist,
  89. newasmsymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname),
  90. 0,location.register);
  91. end;
  92. {*****************************************************************************
  93. TCGHNEWNODE
  94. *****************************************************************************}
  95. procedure tcghnewnode.pass_2;
  96. begin
  97. { completely resolved in first pass now }
  98. end;
  99. {*****************************************************************************
  100. TCGHDISPOSENODE
  101. *****************************************************************************}
  102. procedure tcghdisposenode.pass_2;
  103. begin
  104. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  105. secondpass(left);
  106. if codegenerror then
  107. exit;
  108. case left.location.loc of
  109. LOC_REGISTER:
  110. begin
  111. if not rg.isaddressregister(left.location.register) then
  112. begin
  113. location_release(exprasmlist,left.location);
  114. location.reference.base := rg.getaddressregister(exprasmlist);
  115. cg.a_load_reg_reg(exprasmlist,OS_ADDR,left.location.register,
  116. location.reference.base);
  117. end
  118. else
  119. location.reference.base := left.location.register;
  120. end;
  121. LOC_CREGISTER,
  122. LOC_CREFERENCE,
  123. LOC_REFERENCE:
  124. begin
  125. location_release(exprasmlist,left.location);
  126. location.reference.base:=rg.getaddressregister(exprasmlist);
  127. cg.a_load_loc_reg(exprasmlist,left.location,location.reference.base);
  128. end;
  129. else
  130. internalerror(2002032217);
  131. end;
  132. end;
  133. {*****************************************************************************
  134. TCGADDRNODE
  135. *****************************************************************************}
  136. procedure tcgaddrnode.pass_2;
  137. begin
  138. secondpass(left);
  139. { when loading procvar we do nothing with this node, so load the
  140. location of left }
  141. if nf_procvarload in flags then
  142. begin
  143. location_copy(location,left.location);
  144. exit;
  145. end;
  146. location_release(exprasmlist,left.location);
  147. location_reset(location,LOC_REGISTER,OS_ADDR);
  148. location.register:=rg.getaddressregister(exprasmlist);
  149. {@ on a procvar means returning an address to the procedure that
  150. is stored in it.}
  151. { yes but left.symtableentry can be nil
  152. for example on self !! }
  153. { symtableentry can be also invalid, if left is no tree node }
  154. if (m_tp_procvar in aktmodeswitches) and
  155. (left.nodetype=loadn) and
  156. assigned(tloadnode(left).symtableentry) and
  157. (tloadnode(left).symtableentry.typ=varsym) and
  158. (tvarsym(tloadnode(left).symtableentry).vartype.def.deftype=procvardef) then
  159. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,
  160. location.register)
  161. else
  162. begin
  163. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,
  164. location.register);
  165. end;
  166. end;
  167. {*****************************************************************************
  168. TCGDOUBLEADDRNODE
  169. *****************************************************************************}
  170. procedure tcgdoubleaddrnode.pass_2;
  171. begin
  172. secondpass(left);
  173. location_release(exprasmlist,left.location);
  174. location_reset(location,LOC_REGISTER,OS_ADDR);
  175. location.register:=rg.getaddressregister(exprasmlist);
  176. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,
  177. location.register);
  178. end;
  179. {*****************************************************************************
  180. TCGDEREFNODE
  181. *****************************************************************************}
  182. procedure tcgderefnode.pass_2;
  183. begin
  184. secondpass(left);
  185. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  186. case left.location.loc of
  187. LOC_REGISTER:
  188. begin
  189. if not rg.isaddressregister(left.location.register) then
  190. begin
  191. location_release(exprasmlist,left.location);
  192. location.reference.base := rg.getaddressregister(exprasmlist);
  193. cg.a_load_reg_reg(exprasmlist,OS_ADDR,left.location.register,
  194. location.reference.base);
  195. end
  196. else
  197. location.reference.base := left.location.register;
  198. end;
  199. LOC_CREGISTER,
  200. LOC_CREFERENCE,
  201. LOC_REFERENCE:
  202. begin
  203. location_release(exprasmlist,left.location);
  204. location.reference.base:=rg.getaddressregister(exprasmlist);
  205. cg.a_load_loc_reg(exprasmlist,left.location,location.reference.base);
  206. end;
  207. end;
  208. if (cs_gdb_heaptrc in aktglobalswitches) and
  209. (cs_checkpointer in aktglobalswitches) then
  210. begin
  211. cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,paramanager.getintparaloc(1));
  212. cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER');
  213. end;
  214. end;
  215. {*****************************************************************************
  216. TCGSUBSCRIPTNODE
  217. *****************************************************************************}
  218. procedure tcgsubscriptnode.pass_2;
  219. begin
  220. secondpass(left);
  221. if codegenerror then
  222. exit;
  223. { classes and interfaces must be dereferenced implicit }
  224. if is_class_or_interface(left.resulttype.def) then
  225. begin
  226. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  227. case left.location.loc of
  228. LOC_REGISTER:
  229. begin
  230. if not rg.isaddressregister(left.location.register) then
  231. begin
  232. location_release(exprasmlist,left.location);
  233. location.reference.base:=rg.getaddressregister(exprasmlist);
  234. cg.a_load_reg_reg(exprasmlist,OS_ADDR,
  235. left.location.register,location.reference.base);
  236. end
  237. else
  238. location.reference.base := left.location.register;
  239. end;
  240. LOC_CREGISTER,
  241. LOC_CREFERENCE,
  242. LOC_REFERENCE:
  243. begin
  244. location_release(exprasmlist,left.location);
  245. location.reference.base:=rg.getaddressregister(exprasmlist);
  246. cg.a_load_loc_reg(exprasmlist,left.location,location.reference.base);
  247. end;
  248. end;
  249. end
  250. else if is_interfacecom(left.resulttype.def) then
  251. begin
  252. tg.gettempintfcomreference(exprasmlist,location.reference);
  253. cg.a_load_loc_ref(exprasmlist,left.location,location.reference);
  254. end
  255. else
  256. location_copy(location,left.location);
  257. inc(location.reference.offset,vs.address);
  258. { also update the size of the location }
  259. location.size:=def_cgsize(resulttype.def);
  260. end;
  261. {*****************************************************************************
  262. TCGSELFNODE
  263. *****************************************************************************}
  264. procedure tcgselfnode.pass_2;
  265. begin
  266. rg.getexplicitregisterint(exprasmlist,SELF_POINTER_REG);
  267. if (resulttype.def.deftype=classrefdef) or
  268. is_class(resulttype.def) then
  269. begin
  270. location_reset(location,LOC_CREGISTER,OS_ADDR);
  271. location.register:=SELF_POINTER_REG;
  272. end
  273. else
  274. begin
  275. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  276. location.reference.base:=SELF_POINTER_REG;
  277. end;
  278. end;
  279. {*****************************************************************************
  280. TCGWITHNODE
  281. *****************************************************************************}
  282. procedure tcgwithnode.pass_2;
  283. var
  284. tmpreg: tregister;
  285. usetemp,with_expr_in_temp : boolean;
  286. {$ifdef GDB}
  287. withstartlabel,withendlabel : tasmlabel;
  288. pp : pchar;
  289. mangled_length : longint;
  290. const
  291. withlevel : longint = 0;
  292. {$endif GDB}
  293. begin
  294. if assigned(left) then
  295. begin
  296. secondpass(left);
  297. {$ifdef i386}
  298. if (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  299. (left.location.reference.segment<>R_NO) then
  300. message(parser_e_no_with_for_variable_in_other_segments);
  301. {$endif i386}
  302. reference_reset(withreference);
  303. usetemp:=false;
  304. if (left.nodetype=loadn) and
  305. (tloadnode(left).symtable=aktprocdef.localst) then
  306. begin
  307. { for locals use the local storage }
  308. withreference:=left.location.reference;
  309. include(flags,nf_islocal);
  310. end
  311. else
  312. { call can have happend with a property }
  313. begin
  314. usetemp:=true;
  315. if is_class_or_interface(left.resulttype.def) then
  316. begin
  317. tmpreg := cg.get_scratch_reg_int(exprasmlist);
  318. cg.a_load_loc_reg(exprasmlist,left.location,tmpreg)
  319. end
  320. else
  321. begin
  322. tmpreg := cg.get_scratch_reg_address(exprasmlist);
  323. cg.a_loadaddr_ref_reg(exprasmlist,
  324. left.location.reference,tmpreg);
  325. end;
  326. end;
  327. location_release(exprasmlist,left.location);
  328. { if the with expression is stored in a temp }
  329. { area we must make it persistent and shouldn't }
  330. { release it (FK) }
  331. if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) and
  332. tg.istemp(left.location.reference) then
  333. begin
  334. tg.normaltemptopersistant(left.location.reference.offset);
  335. with_expr_in_temp:=true;
  336. end
  337. else
  338. with_expr_in_temp:=false;
  339. { if usetemp is set the value must be in tmpreg }
  340. if usetemp then
  341. begin
  342. tg.gettempofsizereference(exprasmlist,pointer_size,withreference);
  343. tg.normaltemptopersistant(withreference.offset);
  344. { move to temp reference }
  345. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,withreference);
  346. cg.free_scratch_reg(exprasmlist,tmpreg);
  347. {$ifdef GDB}
  348. if (cs_debuginfo in aktmoduleswitches) then
  349. begin
  350. inc(withlevel);
  351. getaddrlabel(withstartlabel);
  352. getaddrlabel(withendlabel);
  353. cg.a_label(exprasmlist,withstartlabel);
  354. withdebugList.concat(Tai_stabs.Create(strpnew(
  355. '"with'+tostr(withlevel)+':'+tostr(symtablestack.getnewtypecount)+
  356. '=*'+tstoreddef(left.resulttype.def).numberstring+'",'+
  357. tostr(N_LSYM)+',0,0,'+tostr(withreference.offset))));
  358. mangled_length:=length(aktprocdef.mangledname);
  359. getmem(pp,mangled_length+50);
  360. strpcopy(pp,'192,0,0,'+withstartlabel.name);
  361. if (target_info.use_function_relative_addresses) then
  362. begin
  363. strpcopy(strend(pp),'-');
  364. strpcopy(strend(pp),aktprocdef.mangledname);
  365. end;
  366. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  367. end;
  368. {$endif GDB}
  369. end;
  370. { right can be optimize out !!! }
  371. if assigned(right) then
  372. secondpass(right);
  373. if usetemp then
  374. begin
  375. tg.ungetpersistanttemp(exprasmlist,withreference.offset);
  376. {$ifdef GDB}
  377. if (cs_debuginfo in aktmoduleswitches) then
  378. begin
  379. cg.a_label(exprasmlist,withendlabel);
  380. strpcopy(pp,'224,0,0,'+withendlabel.name);
  381. if (target_info.use_function_relative_addresses) then
  382. begin
  383. strpcopy(strend(pp),'-');
  384. strpcopy(strend(pp),aktprocdef.mangledname);
  385. end;
  386. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  387. freemem(pp,mangled_length+50);
  388. dec(withlevel);
  389. end;
  390. {$endif GDB}
  391. end;
  392. if with_expr_in_temp then
  393. tg.ungetpersistanttemp(exprasmlist,left.location.reference.offset);
  394. reference_reset(withreference);
  395. end;
  396. end;
  397. {*****************************************************************************
  398. TCGVECNODE
  399. *****************************************************************************}
  400. function tcgvecnode.get_mul_size : aword;
  401. begin
  402. if nf_memindex in flags then
  403. get_mul_size:=1
  404. else
  405. begin
  406. if (left.resulttype.def.deftype=arraydef) then
  407. get_mul_size:=tarraydef(left.resulttype.def).elesize
  408. else
  409. get_mul_size:=resulttype.def.size;
  410. end
  411. end;
  412. procedure tcgvecnode.second_wideansistring;
  413. begin
  414. end;
  415. procedure tcgvecnode.second_dynamicarray;
  416. begin
  417. end;
  418. procedure tcgvecnode.pass_2;
  419. begin
  420. {!!!!}
  421. writeln('FIX ME: tcgvecnode.pass_2');
  422. end;
  423. begin
  424. cloadvmtnode:=tcgloadvmtnode;
  425. chnewnode:=tcghnewnode;
  426. chdisposenode:=tcghdisposenode;
  427. caddrnode:=tcgaddrnode;
  428. cdoubleaddrnode:=tcgdoubleaddrnode;
  429. cderefnode:=tcgderefnode;
  430. csubscriptnode:=tcgsubscriptnode;
  431. cselfnode:=tcgselfnode;
  432. cwithnode:=tcgwithnode;
  433. cvecnode:=tcgvecnode;
  434. end.
  435. {
  436. $Log$
  437. Revision 1.18 2002-07-28 21:34:31 florian
  438. * more powerpc fixes
  439. + dummy tcgvecnode
  440. Revision 1.17 2002/07/11 14:41:28 florian
  441. * start of the new generic parameter handling
  442. Revision 1.16 2002/07/07 09:52:32 florian
  443. * powerpc target fixed, very simple units can be compiled
  444. * some basic stuff for better callparanode handling, far from being finished
  445. Revision 1.15 2002/07/01 18:46:23 peter
  446. * internal linker
  447. * reorganized aasm layer
  448. Revision 1.14 2002/07/01 16:23:53 peter
  449. * cg64 patch
  450. * basics for currency
  451. * asnode updates for class and interface (not finished)
  452. Revision 1.13 2002/05/20 13:30:40 carl
  453. * bugfix of hdisponen (base must be set, not index)
  454. * more portability fixes
  455. Revision 1.12 2002/05/18 13:34:09 peter
  456. * readded missing revisions
  457. Revision 1.11 2002/05/16 19:46:37 carl
  458. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  459. + try to fix temp allocation (still in ifdef)
  460. + generic constructor calls
  461. + start of tassembler / tmodulebase class cleanup
  462. Revision 1.9 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.8 2002/04/20 21:32:23 carl
  479. + generic FPC_CHECKPOINTER
  480. + first parameter offset in stack now portable
  481. * rename some constants
  482. + move some cpu stuff to other units
  483. - remove unused constents
  484. * fix stacksize for some targets
  485. * fix generic size problems which depend now on EXTEND_SIZE constant
  486. Revision 1.7 2002/04/15 18:58:47 carl
  487. + target_info.size_of_pointer -> pointer_Size
  488. Revision 1.6 2002/04/04 19:05:57 peter
  489. * removed unused units
  490. * use tlocation.size in cg.a_*loc*() routines
  491. Revision 1.5 2002/04/02 17:11:28 peter
  492. * tlocation,treference update
  493. * LOC_CONSTANT added for better constant handling
  494. * secondadd splitted in multiple routines
  495. * location_force_reg added for loading a location to a register
  496. of a specified size
  497. * secondassignment parses now first the right and then the left node
  498. (this is compatible with Kylix). This saves a lot of push/pop especially
  499. with string operations
  500. * adapted some routines to use the new cg methods
  501. Revision 1.4 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. }