ncgmem.pas 45 KB

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