ncgmem.pas 48 KB

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