ncgmem.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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;
  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. implementation
  55. uses
  56. globtype,systems,
  57. cutils,verbose,globals,
  58. symconst,symdef,symsym,paramgr,
  59. aasmbase,aasmtai,aasmcpu,
  60. cgbase,pass_2,
  61. nld,ncon,nadd,
  62. cpuinfo,cpubase,cpupara,
  63. cgobj,cgcpu,
  64. tgobj,rgobj
  65. {$ifdef GDB}
  66. {$ifdef delphi}
  67. ,sysutils
  68. {$else}
  69. ,strings
  70. {$endif}
  71. ,symbase
  72. ,gdb
  73. {$endif GDB}
  74. ;
  75. {*****************************************************************************
  76. TCGLOADNODE
  77. *****************************************************************************}
  78. procedure tcgloadvmtnode.pass_2;
  79. begin
  80. location_reset(location,LOC_REGISTER,OS_ADDR);
  81. location.register:=rg.getregisterint(exprasmlist);
  82. cg.a_load_sym_ofs_reg(exprasmlist,
  83. newasmsymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname),
  84. 0,location.register);
  85. end;
  86. {*****************************************************************************
  87. TCGHNEWNODE
  88. *****************************************************************************}
  89. procedure tcghnewnode.pass_2;
  90. begin
  91. { completely resolved in first pass now }
  92. end;
  93. {*****************************************************************************
  94. TCGHDISPOSENODE
  95. *****************************************************************************}
  96. procedure tcghdisposenode.pass_2;
  97. begin
  98. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  99. secondpass(left);
  100. if codegenerror then
  101. exit;
  102. case left.location.loc of
  103. LOC_REGISTER:
  104. begin
  105. if not rg.isaddressregister(left.location.register) then
  106. begin
  107. location_release(exprasmlist,left.location);
  108. location.reference.base := rg.getaddressregister(exprasmlist);
  109. cg.a_load_reg_reg(exprasmlist,OS_ADDR,left.location.register,
  110. location.reference.base);
  111. end
  112. else
  113. location.reference.base := left.location.register;
  114. end;
  115. LOC_CREGISTER,
  116. LOC_CREFERENCE,
  117. LOC_REFERENCE:
  118. begin
  119. location_release(exprasmlist,left.location);
  120. location.reference.base:=rg.getaddressregister(exprasmlist);
  121. cg.a_load_loc_reg(exprasmlist,left.location,location.reference.base);
  122. end;
  123. else
  124. internalerror(2002032217);
  125. end;
  126. end;
  127. {*****************************************************************************
  128. TCGADDRNODE
  129. *****************************************************************************}
  130. procedure tcgaddrnode.pass_2;
  131. begin
  132. secondpass(left);
  133. { when loading procvar we do nothing with this node, so load the
  134. location of left }
  135. if nf_procvarload in flags then
  136. begin
  137. location_copy(location,left.location);
  138. exit;
  139. end;
  140. location_release(exprasmlist,left.location);
  141. location_reset(location,LOC_REGISTER,OS_ADDR);
  142. location.register:=rg.getaddressregister(exprasmlist);
  143. {@ on a procvar means returning an address to the procedure that
  144. is stored in it.}
  145. { yes but left.symtableentry can be nil
  146. for example on self !! }
  147. { symtableentry can be also invalid, if left is no tree node }
  148. if (m_tp_procvar in aktmodeswitches) and
  149. (left.nodetype=loadn) and
  150. assigned(tloadnode(left).symtableentry) and
  151. (tloadnode(left).symtableentry.typ=varsym) and
  152. (tvarsym(tloadnode(left).symtableentry).vartype.def.deftype=procvardef) then
  153. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,
  154. location.register)
  155. else
  156. begin
  157. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,
  158. location.register);
  159. end;
  160. end;
  161. {*****************************************************************************
  162. TCGDOUBLEADDRNODE
  163. *****************************************************************************}
  164. procedure tcgdoubleaddrnode.pass_2;
  165. begin
  166. secondpass(left);
  167. location_release(exprasmlist,left.location);
  168. location_reset(location,LOC_REGISTER,OS_ADDR);
  169. location.register:=rg.getaddressregister(exprasmlist);
  170. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,
  171. location.register);
  172. end;
  173. {*****************************************************************************
  174. TCGDEREFNODE
  175. *****************************************************************************}
  176. procedure tcgderefnode.pass_2;
  177. begin
  178. secondpass(left);
  179. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  180. case left.location.loc of
  181. LOC_REGISTER:
  182. begin
  183. if not rg.isaddressregister(left.location.register) then
  184. begin
  185. location_release(exprasmlist,left.location);
  186. location.reference.base := rg.getaddressregister(exprasmlist);
  187. cg.a_load_reg_reg(exprasmlist,OS_ADDR,left.location.register,
  188. location.reference.base);
  189. end
  190. else
  191. location.reference.base := left.location.register;
  192. end;
  193. LOC_CREGISTER,
  194. LOC_CREFERENCE,
  195. LOC_REFERENCE:
  196. begin
  197. location_release(exprasmlist,left.location);
  198. location.reference.base:=rg.getaddressregister(exprasmlist);
  199. cg.a_load_loc_reg(exprasmlist,left.location,location.reference.base);
  200. end;
  201. end;
  202. if (cs_gdb_heaptrc in aktglobalswitches) and
  203. (cs_checkpointer in aktglobalswitches) then
  204. begin
  205. cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,paramanager.getintparaloc(1));
  206. cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER');
  207. end;
  208. end;
  209. {*****************************************************************************
  210. TCGSUBSCRIPTNODE
  211. *****************************************************************************}
  212. procedure tcgsubscriptnode.pass_2;
  213. begin
  214. secondpass(left);
  215. if codegenerror then
  216. exit;
  217. { classes and interfaces must be dereferenced implicit }
  218. if is_class_or_interface(left.resulttype.def) then
  219. begin
  220. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  221. case left.location.loc of
  222. LOC_REGISTER:
  223. begin
  224. if not rg.isaddressregister(left.location.register) then
  225. begin
  226. location_release(exprasmlist,left.location);
  227. location.reference.base:=rg.getaddressregister(exprasmlist);
  228. cg.a_load_reg_reg(exprasmlist,OS_ADDR,
  229. left.location.register,location.reference.base);
  230. end
  231. else
  232. location.reference.base := left.location.register;
  233. end;
  234. LOC_CREGISTER,
  235. LOC_CREFERENCE,
  236. LOC_REFERENCE:
  237. begin
  238. location_release(exprasmlist,left.location);
  239. location.reference.base:=rg.getaddressregister(exprasmlist);
  240. cg.a_load_loc_reg(exprasmlist,left.location,location.reference.base);
  241. end;
  242. end;
  243. end
  244. else if is_interfacecom(left.resulttype.def) then
  245. begin
  246. tg.gettempintfcomreference(exprasmlist,location.reference);
  247. cg.a_load_loc_ref(exprasmlist,left.location,location.reference);
  248. end
  249. else
  250. location_copy(location,left.location);
  251. inc(location.reference.offset,vs.address);
  252. { also update the size of the location }
  253. location.size:=def_cgsize(resulttype.def);
  254. end;
  255. {*****************************************************************************
  256. TCGSELFNODE
  257. *****************************************************************************}
  258. procedure tcgselfnode.pass_2;
  259. begin
  260. rg.getexplicitregisterint(exprasmlist,SELF_POINTER_REG);
  261. if (resulttype.def.deftype=classrefdef) or
  262. is_class(resulttype.def) then
  263. begin
  264. location_reset(location,LOC_CREGISTER,OS_ADDR);
  265. location.register:=SELF_POINTER_REG;
  266. end
  267. else
  268. begin
  269. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  270. location.reference.base:=SELF_POINTER_REG;
  271. end;
  272. end;
  273. {*****************************************************************************
  274. TCGWITHNODE
  275. *****************************************************************************}
  276. procedure tcgwithnode.pass_2;
  277. var
  278. tmpreg: tregister;
  279. usetemp,with_expr_in_temp : boolean;
  280. {$ifdef GDB}
  281. withstartlabel,withendlabel : tasmlabel;
  282. pp : pchar;
  283. mangled_length : longint;
  284. const
  285. withlevel : longint = 0;
  286. {$endif GDB}
  287. begin
  288. if assigned(left) then
  289. begin
  290. secondpass(left);
  291. {$ifdef i386}
  292. if (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  293. (left.location.reference.segment<>R_NO) then
  294. message(parser_e_no_with_for_variable_in_other_segments);
  295. {$endif i386}
  296. reference_reset(withreference);
  297. usetemp:=false;
  298. if (left.nodetype=loadn) and
  299. (tloadnode(left).symtable=aktprocdef.localst) then
  300. begin
  301. { for locals use the local storage }
  302. withreference:=left.location.reference;
  303. include(flags,nf_islocal);
  304. end
  305. else
  306. { call can have happend with a property }
  307. begin
  308. usetemp:=true;
  309. if is_class_or_interface(left.resulttype.def) then
  310. begin
  311. tmpreg := cg.get_scratch_reg_int(exprasmlist);
  312. cg.a_load_loc_reg(exprasmlist,left.location,tmpreg)
  313. end
  314. else
  315. begin
  316. tmpreg := cg.get_scratch_reg_address(exprasmlist);
  317. cg.a_loadaddr_ref_reg(exprasmlist,
  318. left.location.reference,tmpreg);
  319. end;
  320. end;
  321. location_release(exprasmlist,left.location);
  322. { if the with expression is stored in a temp }
  323. { area we must make it persistent and shouldn't }
  324. { release it (FK) }
  325. if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) and
  326. tg.istemp(left.location.reference) then
  327. begin
  328. tg.normaltemptopersistant(left.location.reference.offset);
  329. with_expr_in_temp:=true;
  330. end
  331. else
  332. with_expr_in_temp:=false;
  333. { if usetemp is set the value must be in tmpreg }
  334. if usetemp then
  335. begin
  336. tg.gettempofsizereference(exprasmlist,pointer_size,withreference);
  337. tg.normaltemptopersistant(withreference.offset);
  338. { move to temp reference }
  339. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,withreference);
  340. cg.free_scratch_reg(exprasmlist,tmpreg);
  341. {$ifdef GDB}
  342. if (cs_debuginfo in aktmoduleswitches) then
  343. begin
  344. inc(withlevel);
  345. getaddrlabel(withstartlabel);
  346. getaddrlabel(withendlabel);
  347. cg.a_label(exprasmlist,withstartlabel);
  348. withdebugList.concat(Tai_stabs.Create(strpnew(
  349. '"with'+tostr(withlevel)+':'+tostr(symtablestack.getnewtypecount)+
  350. '=*'+tstoreddef(left.resulttype.def).numberstring+'",'+
  351. tostr(N_LSYM)+',0,0,'+tostr(withreference.offset))));
  352. mangled_length:=length(aktprocdef.mangledname);
  353. getmem(pp,mangled_length+50);
  354. strpcopy(pp,'192,0,0,'+withstartlabel.name);
  355. if (target_info.use_function_relative_addresses) then
  356. begin
  357. strpcopy(strend(pp),'-');
  358. strpcopy(strend(pp),aktprocdef.mangledname);
  359. end;
  360. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  361. end;
  362. {$endif GDB}
  363. end;
  364. { right can be optimize out !!! }
  365. if assigned(right) then
  366. secondpass(right);
  367. if usetemp then
  368. begin
  369. tg.ungetpersistanttemp(exprasmlist,withreference.offset);
  370. {$ifdef GDB}
  371. if (cs_debuginfo in aktmoduleswitches) then
  372. begin
  373. cg.a_label(exprasmlist,withendlabel);
  374. strpcopy(pp,'224,0,0,'+withendlabel.name);
  375. if (target_info.use_function_relative_addresses) then
  376. begin
  377. strpcopy(strend(pp),'-');
  378. strpcopy(strend(pp),aktprocdef.mangledname);
  379. end;
  380. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  381. freemem(pp,mangled_length+50);
  382. dec(withlevel);
  383. end;
  384. {$endif GDB}
  385. end;
  386. if with_expr_in_temp then
  387. tg.ungetpersistanttemp(exprasmlist,left.location.reference.offset);
  388. reference_reset(withreference);
  389. end;
  390. end;
  391. begin
  392. cloadvmtnode:=tcgloadvmtnode;
  393. chnewnode:=tcghnewnode;
  394. chdisposenode:=tcghdisposenode;
  395. caddrnode:=tcgaddrnode;
  396. cdoubleaddrnode:=tcgdoubleaddrnode;
  397. cderefnode:=tcgderefnode;
  398. csubscriptnode:=tcgsubscriptnode;
  399. cselfnode:=tcgselfnode;
  400. cwithnode:=tcgwithnode;
  401. end.
  402. {
  403. $Log$
  404. Revision 1.17 2002-07-11 14:41:28 florian
  405. * start of the new generic parameter handling
  406. Revision 1.16 2002/07/07 09:52:32 florian
  407. * powerpc target fixed, very simple units can be compiled
  408. * some basic stuff for better callparanode handling, far from being finished
  409. Revision 1.15 2002/07/01 18:46:23 peter
  410. * internal linker
  411. * reorganized aasm layer
  412. Revision 1.14 2002/07/01 16:23:53 peter
  413. * cg64 patch
  414. * basics for currency
  415. * asnode updates for class and interface (not finished)
  416. Revision 1.13 2002/05/20 13:30:40 carl
  417. * bugfix of hdisponen (base must be set, not index)
  418. * more portability fixes
  419. Revision 1.12 2002/05/18 13:34:09 peter
  420. * readded missing revisions
  421. Revision 1.11 2002/05/16 19:46:37 carl
  422. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  423. + try to fix temp allocation (still in ifdef)
  424. + generic constructor calls
  425. + start of tassembler / tmodulebase class cleanup
  426. Revision 1.9 2002/05/12 16:53:07 peter
  427. * moved entry and exitcode to ncgutil and cgobj
  428. * foreach gets extra argument for passing local data to the
  429. iterator function
  430. * -CR checks also class typecasts at runtime by changing them
  431. into as
  432. * fixed compiler to cycle with the -CR option
  433. * fixed stabs with elf writer, finally the global variables can
  434. be watched
  435. * removed a lot of routines from cga unit and replaced them by
  436. calls to cgobj
  437. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  438. u32bit then the other is typecasted also to u32bit without giving
  439. a rangecheck warning/error.
  440. * fixed pascal calling method with reversing also the high tree in
  441. the parast, detected by tcalcst3 test
  442. Revision 1.8 2002/04/20 21:32:23 carl
  443. + generic FPC_CHECKPOINTER
  444. + first parameter offset in stack now portable
  445. * rename some constants
  446. + move some cpu stuff to other units
  447. - remove unused constents
  448. * fix stacksize for some targets
  449. * fix generic size problems which depend now on EXTEND_SIZE constant
  450. Revision 1.7 2002/04/15 18:58:47 carl
  451. + target_info.size_of_pointer -> pointer_Size
  452. Revision 1.6 2002/04/04 19:05:57 peter
  453. * removed unused units
  454. * use tlocation.size in cg.a_*loc*() routines
  455. Revision 1.5 2002/04/02 17:11:28 peter
  456. * tlocation,treference update
  457. * LOC_CONSTANT added for better constant handling
  458. * secondadd splitted in multiple routines
  459. * location_force_reg added for loading a location to a register
  460. of a specified size
  461. * secondassignment parses now first the right and then the left node
  462. (this is compatible with Kylix). This saves a lot of push/pop especially
  463. with string operations
  464. * adapted some routines to use the new cg methods
  465. Revision 1.4 2002/03/31 20:26:34 jonas
  466. + a_loadfpu_* and a_loadmm_* methods in tcg
  467. * register allocation is now handled by a class and is mostly processor
  468. independent (+rgobj.pas and i386/rgcpu.pas)
  469. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  470. * some small improvements and fixes to the optimizer
  471. * some register allocation fixes
  472. * some fpuvaroffset fixes in the unary minus node
  473. * push/popusedregisters is now called rg.save/restoreusedregisters and
  474. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  475. also better optimizable)
  476. * fixed and optimized register saving/restoring for new/dispose nodes
  477. * LOC_FPU locations now also require their "register" field to be set to
  478. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  479. - list field removed of the tnode class because it's not used currently
  480. and can cause hard-to-find bugs
  481. }