ncgmem.pas 47 KB

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