ncgmem.pas 46 KB

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