ncgmem.pas 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for memory related nodes which are
  4. the same for all (most?) processors
  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 ncgmem;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,cgbase,cgutils,cpuinfo,cpubase,
  23. symtype,
  24. node,nmem;
  25. type
  26. tcgloadvmtaddrnode = class(tloadvmtaddrnode)
  27. procedure pass_generate_code;override;
  28. end;
  29. tcgloadparentfpnode = class(tloadparentfpnode)
  30. procedure pass_generate_code;override;
  31. end;
  32. tcgaddrnode = class(taddrnode)
  33. procedure pass_generate_code;override;
  34. end;
  35. tcgderefnode = class(tderefnode)
  36. procedure pass_generate_code;override;
  37. end;
  38. tcgsubscriptnode = class(tsubscriptnode)
  39. protected
  40. function handle_platform_subscript: boolean; virtual;
  41. public
  42. procedure pass_generate_code;override;
  43. end;
  44. tcgwithnode = class(twithnode)
  45. procedure pass_generate_code;override;
  46. end;
  47. tcgvecnode = class(tvecnode)
  48. function get_mul_size : aint;
  49. private
  50. procedure rangecheck_array;
  51. procedure rangecheck_string;
  52. protected
  53. {# This routine is used to calculate the address of the reference.
  54. On entry reg contains the index in the array,
  55. and l contains the size of each element in the array.
  56. This routine should update location.reference correctly,
  57. so it points to the correct address.
  58. }
  59. procedure update_reference_reg_mul(maybe_const_reg: tregister;regsize: tdef; l: aint);virtual;
  60. procedure update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l: aint);virtual;
  61. procedure update_reference_offset(var ref: treference; index, mulsize: aint); virtual;
  62. procedure second_wideansistring;virtual;
  63. procedure second_dynamicarray;virtual;
  64. public
  65. procedure pass_generate_code;override;
  66. end;
  67. implementation
  68. uses
  69. systems,
  70. cutils,cclasses,verbose,globals,constexp,
  71. symconst,symbase,symdef,symsym,symtable,defutil,paramgr,
  72. aasmbase,aasmtai,aasmdata,
  73. procinfo,pass_2,parabase,
  74. pass_1,nld,ncon,nadd,ncnv,nutils,
  75. cgobj,hlcgobj,
  76. tgobj,ncgutil,objcgutl,
  77. defcmp
  78. ;
  79. {*****************************************************************************
  80. TCGLOADVMTADDRNODE
  81. *****************************************************************************}
  82. procedure tcgloadvmtaddrnode.pass_generate_code;
  83. var
  84. href : treference;
  85. pool : THashSet;
  86. entry : PHashSetItem;
  87. begin
  88. location_reset(location,LOC_REGISTER,OS_ADDR);
  89. if (left.nodetype=typen) then
  90. begin
  91. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  92. if not is_objcclass(left.resultdef) then
  93. begin
  94. reference_reset_symbol(href,
  95. current_asmdata.RefAsmSymbol(tobjectdef(tclassrefdef(resultdef).pointeddef).vmt_mangledname,AT_DATA),0,
  96. sizeof(pint));
  97. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
  98. end
  99. else
  100. begin
  101. pool:=current_asmdata.ConstPools[sp_objcclassnamerefs];
  102. entry:=pool.FindOrAdd(@tobjectdef(left.resultdef).objextname^[1],length(tobjectdef(left.resultdef).objextname^));
  103. if (target_info.system in systems_objc_nfabi) then
  104. begin
  105. { find/add necessary classref/classname pool entries }
  106. objcfinishclassrefnfpoolentry(entry,tobjectdef(left.resultdef));
  107. end
  108. else
  109. begin
  110. { find/add necessary classref/classname pool entries }
  111. objcfinishstringrefpoolentry(entry,sp_objcclassnames,sec_objc_cls_refs,sec_objc_class_names);
  112. end;
  113. reference_reset_symbol(href,tasmlabel(entry^.Data),0,sizeof(pint));
  114. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,location.register);
  115. end;
  116. end
  117. else
  118. begin
  119. { left contains self, load vmt from self }
  120. secondpass(left);
  121. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(left.resultdef),left.location,location.register);
  122. end;
  123. end;
  124. {*****************************************************************************
  125. TCGLOADPARENTFPNODE
  126. *****************************************************************************}
  127. procedure tcgloadparentfpnode.pass_generate_code;
  128. var
  129. currpi : tprocinfo;
  130. hsym : tparavarsym;
  131. href : treference;
  132. begin
  133. if (current_procinfo.procdef.parast.symtablelevel=parentpd.parast.symtablelevel) then
  134. begin
  135. location_reset(location,LOC_REGISTER,OS_ADDR);
  136. location.register:=current_procinfo.framepointer;
  137. end
  138. else
  139. begin
  140. currpi:=current_procinfo;
  141. location_reset(location,LOC_REGISTER,OS_ADDR);
  142. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  143. { load framepointer of current proc }
  144. hsym:=tparavarsym(currpi.procdef.parast.Find('parentfp'));
  145. if not assigned(hsym) then
  146. internalerror(200309281);
  147. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,parentfpvoidpointertype,parentfpvoidpointertype,hsym.localloc,location.register);
  148. { walk parents }
  149. while (currpi.procdef.owner.symtablelevel>parentpd.parast.symtablelevel) do
  150. begin
  151. currpi:=currpi.parent;
  152. if not assigned(currpi) then
  153. internalerror(200311201);
  154. hsym:=tparavarsym(currpi.procdef.parast.Find('parentfp'));
  155. if not assigned(hsym) then
  156. internalerror(200309282);
  157. if hsym.localloc.loc<>LOC_REFERENCE then
  158. internalerror(200309283);
  159. reference_reset_base(href,location.register,hsym.localloc.reference.offset,sizeof(pint));
  160. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,location.register);
  161. end;
  162. end;
  163. end;
  164. {*****************************************************************************
  165. TCGADDRNODE
  166. *****************************************************************************}
  167. procedure tcgaddrnode.pass_generate_code;
  168. begin
  169. secondpass(left);
  170. location_reset(location,LOC_REGISTER,OS_ADDR);
  171. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  172. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  173. { on x86_64-win64, array of chars can be returned in registers, however,
  174. when passing these arrays to other functions, the compiler wants to take
  175. the address of the array so when the addrnode has been created internally,
  176. we have to force the data into memory, see also tw14388.pp
  177. }
  178. if nf_internal in flags then
  179. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef)
  180. else
  181. internalerror(2006111510);
  182. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,location.register);
  183. end;
  184. {*****************************************************************************
  185. TCGDEREFNODE
  186. *****************************************************************************}
  187. procedure tcgderefnode.pass_generate_code;
  188. var
  189. paraloc1 : tcgpara;
  190. pd : tprocdef;
  191. sym : tsym;
  192. st : tsymtable;
  193. hp : pnode;
  194. hp2 : tnode;
  195. extraoffset : tcgint;
  196. begin
  197. sym:=nil;
  198. { assume natural alignment, except for packed records }
  199. if not(resultdef.typ in [recorddef,objectdef]) or
  200. (tabstractrecordsymtable(tabstractrecorddef(resultdef).symtable).usefieldalignment<>1) then
  201. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),resultdef.alignment)
  202. else
  203. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),1);
  204. { can we fold an add/sub node into the offset of the deref node? }
  205. extraoffset:=0;
  206. hp:=actualtargetnode(@left);
  207. if (hp^.nodetype=subn) and is_constintnode(taddnode(hp^).right) then
  208. begin
  209. extraoffset:=-tcgint(tordconstnode(taddnode(hp^).right).value);
  210. replacenode(hp^,taddnode(hp^).left);
  211. end
  212. else if (hp^.nodetype=addn) and is_constintnode(taddnode(hp^).right) then
  213. begin
  214. extraoffset:=tcgint(tordconstnode(taddnode(hp^).right).value);
  215. replacenode(hp^,taddnode(hp^).left);
  216. end
  217. else if (hp^.nodetype=addn) and is_constintnode(taddnode(hp^).left) then
  218. begin
  219. extraoffset:=tcgint(tordconstnode(taddnode(hp^).left).value);
  220. replacenode(hp^,taddnode(hp^).right);
  221. end;
  222. secondpass(left);
  223. if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE,LOC_CONSTANT]) then
  224. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  225. case left.location.loc of
  226. LOC_CREGISTER,
  227. LOC_REGISTER:
  228. begin
  229. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
  230. {$ifdef cpu_uses_separate_address_registers}
  231. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  232. begin
  233. location.reference.base := cg.getaddressregister(current_asmdata.CurrAsmList);
  234. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,
  235. location.reference.base);
  236. end
  237. else
  238. {$endif}
  239. location.reference.base := left.location.register;
  240. end;
  241. LOC_CREFERENCE,
  242. LOC_REFERENCE:
  243. begin
  244. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  245. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,location.reference.base);
  246. end;
  247. LOC_CONSTANT:
  248. begin
  249. location.reference.offset:=left.location.value;
  250. end;
  251. else
  252. internalerror(200507031);
  253. end;
  254. location.reference.offset:=location.reference.offset+extraoffset;
  255. if (cs_use_heaptrc in current_settings.globalswitches) and
  256. (cs_checkpointer in current_settings.localswitches) and
  257. not(cs_compilesystem in current_settings.moduleswitches) and
  258. {$ifdef x86}
  259. (tpointerdef(left.resultdef).x86pointertyp = default_x86_data_pointer_type) and
  260. {$endif x86}
  261. not(nf_no_checkpointer in flags) and
  262. { can be NR_NO in case of LOC_CONSTANT }
  263. (location.reference.base<>NR_NO) then
  264. begin
  265. if not searchsym_in_named_module('HEAPTRC','CHECKPOINTER',sym,st) or
  266. (sym.typ<>procsym) then
  267. internalerror(2012010601);
  268. pd:=tprocdef(tprocsym(sym).ProcdefList[0]);
  269. paraloc1.init;
  270. paramanager.getintparaloc(pd,1,paraloc1);
  271. hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,resultdef,location.reference.base,paraloc1);
  272. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  273. paraloc1.done;
  274. hlcg.allocallcpuregisters(current_asmdata.CurrAsmList);
  275. hlcg.a_call_name(current_asmdata.CurrAsmList,pd,'FPC_CHECKPOINTER',[@paraloc1],nil,false);
  276. hlcg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  277. end;
  278. end;
  279. {*****************************************************************************
  280. TCGSUBSCRIPTNODE
  281. *****************************************************************************}
  282. function tcgsubscriptnode.handle_platform_subscript: boolean;
  283. begin
  284. result:=false;
  285. end;
  286. procedure tcgsubscriptnode.pass_generate_code;
  287. var
  288. asmsym: tasmsymbol;
  289. paraloc1 : tcgpara;
  290. tmpref: treference;
  291. sref: tsubsetreference;
  292. offsetcorrection : aint;
  293. pd : tprocdef;
  294. sym : tsym;
  295. st : tsymtable;
  296. begin
  297. sym:=nil;
  298. secondpass(left);
  299. if codegenerror then
  300. exit;
  301. paraloc1.init;
  302. { several object types must be dereferenced implicitly }
  303. if is_implicit_pointer_object_type(left.resultdef) then
  304. begin
  305. if (not is_managed_type(left.resultdef)) or
  306. (target_info.system in systems_garbage_collected_managed_types) then
  307. begin
  308. { the contents of a class are aligned to a sizeof(pointer) }
  309. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),sizeof(pint));
  310. case left.location.loc of
  311. LOC_CREGISTER,
  312. LOC_REGISTER:
  313. begin
  314. {$ifdef cpu_uses_separate_address_registers}
  315. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  316. begin
  317. location.reference.base:=rg.getaddressregister(current_asmdata.CurrAsmList);
  318. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,
  319. left.location.register,location.reference.base);
  320. end
  321. else
  322. {$endif}
  323. location.reference.base := left.location.register;
  324. end;
  325. LOC_CREFERENCE,
  326. LOC_REFERENCE,
  327. { tricky type casting of parameters can cause these locations, see tb0592.pp on x86_64-linux }
  328. LOC_SUBSETREG,
  329. LOC_CSUBSETREG,
  330. LOC_SUBSETREF,
  331. LOC_CSUBSETREF:
  332. begin
  333. location.reference.base:=hlcg.getaddressregister(current_asmdata.CurrAsmList,left.resultdef);
  334. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,location.reference.base);
  335. end;
  336. LOC_CONSTANT:
  337. begin
  338. { can happen with @classtype(pointerconst).field }
  339. location.reference.offset:=left.location.value;
  340. end;
  341. else
  342. internalerror(2009092401);
  343. end;
  344. { implicit deferencing }
  345. if (cs_use_heaptrc in current_settings.globalswitches) and
  346. (cs_checkpointer in current_settings.localswitches) and
  347. not(cs_compilesystem in current_settings.moduleswitches) then
  348. begin
  349. if not searchsym_in_named_module('HEAPTRC','CHECKPOINTER',sym,st) or
  350. (sym.typ<>procsym) then
  351. internalerror(2012010602);
  352. pd:=tprocdef(tprocsym(sym).ProcdefList[0]);
  353. paramanager.getintparaloc(pd,1,paraloc1);
  354. hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,resultdef,location.reference.base,paraloc1);
  355. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  356. hlcg.allocallcpuregisters(current_asmdata.CurrAsmList);
  357. hlcg.a_call_name(current_asmdata.CurrAsmList,pd,'FPC_CHECKPOINTER',[@paraloc1],nil,false);
  358. hlcg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  359. end;
  360. end
  361. else
  362. { reference-counted implicit pointer object types don't have
  363. fields -> cannot be subscripted (calls are handled via call
  364. nodes) }
  365. internalerror(2011011901);
  366. end
  367. else
  368. begin
  369. location_copy(location,left.location);
  370. { some abi's require that functions return (some) records in }
  371. { registers }
  372. case location.loc of
  373. LOC_REFERENCE,
  374. LOC_CREFERENCE:
  375. ;
  376. LOC_CONSTANT,
  377. LOC_REGISTER,
  378. LOC_CREGISTER,
  379. { if a floating point value is casted into a record, it
  380. can happen that we get here an fpu or mm register }
  381. LOC_MMREGISTER,
  382. LOC_FPUREGISTER,
  383. LOC_CMMREGISTER,
  384. LOC_CFPUREGISTER:
  385. begin
  386. { in case the result is not something that can be put
  387. into an integer register (e.g.
  388. function_returning_record().non_regable_field, or
  389. a function returning a value > sizeof(intreg))
  390. -> force to memory
  391. }
  392. if not tstoreddef(left.resultdef).is_intregable or
  393. not tstoreddef(resultdef).is_intregable or
  394. { if the field spans multiple registers, we must force the record into
  395. memory as well }
  396. ((left.location.size in [OS_PAIR,OS_SPAIR]) and
  397. (vs.fieldoffset div sizeof(aword)<>(vs.fieldoffset+vs.getsize-1) div sizeof(aword))) or
  398. (location.loc in [LOC_MMREGISTER,LOC_FPUREGISTER,LOC_CMMREGISTER,LOC_CFPUREGISTER,
  399. { actually, we should be able to "subscript" a constant, but this would require some code
  400. which enables dumping and reading constants from a temporary memory buffer. This
  401. must be done a CPU dependent way, so it is not easy and probably not worth the effort (FK)
  402. }
  403. LOC_CONSTANT]) then
  404. hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef)
  405. else
  406. begin
  407. if (left.location.loc = LOC_REGISTER) then
  408. location.loc := LOC_SUBSETREG
  409. else
  410. location.loc := LOC_CSUBSETREG;
  411. location.size:=def_cgsize(resultdef);
  412. offsetcorrection:=0;
  413. if (left.location.size in [OS_PAIR,OS_SPAIR]) then
  414. begin
  415. if (vs.fieldoffset>=sizeof(aword)) then
  416. begin
  417. location.sreg.subsetreg := left.location.registerhi;
  418. offsetcorrection:=sizeof(aword)*8;
  419. end
  420. else
  421. location.sreg.subsetreg := left.location.register;
  422. location.sreg.subsetregsize := OS_INT;
  423. end
  424. else
  425. begin
  426. location.sreg.subsetreg := left.location.register;
  427. location.sreg.subsetregsize := left.location.size;
  428. end;
  429. if not is_packed_record_or_object(left.resultdef) then
  430. begin
  431. if (target_info.endian = ENDIAN_BIG) then
  432. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8+offsetcorrection
  433. else
  434. location.sreg.startbit := (vs.fieldoffset * 8)-offsetcorrection;
  435. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  436. end
  437. else
  438. begin
  439. location.sreg.bitlen := resultdef.packedbitsize;
  440. if (target_info.endian = ENDIAN_BIG) then
  441. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset+offsetcorrection
  442. else
  443. location.sreg.startbit := vs.fieldoffset-offsetcorrection;
  444. end;
  445. end;
  446. end;
  447. LOC_SUBSETREG,
  448. LOC_CSUBSETREG:
  449. begin
  450. location.size:=def_cgsize(resultdef);
  451. if not is_packed_record_or_object(left.resultdef) then
  452. begin
  453. if (target_info.endian = ENDIAN_BIG) then
  454. inc(location.sreg.startbit, (left.resultdef.size - tcgsize2size[location.size] - vs.fieldoffset) * 8)
  455. else
  456. inc(location.sreg.startbit, vs.fieldoffset * 8);
  457. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  458. end
  459. else
  460. begin
  461. location.sreg.bitlen := resultdef.packedbitsize;
  462. if (target_info.endian = ENDIAN_BIG) then
  463. inc(location.sreg.startbit, left.location.sreg.bitlen - location.sreg.bitlen - vs.fieldoffset)
  464. else
  465. inc(location.sreg.startbit, vs.fieldoffset);
  466. end;
  467. end;
  468. else
  469. internalerror(2006031901);
  470. end;
  471. end;
  472. if is_objc_class_or_protocol(left.resultdef) and
  473. (target_info.system in systems_objc_nfabi) then
  474. begin
  475. if (location.loc<>LOC_REFERENCE) or
  476. (location.reference.index<>NR_NO) then
  477. internalerror(2009092402);
  478. { the actual field offset is stored in memory (to solve the
  479. "fragile base class" problem: this way the layout of base
  480. classes can be changed without breaking programs compiled against
  481. earlier versions)
  482. }
  483. asmsym:=current_asmdata.RefAsmSymbol(vs.mangledname);
  484. reference_reset_symbol(tmpref,asmsym,0,sizeof(pint));
  485. location.reference.index:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
  486. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ptruinttype,ptruinttype,tmpref,location.reference.index);
  487. { always packrecords C -> natural alignment }
  488. location.reference.alignment:=vs.vardef.alignment;
  489. end
  490. else if handle_platform_subscript then
  491. begin
  492. { done }
  493. end
  494. else if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  495. begin
  496. if not is_packed_record_or_object(left.resultdef) then
  497. begin
  498. inc(location.reference.offset,vs.fieldoffset);
  499. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset);
  500. end
  501. else if (vs.fieldoffset mod 8 = 0) and
  502. (resultdef.packedbitsize mod 8 = 0) and
  503. { is different in case of e.g. packenum 2 and an enum }
  504. { which fits in 8 bits }
  505. (resultdef.size*8 = resultdef.packedbitsize) then
  506. begin
  507. inc(location.reference.offset,vs.fieldoffset div 8);
  508. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset div 8);
  509. end
  510. else
  511. begin
  512. sref.ref:=location.reference;
  513. sref.ref.alignment:=1;
  514. sref.bitindexreg:=NR_NO;
  515. inc(sref.ref.offset,vs.fieldoffset div 8);
  516. sref.startbit:=vs.fieldoffset mod 8;
  517. sref.bitlen:=resultdef.packedbitsize;
  518. if (left.location.loc=LOC_REFERENCE) then
  519. location.loc:=LOC_SUBSETREF
  520. else
  521. location.loc:=LOC_CSUBSETREF;
  522. location.sref:=sref;
  523. end;
  524. { also update the size of the location }
  525. location.size:=def_cgsize(resultdef);
  526. end;
  527. paraloc1.done;
  528. end;
  529. {*****************************************************************************
  530. TCGWITHNODE
  531. *****************************************************************************}
  532. procedure tcgwithnode.pass_generate_code;
  533. begin
  534. location_reset(location,LOC_VOID,OS_NO);
  535. if assigned(left) then
  536. secondpass(left);
  537. end;
  538. {*****************************************************************************
  539. TCGVECNODE
  540. *****************************************************************************}
  541. function tcgvecnode.get_mul_size : aint;
  542. begin
  543. if nf_memindex in flags then
  544. get_mul_size:=1
  545. else
  546. begin
  547. if (left.resultdef.typ=arraydef) then
  548. if not is_packed_array(left.resultdef) then
  549. get_mul_size:=tarraydef(left.resultdef).elesize
  550. else
  551. get_mul_size:=tarraydef(left.resultdef).elepackedbitsize
  552. else
  553. get_mul_size:=resultdef.size;
  554. end
  555. end;
  556. { this routine must, like any other routine, not change the contents }
  557. { of base/index registers of references, as these may be regvars. }
  558. { The register allocator can coalesce one LOC_REGISTER being moved }
  559. { into another (as their live ranges won't overlap), but not a }
  560. { LOC_CREGISTER moved into a LOC_(C)REGISTER most of the time (as }
  561. { the live range of the LOC_CREGISTER will most likely overlap the }
  562. { the live range of the target LOC_(C)REGISTER) }
  563. { The passed register may be a LOC_CREGISTER as well. }
  564. procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);
  565. var
  566. hreg: tregister;
  567. begin
  568. if l<>1 then
  569. begin
  570. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  571. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,maybe_const_reg,hreg);
  572. maybe_const_reg:=hreg;
  573. end;
  574. if location.reference.base=NR_NO then
  575. location.reference.base:=maybe_const_reg
  576. else if location.reference.index=NR_NO then
  577. location.reference.index:=maybe_const_reg
  578. else
  579. begin
  580. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  581. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
  582. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  583. { insert new index register }
  584. location.reference.index:=maybe_const_reg;
  585. end;
  586. { update alignment }
  587. if (location.reference.alignment=0) then
  588. internalerror(2009020704);
  589. location.reference.alignment:=newalignment(location.reference.alignment,l);
  590. end;
  591. { see remarks for tcgvecnode.update_reference_reg_mul above }
  592. procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l:aint);
  593. var
  594. sref: tsubsetreference;
  595. offsetreg, hreg: tregister;
  596. alignpower: aint;
  597. temp : longint;
  598. begin
  599. { only orddefs are bitpacked. Even then we only need special code in }
  600. { case the bitpacked *byte size* is not a power of two, otherwise }
  601. { everything can be handled using the the regular array code. }
  602. if ((l mod 8) = 0) and
  603. (ispowerof2(l div 8,temp) or
  604. not is_ordinal(resultdef)
  605. {$ifndef cpu64bitalu}
  606. or is_64bitint(resultdef)
  607. {$endif not cpu64bitalu}
  608. ) then
  609. begin
  610. update_reference_reg_mul(maybe_const_reg,regsize,l div 8);
  611. exit;
  612. end;
  613. if (l > 8*sizeof(aint)) then
  614. internalerror(200608051);
  615. sref.ref := location.reference;
  616. hreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  617. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
  618. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg);
  619. { keep alignment for index }
  620. sref.ref.alignment := left.resultdef.alignment;
  621. if not ispowerof2(packedbitsloadsize(l),temp) then
  622. internalerror(2006081201);
  623. alignpower:=temp;
  624. offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  625. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,hreg,offsetreg);
  626. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
  627. if (sref.ref.base = NR_NO) then
  628. sref.ref.base := offsetreg
  629. else if (sref.ref.index = NR_NO) then
  630. sref.ref.index := offsetreg
  631. else
  632. begin
  633. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
  634. sref.ref.base := offsetreg;
  635. end;
  636. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,hreg);
  637. sref.bitindexreg := hreg;
  638. sref.startbit := 0;
  639. sref.bitlen := resultdef.packedbitsize;
  640. if (left.location.loc = LOC_REFERENCE) then
  641. location.loc := LOC_SUBSETREF
  642. else
  643. location.loc := LOC_CSUBSETREF;
  644. location.sref := sref;
  645. end;
  646. procedure tcgvecnode.update_reference_offset(var ref: treference; index, mulsize: aint);
  647. begin
  648. inc(ref.offset,index*mulsize);
  649. end;
  650. procedure tcgvecnode.second_wideansistring;
  651. begin
  652. end;
  653. procedure tcgvecnode.second_dynamicarray;
  654. begin
  655. end;
  656. procedure tcgvecnode.rangecheck_array;
  657. var
  658. hightree : tnode;
  659. poslabel,
  660. neglabel : tasmlabel;
  661. hreg : tregister;
  662. paraloc1,paraloc2 : tcgpara;
  663. pd : tprocdef;
  664. begin
  665. { omit range checking when this is an array access to a pointer which has been
  666. typecasted from an array }
  667. if (ado_isconvertedpointer in tarraydef(left.resultdef).arrayoptions) then
  668. exit;
  669. paraloc1.init;
  670. paraloc2.init;
  671. if is_open_array(left.resultdef) or
  672. is_array_of_const(left.resultdef) then
  673. begin
  674. { cdecl functions don't have high() so we can not check the range }
  675. { (can't use current_procdef, since it may be a nested procedure) }
  676. if not(tprocdef(tparasymtable(tparavarsym(tloadnode(left).symtableentry).owner).defowner).proccalloption in cdecl_pocalls) then
  677. begin
  678. { Get high value }
  679. hightree:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry));
  680. { it must be available }
  681. if not assigned(hightree) then
  682. internalerror(200212201);
  683. firstpass(hightree);
  684. secondpass(hightree);
  685. { generate compares }
  686. if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  687. hreg:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_INT)
  688. else
  689. begin
  690. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  691. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,hreg);
  692. end;
  693. current_asmdata.getjumplabel(neglabel);
  694. current_asmdata.getjumplabel(poslabel);
  695. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_LT,0,hreg,poslabel);
  696. cg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_BE,hightree.location,hreg,neglabel);
  697. cg.a_label(current_asmdata.CurrAsmList,poslabel);
  698. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_RANGEERROR',false);
  699. cg.a_label(current_asmdata.CurrAsmList,neglabel);
  700. { release hightree }
  701. hightree.free;
  702. end;
  703. end
  704. else
  705. if is_dynamic_array(left.resultdef) then
  706. begin
  707. pd:=search_system_proc('fpc_dynarray_rangecheck');
  708. paramanager.getintparaloc(pd,1,paraloc1);
  709. paramanager.getintparaloc(pd,2,paraloc2);
  710. if pd.is_pushleftright then
  711. begin
  712. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  713. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  714. end
  715. else
  716. begin
  717. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  718. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  719. end;
  720. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  721. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  722. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  723. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DYNARRAY_RANGECHECK',false);
  724. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  725. end;
  726. { for regular arrays, we don't have to do anything because the index has been
  727. type converted to the index type, which already inserted a range check if
  728. necessary }
  729. paraloc1.done;
  730. paraloc2.done;
  731. end;
  732. procedure tcgvecnode.rangecheck_string;
  733. var
  734. paraloc1,
  735. paraloc2: tcgpara;
  736. helpername: TIDString;
  737. pd: tprocdef;
  738. begin
  739. paraloc1.init;
  740. paraloc2.init;
  741. case tstringdef(left.resultdef).stringtype of
  742. { it's the same for ansi- and wide strings }
  743. st_unicodestring,
  744. st_widestring,
  745. st_ansistring:
  746. begin
  747. helpername:='fpc_'+tstringdef(left.resultdef).stringtypname+'_rangecheck';
  748. pd:=search_system_proc(helpername);
  749. paramanager.getintparaloc(pd,1,paraloc1);
  750. paramanager.getintparaloc(pd,2,paraloc2);
  751. if pd.is_pushleftright then
  752. begin
  753. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  754. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  755. end
  756. else
  757. begin
  758. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  759. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  760. end;
  761. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  762. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  763. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  764. cg.a_call_name(current_asmdata.CurrAsmList,helpername,false);
  765. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  766. end;
  767. st_shortstring:
  768. begin
  769. {!!!!!!!!!!!!!!!!!}
  770. { if this one is implemented making use of the high parameter for openshortstrings, update ncgutils.do_get_used_regvars() too (JM) }
  771. end;
  772. st_longstring:
  773. begin
  774. {!!!!!!!!!!!!!!!!!}
  775. end;
  776. end;
  777. paraloc1.done;
  778. paraloc2.done;
  779. end;
  780. procedure tcgvecnode.pass_generate_code;
  781. var
  782. offsetdec,
  783. extraoffset : aint;
  784. rightp : pnode;
  785. otl,ofl : tasmlabel;
  786. newsize : tcgsize;
  787. mulsize,
  788. bytemulsize,
  789. alignpow : aint;
  790. isjump : boolean;
  791. paraloc1,
  792. paraloc2 : tcgpara;
  793. subsetref : tsubsetreference;
  794. temp : longint;
  795. begin
  796. paraloc1.init;
  797. paraloc2.init;
  798. mulsize:=get_mul_size;
  799. if not is_packed_array(left.resultdef) then
  800. bytemulsize:=mulsize
  801. else
  802. bytemulsize:=mulsize div 8;
  803. newsize:=def_cgsize(resultdef);
  804. secondpass(left);
  805. if left.location.loc=LOC_CREFERENCE then
  806. location_reset_ref(location,LOC_CREFERENCE,newsize,left.location.reference.alignment)
  807. else
  808. location_reset_ref(location,LOC_REFERENCE,newsize,left.location.reference.alignment);
  809. { an ansistring needs to be dereferenced }
  810. if is_ansistring(left.resultdef) or
  811. is_wide_or_unicode_string(left.resultdef) then
  812. begin
  813. if nf_callunique in flags then
  814. internalerror(200304236);
  815. {DM!!!!!}
  816. case left.location.loc of
  817. LOC_REGISTER,
  818. LOC_CREGISTER :
  819. begin
  820. {$ifdef m68k}
  821. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  822. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,location.reference.base);
  823. {$else m68k}
  824. location.reference.base:=left.location.register;
  825. {$endif m68k}
  826. end;
  827. LOC_CREFERENCE,
  828. LOC_REFERENCE :
  829. begin
  830. location.reference.base:=hlcg.getaddressregister(current_asmdata.CurrAsmList,left.resultdef);
  831. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location.reference,location.reference.base);
  832. end;
  833. else
  834. internalerror(2002032218);
  835. end;
  836. if is_ansistring(left.resultdef) then
  837. offsetdec:=1
  838. else
  839. offsetdec:=2;
  840. location.reference.alignment:=offsetdec;
  841. { in ansistrings/widestrings S[1] is p<w>char(S)[0] }
  842. if not(cs_zerobasedstrings in current_settings.localswitches) then
  843. update_reference_offset(location.reference,-1,offsetdec);
  844. end
  845. else if is_dynamic_array(left.resultdef) then
  846. begin
  847. case left.location.loc of
  848. LOC_REGISTER,
  849. LOC_CREGISTER :
  850. location.reference.base:=left.location.register;
  851. LOC_REFERENCE,
  852. LOC_CREFERENCE :
  853. begin
  854. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  855. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,
  856. left.location.reference,location.reference.base);
  857. end;
  858. else
  859. internalerror(2002032219);
  860. end;
  861. { a dynarray points to the start of a memory block, which
  862. we assume to be always aligned to a multiple of the
  863. pointer size
  864. }
  865. location.reference.alignment:=sizeof(pint);
  866. end
  867. else
  868. begin
  869. { may happen in case of function results }
  870. case left.location.loc of
  871. LOC_CREGISTER,
  872. LOC_CMMREGISTER,
  873. LOC_REGISTER,
  874. LOC_MMREGISTER:
  875. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  876. end;
  877. location_copy(location,left.location);
  878. end;
  879. { location must be memory }
  880. if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  881. internalerror(200411013);
  882. { offset can only differ from 0 if arraydef }
  883. if (left.resultdef.typ=arraydef) and
  884. not(is_dynamic_array(left.resultdef)) and
  885. (not(is_packed_array(left.resultdef)) or
  886. ((mulsize mod 8 = 0) and
  887. ispowerof2(mulsize div 8,temp)) or
  888. { only orddefs are bitpacked }
  889. not is_ordinal(resultdef)
  890. {$ifndef cpu64bitalu}
  891. or is_64bitint(resultdef)
  892. {$endif not cpu64bitalu}
  893. ) then
  894. update_reference_offset(location.reference,-tarraydef(left.resultdef).lowrange,bytemulsize);
  895. if right.nodetype=ordconstn then
  896. begin
  897. { offset can only differ from 0 if arraydef }
  898. if cs_check_range in current_settings.localswitches then
  899. begin
  900. secondpass(right);
  901. case left.resultdef.typ of
  902. arraydef :
  903. rangecheck_array;
  904. stringdef :
  905. rangecheck_string;
  906. end;
  907. end;
  908. if not(is_packed_array(left.resultdef)) or
  909. ((mulsize mod 8 = 0) and
  910. (ispowerof2(mulsize div 8,temp) or
  911. { only orddefs are bitpacked }
  912. not is_ordinal(resultdef))) then
  913. begin
  914. extraoffset:=tordconstnode(right).value.svalue;
  915. update_reference_offset(location.reference,extraoffset,bytemulsize);
  916. { adjust alignment after this change }
  917. location.reference.alignment:=newalignment(location.reference.alignment,extraoffset*bytemulsize);
  918. { don't do this for floats etc.; needed to properly set the }
  919. { size for bitpacked arrays (e.g. a bitpacked array of }
  920. { enums who are size 2 but fit in one byte -> in the array }
  921. { they will be one byte and have to be stored like that) }
  922. if is_packed_array(left.resultdef) and
  923. (tcgsize2size[newsize] <> bytemulsize) then
  924. newsize:=int_cgsize(bytemulsize);
  925. end
  926. else
  927. begin
  928. subsetref.ref := location.reference;
  929. subsetref.ref.alignment := left.resultdef.alignment;
  930. if not ispowerof2(packedbitsloadsize(resultdef.packedbitsize),temp) then
  931. internalerror(2006081212);
  932. alignpow:=temp;
  933. update_reference_offset(subsetref.ref,(mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow),1 shl alignpow);
  934. subsetref.bitindexreg := NR_NO;
  935. subsetref.startbit := (mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) and ((1 shl (3+alignpow))-1);
  936. subsetref.bitlen := resultdef.packedbitsize;
  937. if (left.location.loc = LOC_REFERENCE) then
  938. location.loc := LOC_SUBSETREF
  939. else
  940. location.loc := LOC_CSUBSETREF;
  941. location.sref := subsetref;
  942. end;
  943. end
  944. else
  945. { not nodetype=ordconstn }
  946. begin
  947. if (cs_opt_level1 in current_settings.optimizerswitches) and
  948. { if we do range checking, we don't }
  949. { need that fancy code (it would be }
  950. { buggy) }
  951. not(cs_check_range in current_settings.localswitches) and
  952. (left.resultdef.typ=arraydef) and
  953. not is_packed_array(left.resultdef) then
  954. begin
  955. extraoffset:=0;
  956. rightp:=actualtargetnode(@right);
  957. if rightp^.nodetype=addn then
  958. begin
  959. if taddnode(rightp^).right.nodetype=ordconstn then
  960. begin
  961. extraoffset:=tordconstnode(taddnode(rightp^).right).value.svalue;
  962. replacenode(rightp^,taddnode(rightp^).left);
  963. end
  964. else if taddnode(rightp^).left.nodetype=ordconstn then
  965. begin
  966. extraoffset:=tordconstnode(taddnode(rightp^).left).value.svalue;
  967. replacenode(rightp^,taddnode(rightp^).right);
  968. end;
  969. end
  970. else if rightp^.nodetype=subn then
  971. begin
  972. if taddnode(rightp^).right.nodetype=ordconstn then
  973. begin
  974. extraoffset:=-tordconstnode(taddnode(rightp^).right).value.svalue;
  975. replacenode(rightp^,taddnode(rightp^).left);
  976. end;
  977. end;
  978. update_reference_offset(location.reference,extraoffset,mulsize);
  979. end;
  980. { calculate from left to right }
  981. if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  982. internalerror(200304237);
  983. isjump:=(right.expectloc=LOC_JUMP);
  984. otl:=nil;
  985. ofl:=nil;
  986. if isjump then
  987. begin
  988. otl:=current_procinfo.CurrTrueLabel;
  989. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  990. ofl:=current_procinfo.CurrFalseLabel;
  991. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  992. end;
  993. secondpass(right);
  994. { if mulsize = 1, we won't have to modify the index }
  995. if not(right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or (right.location.size<>OS_ADDR) then
  996. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,ptruinttype,true);
  997. if isjump then
  998. begin
  999. current_procinfo.CurrTrueLabel:=otl;
  1000. current_procinfo.CurrFalseLabel:=ofl;
  1001. end
  1002. else if (right.location.loc = LOC_JUMP) then
  1003. internalerror(2006010801);
  1004. { produce possible range check code: }
  1005. if cs_check_range in current_settings.localswitches then
  1006. begin
  1007. if left.resultdef.typ=arraydef then
  1008. rangecheck_array
  1009. else if (left.resultdef.typ=stringdef) then
  1010. rangecheck_string;
  1011. end;
  1012. { insert the register and the multiplication factor in the
  1013. reference }
  1014. if not is_packed_array(left.resultdef) then
  1015. update_reference_reg_mul(right.location.register,right.resultdef,mulsize)
  1016. else
  1017. update_reference_reg_packed(right.location.register,right.resultdef,mulsize);
  1018. end;
  1019. location.size:=newsize;
  1020. paraloc1.done;
  1021. paraloc2.done;
  1022. end;
  1023. begin
  1024. cloadvmtaddrnode:=tcgloadvmtaddrnode;
  1025. cloadparentfpnode:=tcgloadparentfpnode;
  1026. caddrnode:=tcgaddrnode;
  1027. cderefnode:=tcgderefnode;
  1028. csubscriptnode:=tcgsubscriptnode;
  1029. cwithnode:=tcgwithnode;
  1030. cvecnode:=tcgvecnode;
  1031. end.