ncgmem.pas 43 KB

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