ncgmem.pas 44 KB

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