ncgmem.pas 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  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. protected
  48. {# This routine is used to calculate the address of the reference.
  49. On entry reg contains the index in the array,
  50. and l contains the size of each element in the array.
  51. This routine should update location.reference correctly,
  52. so it points to the correct address.
  53. }
  54. procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);virtual;
  55. procedure update_reference_reg_packed(maybe_const_reg:tregister;l:aint);virtual;
  56. procedure second_wideansistring;virtual;
  57. procedure second_dynamicarray;virtual;
  58. public
  59. procedure pass_generate_code;override;
  60. end;
  61. implementation
  62. uses
  63. systems,
  64. cutils,cclasses,verbose,globals,constexp,
  65. symconst,symdef,symsym,symtable,defutil,paramgr,
  66. aasmbase,aasmtai,aasmdata,
  67. procinfo,pass_2,parabase,
  68. pass_1,nld,ncon,nadd,nutils,
  69. cgutils,cgobj,
  70. tgobj,ncgutil,objcgutl
  71. ;
  72. {*****************************************************************************
  73. TCGLOADVMTADDRNODE
  74. *****************************************************************************}
  75. procedure tcgloadvmtaddrnode.pass_generate_code;
  76. var
  77. href : treference;
  78. pool : THashSet;
  79. entry : PHashSetItem;
  80. begin
  81. location_reset(location,LOC_REGISTER,OS_ADDR);
  82. if (left.nodetype=typen) then
  83. begin
  84. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  85. if not is_objcclass(left.resultdef) then
  86. begin
  87. reference_reset_symbol(href,
  88. current_asmdata.RefAsmSymbol(tobjectdef(tclassrefdef(resultdef).pointeddef).vmt_mangledname),0,
  89. sizeof(pint));
  90. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
  91. end
  92. else
  93. begin
  94. if current_asmdata.ConstPools[sp_objcclassnamerefs]=nil then
  95. current_asmdata.ConstPools[sp_objcclassnamerefs]:=THashSet.Create(64, True, False);
  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 system_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. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,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. internalerror(2006111510);
  169. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,location.register);
  170. end;
  171. {*****************************************************************************
  172. TCGDEREFNODE
  173. *****************************************************************************}
  174. procedure tcgderefnode.pass_generate_code;
  175. var
  176. paraloc1 : tcgpara;
  177. begin
  178. secondpass(left);
  179. { assume natural alignment, except for packed records }
  180. if not(resultdef.typ in [recorddef,objectdef]) or
  181. (tabstractrecordsymtable(tabstractrecorddef(resultdef).symtable).usefieldalignment<>1) then
  182. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),resultdef.alignment)
  183. else
  184. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),1);
  185. case left.location.loc of
  186. LOC_CREGISTER,
  187. LOC_REGISTER:
  188. begin
  189. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
  190. {$ifdef cpu_uses_separate_address_registers}
  191. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  192. begin
  193. location.reference.base := cg.getaddressregister(current_asmdata.CurrAsmList);
  194. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,
  195. location.reference.base);
  196. end
  197. else
  198. {$endif}
  199. location.reference.base := left.location.register;
  200. end;
  201. LOC_CREFERENCE,
  202. LOC_REFERENCE:
  203. begin
  204. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  205. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference.base);
  206. end;
  207. LOC_CONSTANT:
  208. begin
  209. location.reference.offset:=left.location.value;
  210. end;
  211. else
  212. internalerror(200507031);
  213. end;
  214. if (cs_use_heaptrc in current_settings.globalswitches) and
  215. (cs_checkpointer in current_settings.localswitches) and
  216. not(cs_compilesystem in current_settings.moduleswitches) and
  217. not(tpointerdef(left.resultdef).is_far) and
  218. not(nf_no_checkpointer in flags) and
  219. { can be NR_NO in case of LOC_CONSTANT }
  220. (location.reference.base<>NR_NO) then
  221. begin
  222. paraloc1.init;
  223. paramanager.getintparaloc(pocall_default,1,paraloc1);
  224. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  225. cg.a_param_reg(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  226. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  227. paraloc1.done;
  228. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  229. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER',false);
  230. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  231. end;
  232. end;
  233. {*****************************************************************************
  234. TCGSUBSCRIPTNODE
  235. *****************************************************************************}
  236. procedure tcgsubscriptnode.pass_generate_code;
  237. var
  238. sym: tasmsymbol;
  239. paraloc1 : tcgpara;
  240. hreg : tregister;
  241. tmpref: treference;
  242. sref: tsubsetreference;
  243. begin
  244. secondpass(left);
  245. if codegenerror then
  246. exit;
  247. paraloc1.init;
  248. { classes and interfaces must be dereferenced implicitly }
  249. if is_class_or_interface_or_objc(left.resultdef) then
  250. begin
  251. { the contents of a class are aligned to a sizeof(pointer) }
  252. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),sizeof(pint));
  253. case left.location.loc of
  254. LOC_CREGISTER,
  255. LOC_REGISTER:
  256. begin
  257. {$ifdef cpu_uses_separate_address_registers}
  258. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  259. begin
  260. location.reference.base:=rg.getaddressregister(current_asmdata.CurrAsmList);
  261. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  262. left.location.register,location.reference.base);
  263. end
  264. else
  265. {$endif}
  266. location.reference.base := left.location.register;
  267. end;
  268. LOC_CREFERENCE,
  269. LOC_REFERENCE:
  270. begin
  271. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  272. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference.base);
  273. end;
  274. else
  275. internalerror(2009092401);
  276. end;
  277. { implicit deferencing }
  278. if (cs_use_heaptrc in current_settings.globalswitches) and
  279. (cs_checkpointer in current_settings.localswitches) and
  280. not(cs_compilesystem in current_settings.moduleswitches) then
  281. begin
  282. paramanager.getintparaloc(pocall_default,1,paraloc1);
  283. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  284. cg.a_param_reg(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  285. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  286. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  287. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER',false);
  288. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  289. end;
  290. end
  291. else if is_interfacecom(left.resultdef) then
  292. begin
  293. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),sizeof(pint));
  294. tg.GetTempTyped(current_asmdata.CurrAsmList,left.resultdef,tt_normal,location.reference);
  295. cg.a_load_loc_ref(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference);
  296. { implicit deferencing also for interfaces }
  297. if (cs_use_heaptrc in current_settings.globalswitches) and
  298. (cs_checkpointer in current_settings.localswitches) and
  299. not(cs_compilesystem in current_settings.moduleswitches) then
  300. begin
  301. paramanager.getintparaloc(pocall_default,1,paraloc1);
  302. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  303. cg.a_param_reg(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  304. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  305. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  306. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER',false);
  307. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  308. end;
  309. end
  310. else
  311. begin
  312. location_copy(location,left.location);
  313. { some abi's require that functions return (some) records in }
  314. { registers }
  315. case location.loc of
  316. LOC_REFERENCE,
  317. LOC_CREFERENCE:
  318. ;
  319. LOC_REGISTER,
  320. LOC_CREGISTER:
  321. begin
  322. if (left.resultdef.size > sizeof(pint)) then
  323. location_force_mem(current_asmdata.CurrAsmList,location)
  324. else
  325. begin
  326. if (left.location.loc = LOC_REGISTER) then
  327. location.loc := LOC_SUBSETREG
  328. else
  329. location.loc := LOC_CSUBSETREG;
  330. location.size:=def_cgsize(resultdef);
  331. location.sreg.subsetreg := left.location.register;
  332. location.sreg.subsetregsize := left.location.size;
  333. if not is_packed_record_or_object(left.resultdef) then
  334. begin
  335. if (target_info.endian = ENDIAN_BIG) then
  336. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8
  337. else
  338. location.sreg.startbit := (vs.fieldoffset * 8);
  339. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  340. end
  341. else
  342. begin
  343. location.sreg.bitlen := resultdef.packedbitsize;
  344. if (target_info.endian = ENDIAN_BIG) then
  345. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset
  346. else
  347. location.sreg.startbit := vs.fieldoffset;
  348. end;
  349. end;
  350. end;
  351. LOC_SUBSETREG,
  352. LOC_CSUBSETREG:
  353. begin
  354. location.size:=def_cgsize(resultdef);
  355. if not is_packed_record_or_object(left.resultdef) then
  356. begin
  357. if (target_info.endian = ENDIAN_BIG) then
  358. inc(location.sreg.startbit, (left.resultdef.size - tcgsize2size[location.size] - vs.fieldoffset) * 8)
  359. else
  360. inc(location.sreg.startbit, vs.fieldoffset * 8);
  361. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  362. end
  363. else
  364. begin
  365. location.sreg.bitlen := resultdef.packedbitsize;
  366. if (target_info.endian = ENDIAN_BIG) then
  367. inc(location.sreg.startbit, left.location.sreg.bitlen - location.sreg.bitlen - vs.fieldoffset)
  368. else
  369. inc(location.sreg.startbit, vs.fieldoffset);
  370. end;
  371. end;
  372. else
  373. internalerror(2006031901);
  374. end;
  375. end;
  376. if is_objc_class_or_protocol(left.resultdef) and
  377. (target_info.system in system_objc_nfabi) then
  378. begin
  379. if (location.loc<>LOC_REFERENCE) or
  380. (location.reference.index<>NR_NO) then
  381. internalerror(2009092402);
  382. { the actual field offset is stored in memory (to solve the
  383. "fragile base class" problem: this way the layout of base
  384. classes can be changed without breaking programs compiled against
  385. earlier versions)
  386. }
  387. hreg:=cg.g_indirect_sym_load(current_asmdata.CurrAsmList,vs.mangledname,false);
  388. { TODO: clean up. g_indirect_sym_load cannot perform
  389. a plain load for targets that don't need an indirect load
  390. because it's also used in ncgld, but this is not very nice...
  391. }
  392. if (hreg=NR_NO) then
  393. begin
  394. sym:=current_asmdata.RefAsmSymbol(vs.mangledname);
  395. reference_reset_symbol(tmpref,sym,0,sizeof(pint));
  396. location.reference.index:=cg.getaddressregister(current_asmdata.CurrAsmList);
  397. end
  398. else
  399. begin
  400. reference_reset_base(tmpref,hreg,0,sizeof(pint));
  401. location.reference.index:=hreg;
  402. end;
  403. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,location.reference.index);
  404. { always packrecords C -> natural alignment }
  405. location.reference.alignment:=vs.vardef.alignment;
  406. end
  407. else if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  408. begin
  409. if not is_packed_record_or_object(left.resultdef) then
  410. begin
  411. inc(location.reference.offset,vs.fieldoffset);
  412. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset);
  413. end
  414. else if (vs.fieldoffset mod 8 = 0) and
  415. (resultdef.packedbitsize mod 8 = 0) and
  416. { is different in case of e.g. packenum 2 and an enum }
  417. { which fits in 8 bits }
  418. (resultdef.size*8 = resultdef.packedbitsize) then
  419. begin
  420. inc(location.reference.offset,vs.fieldoffset div 8);
  421. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset div 8);
  422. end
  423. else
  424. begin
  425. sref.ref:=location.reference;
  426. sref.ref.alignment:=1;
  427. sref.bitindexreg:=NR_NO;
  428. inc(sref.ref.offset,vs.fieldoffset div 8);
  429. sref.startbit:=vs.fieldoffset mod 8;
  430. sref.bitlen:=resultdef.packedbitsize;
  431. if (left.location.loc=LOC_REFERENCE) then
  432. location.loc:=LOC_SUBSETREF
  433. else
  434. location.loc:=LOC_CSUBSETREF;
  435. location.sref:=sref;
  436. end;
  437. { also update the size of the location }
  438. location.size:=def_cgsize(resultdef);
  439. end;
  440. paraloc1.done;
  441. end;
  442. {*****************************************************************************
  443. TCGWITHNODE
  444. *****************************************************************************}
  445. procedure tcgwithnode.pass_generate_code;
  446. begin
  447. location_reset(location,LOC_VOID,OS_NO);
  448. if assigned(left) then
  449. secondpass(left);
  450. end;
  451. {*****************************************************************************
  452. TCGVECNODE
  453. *****************************************************************************}
  454. function tcgvecnode.get_mul_size : aint;
  455. begin
  456. if nf_memindex in flags then
  457. get_mul_size:=1
  458. else
  459. begin
  460. if (left.resultdef.typ=arraydef) then
  461. if not is_packed_array(left.resultdef) then
  462. get_mul_size:=tarraydef(left.resultdef).elesize
  463. else
  464. get_mul_size:=tarraydef(left.resultdef).elepackedbitsize
  465. else
  466. get_mul_size:=resultdef.size;
  467. end
  468. end;
  469. { this routine must, like any other routine, not change the contents }
  470. { of base/index registers of references, as these may be regvars. }
  471. { The register allocator can coalesce one LOC_REGISTER being moved }
  472. { into another (as their live ranges won't overlap), but not a }
  473. { LOC_CREGISTER moved into a LOC_(C)REGISTER most of the time (as }
  474. { the live range of the LOC_CREGISTER will most likely overlap the }
  475. { the live range of the target LOC_(C)REGISTER) }
  476. { The passed register may be a LOC_CREGISTER as well. }
  477. procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint);
  478. var
  479. hreg: tregister;
  480. begin
  481. if l<>1 then
  482. begin
  483. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  484. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,maybe_const_reg,hreg);
  485. maybe_const_reg:=hreg;
  486. end;
  487. if location.reference.base=NR_NO then
  488. location.reference.base:=maybe_const_reg
  489. else if location.reference.index=NR_NO then
  490. location.reference.index:=maybe_const_reg
  491. else
  492. begin
  493. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  494. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
  495. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  496. { insert new index register }
  497. location.reference.index:=maybe_const_reg;
  498. end;
  499. { update alignment }
  500. if (location.reference.alignment=0) then
  501. internalerror(2009020704);
  502. location.reference.alignment:=newalignment(location.reference.alignment,l);
  503. end;
  504. { see remarks for tcgvecnode.update_reference_reg_mul above }
  505. procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg:tregister;l:aint);
  506. var
  507. sref: tsubsetreference;
  508. offsetreg, hreg: tregister;
  509. alignpower: aint;
  510. temp : longint;
  511. begin
  512. { only orddefs are bitpacked. Even then we only need special code in }
  513. { case the bitpacked *byte size* is not a power of two, otherwise }
  514. { everything can be handled using the the regular array code. }
  515. if ((l mod 8) = 0) and
  516. (ispowerof2(l div 8,temp) or
  517. not is_ordinal(resultdef)) then
  518. begin
  519. update_reference_reg_mul(maybe_const_reg,l div 8);
  520. exit;
  521. end;
  522. if (l > 8*sizeof(aint)) then
  523. internalerror(200608051);
  524. sref.ref := location.reference;
  525. hreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  526. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
  527. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg);
  528. { keep alignment for index }
  529. sref.ref.alignment := left.resultdef.alignment;
  530. if not ispowerof2(sref.ref.alignment,temp) then
  531. internalerror(2006081201);
  532. alignpower:=temp;
  533. offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  534. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,hreg,offsetreg);
  535. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
  536. if (sref.ref.base = NR_NO) then
  537. sref.ref.base := offsetreg
  538. else if (sref.ref.index = NR_NO) then
  539. sref.ref.index := offsetreg
  540. else
  541. begin
  542. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
  543. sref.ref.base := offsetreg;
  544. end;
  545. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,hreg);
  546. sref.bitindexreg := hreg;
  547. sref.startbit := 0;
  548. sref.bitlen := resultdef.packedbitsize;
  549. if (left.location.loc = LOC_REFERENCE) then
  550. location.loc := LOC_SUBSETREF
  551. else
  552. location.loc := LOC_CSUBSETREF;
  553. location.sref := sref;
  554. end;
  555. procedure tcgvecnode.second_wideansistring;
  556. begin
  557. end;
  558. procedure tcgvecnode.second_dynamicarray;
  559. begin
  560. end;
  561. procedure tcgvecnode.rangecheck_array;
  562. var
  563. hightree : tnode;
  564. poslabel,
  565. neglabel : tasmlabel;
  566. hreg : tregister;
  567. paraloc1,paraloc2 : tcgpara;
  568. begin
  569. paraloc1.init;
  570. paraloc2.init;
  571. if is_open_array(left.resultdef) or
  572. is_array_of_const(left.resultdef) then
  573. begin
  574. { cdecl functions don't have high() so we can not check the range }
  575. { (can't use current_procdef, since it may be a nested procedure) }
  576. if not(tprocdef(tparasymtable(tparavarsym(tloadnode(left).symtableentry).owner).defowner).proccalloption in [pocall_cdecl,pocall_cppdecl]) then
  577. begin
  578. { Get high value }
  579. hightree:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry));
  580. { it must be available }
  581. if not assigned(hightree) then
  582. internalerror(200212201);
  583. firstpass(hightree);
  584. secondpass(hightree);
  585. { generate compares }
  586. if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  587. hreg:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_INT)
  588. else
  589. begin
  590. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  591. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_INT,right.location,hreg);
  592. end;
  593. current_asmdata.getjumplabel(neglabel);
  594. current_asmdata.getjumplabel(poslabel);
  595. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_LT,0,hreg,poslabel);
  596. cg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_BE,hightree.location,hreg,neglabel);
  597. cg.a_label(current_asmdata.CurrAsmList,poslabel);
  598. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_RANGEERROR',false);
  599. cg.a_label(current_asmdata.CurrAsmList,neglabel);
  600. { release hightree }
  601. hightree.free;
  602. end;
  603. end
  604. else
  605. if is_dynamic_array(left.resultdef) then
  606. begin
  607. paramanager.getintparaloc(pocall_default,1,paraloc1);
  608. paramanager.getintparaloc(pocall_default,2,paraloc2);
  609. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc2);
  610. cg.a_param_loc(current_asmdata.CurrAsmList,right.location,paraloc2);
  611. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  612. cg.a_param_loc(current_asmdata.CurrAsmList,left.location,paraloc1);
  613. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  614. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc2);
  615. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  616. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DYNARRAY_RANGECHECK',false);
  617. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  618. end
  619. else
  620. cg.g_rangecheck(current_asmdata.CurrAsmList,right.location,right.resultdef,left.resultdef);
  621. paraloc1.done;
  622. paraloc2.done;
  623. end;
  624. procedure tcgvecnode.pass_generate_code;
  625. var
  626. offsetdec,
  627. extraoffset : aint;
  628. t : tnode;
  629. href : treference;
  630. otl,ofl : tasmlabel;
  631. newsize : tcgsize;
  632. mulsize,
  633. bytemulsize,
  634. alignpow : aint;
  635. isjump : boolean;
  636. paraloc1,
  637. paraloc2 : tcgpara;
  638. subsetref : tsubsetreference;
  639. temp : longint;
  640. begin
  641. paraloc1.init;
  642. paraloc2.init;
  643. mulsize:=get_mul_size;
  644. if not is_packed_array(left.resultdef) then
  645. bytemulsize:=mulsize
  646. else
  647. bytemulsize:=mulsize div 8;
  648. newsize:=def_cgsize(resultdef);
  649. secondpass(left);
  650. if left.location.loc=LOC_CREFERENCE then
  651. location_reset_ref(location,LOC_CREFERENCE,newsize,left.location.reference.alignment)
  652. else
  653. location_reset_ref(location,LOC_REFERENCE,newsize,left.location.reference.alignment);
  654. { an ansistring needs to be dereferenced }
  655. if is_ansistring(left.resultdef) or
  656. is_widestring(left.resultdef) or
  657. is_unicodestring(left.resultdef) then
  658. begin
  659. if nf_callunique in flags then
  660. internalerror(200304236);
  661. {DM!!!!!}
  662. case left.location.loc of
  663. LOC_REGISTER,
  664. LOC_CREGISTER :
  665. begin
  666. {$ifdef m68k}
  667. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  668. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,location.reference.base);
  669. {$else m68k}
  670. location.reference.base:=left.location.register;
  671. {$endif m68k}
  672. end;
  673. LOC_CREFERENCE,
  674. LOC_REFERENCE :
  675. begin
  676. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  677. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,location.reference.base);
  678. end;
  679. else
  680. internalerror(2002032218);
  681. end;
  682. { check for a zero length string,
  683. we can use the ansistring routine here }
  684. if (cs_check_range in current_settings.localswitches) then
  685. begin
  686. paramanager.getintparaloc(pocall_default,1,paraloc1);
  687. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  688. cg.a_param_reg(current_asmdata.CurrAsmList,OS_ADDR,location.reference.base,paraloc1);
  689. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  690. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  691. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resultdef).stringtypname)+'_CHECKZERO',false);
  692. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  693. end;
  694. { in ansistrings/widestrings S[1] is p<w>char(S)[0] !! }
  695. if is_ansistring(left.resultdef) then
  696. offsetdec:=1
  697. else
  698. offsetdec:=2;
  699. location.reference.alignment:=offsetdec;
  700. dec(location.reference.offset,offsetdec);
  701. end
  702. else if is_dynamic_array(left.resultdef) then
  703. begin
  704. case left.location.loc of
  705. LOC_REGISTER,
  706. LOC_CREGISTER :
  707. location.reference.base:=left.location.register;
  708. LOC_REFERENCE,
  709. LOC_CREFERENCE :
  710. begin
  711. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  712. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  713. left.location.reference,location.reference.base);
  714. end;
  715. else
  716. internalerror(2002032219);
  717. end;
  718. { a dynarray points to the start of a memory block, which
  719. we assume to be always aligned to a multiple of the
  720. pointer size
  721. }
  722. location.reference.alignment:=sizeof(pint);
  723. end
  724. else
  725. location_copy(location,left.location);
  726. { location must be memory }
  727. if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  728. internalerror(200411013);
  729. { offset can only differ from 0 if arraydef }
  730. if (left.resultdef.typ=arraydef) and
  731. not(is_dynamic_array(left.resultdef)) and
  732. (not(is_packed_array(left.resultdef)) or
  733. ((mulsize mod 8 = 0) and
  734. ispowerof2(mulsize div 8,temp)) or
  735. { only orddefs are bitpacked }
  736. not is_ordinal(resultdef)) then
  737. dec(location.reference.offset,bytemulsize*tarraydef(left.resultdef).lowrange);
  738. if right.nodetype=ordconstn then
  739. begin
  740. { offset can only differ from 0 if arraydef }
  741. case left.resultdef.typ of
  742. arraydef :
  743. begin
  744. { do not do any range checking when this is an array access to a pointer which has been
  745. typecasted from an array }
  746. if (not (ado_isconvertedpointer in tarraydef(left.resultdef).arrayoptions)) then
  747. begin
  748. if not(is_open_array(left.resultdef)) and
  749. not(is_array_of_const(left.resultdef)) and
  750. not(is_dynamic_array(left.resultdef)) then
  751. begin
  752. if (tordconstnode(right).value.svalue>tarraydef(left.resultdef).highrange) or
  753. (tordconstnode(right).value.svalue<tarraydef(left.resultdef).lowrange) then
  754. begin
  755. { this should be caught in the typecheckpass! (JM) }
  756. if (cs_check_range in current_settings.localswitches) then
  757. CGMessage(parser_e_range_check_error)
  758. else
  759. CGMessage(parser_w_range_check_error);
  760. end;
  761. end
  762. else
  763. begin
  764. { range checking for open and dynamic arrays needs
  765. runtime code }
  766. secondpass(right);
  767. if (cs_check_range in current_settings.localswitches) then
  768. rangecheck_array;
  769. end;
  770. end;
  771. end;
  772. stringdef :
  773. begin
  774. if (cs_check_range in current_settings.localswitches) then
  775. begin
  776. case tstringdef(left.resultdef).stringtype of
  777. { it's the same for ansi- and wide strings }
  778. st_unicodestring,
  779. st_widestring,
  780. st_ansistring:
  781. begin
  782. paramanager.getintparaloc(pocall_default,1,paraloc1);
  783. paramanager.getintparaloc(pocall_default,2,paraloc2);
  784. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc2);
  785. cg.a_param_const(current_asmdata.CurrAsmList,OS_INT,tordconstnode(right).value.svalue,paraloc2);
  786. href:=location.reference;
  787. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  788. if not(tf_winlikewidestring in target_info.flags) or
  789. (tstringdef(left.resultdef).stringtype<>st_widestring) then
  790. begin
  791. dec(href.offset,sizeof(pint)-offsetdec);
  792. cg.a_param_ref(current_asmdata.CurrAsmList,OS_ADDR,href,paraloc1);
  793. end
  794. else
  795. begin
  796. { winlike widestrings have a 4 byte length }
  797. dec(href.offset,4-offsetdec);
  798. cg.a_param_ref(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
  799. end;
  800. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  801. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc2);
  802. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  803. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resultdef).stringtypname)+'_RANGECHECK',false);
  804. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  805. end;
  806. st_shortstring:
  807. begin
  808. {!!!!!!!!!!!!!!!!!}
  809. { if this one is implemented making use of the high parameter for openshortstrings, update ncgutils.do_get_used_regvars() too (JM) }
  810. end;
  811. st_longstring:
  812. begin
  813. {!!!!!!!!!!!!!!!!!}
  814. end;
  815. end;
  816. end;
  817. end;
  818. end;
  819. if not(is_packed_array(left.resultdef)) or
  820. ((mulsize mod 8 = 0) and
  821. (ispowerof2(mulsize div 8,temp) or
  822. { only orddefs are bitpacked }
  823. not is_ordinal(resultdef))) then
  824. begin
  825. extraoffset:=bytemulsize*tordconstnode(right).value.svalue;
  826. inc(location.reference.offset,extraoffset);
  827. { adjust alignment after to this change }
  828. location.reference.alignment:=newalignment(location.reference.alignment,extraoffset);
  829. { don't do this for floats etc.; needed to properly set the }
  830. { size for bitpacked arrays (e.g. a bitpacked array of }
  831. { enums who are size 2 but fit in one byte -> in the array }
  832. { they will be one byte and have to be stored like that) }
  833. if is_packed_array(left.resultdef) and
  834. (tcgsize2size[newsize] <> bytemulsize) then
  835. newsize:=int_cgsize(bytemulsize);
  836. end
  837. else
  838. begin
  839. subsetref.ref := location.reference;
  840. subsetref.ref.alignment := left.resultdef.alignment;
  841. if not ispowerof2(subsetref.ref.alignment,temp) then
  842. internalerror(2006081212);
  843. alignpow:=temp;
  844. inc(subsetref.ref.offset,((mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow)) shl alignpow);
  845. subsetref.bitindexreg := NR_NO;
  846. subsetref.startbit := (mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) and ((1 shl (3+alignpow))-1);
  847. subsetref.bitlen := resultdef.packedbitsize;
  848. if (left.location.loc = LOC_REFERENCE) then
  849. location.loc := LOC_SUBSETREF
  850. else
  851. location.loc := LOC_CSUBSETREF;
  852. location.sref := subsetref;
  853. end;
  854. end
  855. else
  856. { not nodetype=ordconstn }
  857. begin
  858. if (cs_opt_level1 in current_settings.optimizerswitches) and
  859. { if we do range checking, we don't }
  860. { need that fancy code (it would be }
  861. { buggy) }
  862. not(cs_check_range in current_settings.localswitches) and
  863. (left.resultdef.typ=arraydef) and
  864. not is_packed_array(left.resultdef) then
  865. begin
  866. extraoffset:=0;
  867. if (right.nodetype=addn) 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. else if taddnode(right).left.nodetype=ordconstn then
  878. begin
  879. extraoffset:=tordconstnode(taddnode(right).left).value.svalue;
  880. t:=taddnode(right).right;
  881. taddnode(right).right:=nil;
  882. right.free;
  883. right:=t;
  884. end;
  885. end
  886. else if (right.nodetype=subn) then
  887. begin
  888. if taddnode(right).right.nodetype=ordconstn then
  889. begin
  890. extraoffset:=-tordconstnode(taddnode(right).right).value.svalue;
  891. t:=taddnode(right).left;
  892. taddnode(right).left:=nil;
  893. right.free;
  894. right:=t;
  895. end;
  896. end;
  897. inc(location.reference.offset,
  898. mulsize*extraoffset);
  899. end;
  900. { calculate from left to right }
  901. if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  902. internalerror(200304237);
  903. isjump:=(right.expectloc=LOC_JUMP);
  904. if isjump then
  905. begin
  906. otl:=current_procinfo.CurrTrueLabel;
  907. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  908. ofl:=current_procinfo.CurrFalseLabel;
  909. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  910. end;
  911. secondpass(right);
  912. { if mulsize = 1, we won't have to modify the index }
  913. location_force_reg(current_asmdata.CurrAsmList,right.location,OS_ADDR,true);
  914. if isjump then
  915. begin
  916. current_procinfo.CurrTrueLabel:=otl;
  917. current_procinfo.CurrFalseLabel:=ofl;
  918. end
  919. else if (right.location.loc = LOC_JUMP) then
  920. internalerror(2006010801);
  921. { only range check now, we can't range check loc_flags/loc_jump }
  922. if cs_check_range in current_settings.localswitches then
  923. begin
  924. if left.resultdef.typ=arraydef then
  925. rangecheck_array;
  926. end;
  927. { produce possible range check code: }
  928. if cs_check_range in current_settings.localswitches then
  929. begin
  930. if left.resultdef.typ=arraydef then
  931. begin
  932. { done defore (PM) }
  933. end
  934. else if (left.resultdef.typ=stringdef) then
  935. begin
  936. case tstringdef(left.resultdef).stringtype of
  937. { it's the same for ansi- and wide strings }
  938. st_unicodestring,
  939. st_widestring,
  940. st_ansistring:
  941. begin
  942. paramanager.getintparaloc(pocall_default,1,paraloc1);
  943. paramanager.getintparaloc(pocall_default,2,paraloc2);
  944. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc2);
  945. cg.a_param_reg(current_asmdata.CurrAsmList,OS_INT,right.location.register,paraloc2);
  946. href:=location.reference;
  947. dec(href.offset,sizeof(pint)-offsetdec);
  948. href:=location.reference;
  949. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  950. if not(tf_winlikewidestring in target_info.flags) or
  951. (tstringdef(left.resultdef).stringtype<>st_widestring) then
  952. begin
  953. dec(href.offset,sizeof(pint)-offsetdec);
  954. cg.a_param_ref(current_asmdata.CurrAsmList,OS_ADDR,href,paraloc1);
  955. end
  956. else
  957. begin
  958. { winlike widestrings have a 4 byte length }
  959. dec(href.offset,4-offsetdec);
  960. cg.a_param_ref(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
  961. end;
  962. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  963. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc2);
  964. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  965. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resultdef).stringtypname)+'_RANGECHECK',false);
  966. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  967. end;
  968. st_shortstring:
  969. begin
  970. {!!!!!!!!!!!!!!!!!}
  971. end;
  972. st_longstring:
  973. begin
  974. {!!!!!!!!!!!!!!!!!}
  975. end;
  976. end;
  977. end;
  978. end;
  979. { insert the register and the multiplication factor in the
  980. reference }
  981. if not is_packed_array(left.resultdef) then
  982. update_reference_reg_mul(right.location.register,mulsize)
  983. else
  984. update_reference_reg_packed(right.location.register,mulsize);
  985. end;
  986. location.size:=newsize;
  987. paraloc1.done;
  988. paraloc2.done;
  989. end;
  990. begin
  991. cloadvmtaddrnode:=tcgloadvmtaddrnode;
  992. cloadparentfpnode:=tcgloadparentfpnode;
  993. caddrnode:=tcgaddrnode;
  994. cderefnode:=tcgderefnode;
  995. csubscriptnode:=tcgsubscriptnode;
  996. cwithnode:=tcgwithnode;
  997. cvecnode:=tcgvecnode;
  998. end.