ncgmem.pas 43 KB

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