ncgmem.pas 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for memory related nodes which are
  4. the same for all (most?) processors
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ncgmem;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,cgbase,cpuinfo,cpubase,
  23. node,nmem;
  24. type
  25. tcgloadvmtaddrnode = class(tloadvmtaddrnode)
  26. procedure pass_generate_code;override;
  27. end;
  28. tcgloadparentfpnode = class(tloadparentfpnode)
  29. procedure pass_generate_code;override;
  30. end;
  31. tcgaddrnode = class(taddrnode)
  32. procedure pass_generate_code;override;
  33. end;
  34. tcgderefnode = class(tderefnode)
  35. procedure pass_generate_code;override;
  36. end;
  37. tcgsubscriptnode = class(tsubscriptnode)
  38. procedure pass_generate_code;override;
  39. end;
  40. tcgwithnode = class(twithnode)
  41. procedure pass_generate_code;override;
  42. end;
  43. tcgvecnode = class(tvecnode)
  44. function get_mul_size : aint;
  45. private
  46. procedure rangecheck_array;
  47. procedure rangecheck_string;
  48. protected
  49. {# This routine is used to calculate the address of the reference.
  50. On entry reg contains the index in the array,
  51. and l contains the size of each element in the array.
  52. This routine should update location.reference correctly,
  53. so it points to the correct address.
  54. }
  55. procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);virtual;
  56. procedure update_reference_reg_packed(maybe_const_reg:tregister;l:aint);virtual;
  57. procedure second_wideansistring;virtual;
  58. procedure second_dynamicarray;virtual;
  59. public
  60. procedure pass_generate_code;override;
  61. end;
  62. implementation
  63. uses
  64. systems,
  65. cutils,cclasses,verbose,globals,constexp,
  66. symconst,symbase,symtype,symdef,symsym,symtable,defutil,paramgr,
  67. aasmbase,aasmtai,aasmdata,
  68. procinfo,pass_2,parabase,
  69. pass_1,nld,ncon,nadd,nutils,
  70. cgutils,cgobj,hlcgobj,
  71. tgobj,ncgutil,objcgutl
  72. ;
  73. {*****************************************************************************
  74. TCGLOADVMTADDRNODE
  75. *****************************************************************************}
  76. procedure tcgloadvmtaddrnode.pass_generate_code;
  77. var
  78. href : treference;
  79. pool : THashSet;
  80. entry : PHashSetItem;
  81. begin
  82. location_reset(location,LOC_REGISTER,OS_ADDR);
  83. if (left.nodetype=typen) then
  84. begin
  85. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  86. if not is_objcclass(left.resultdef) then
  87. begin
  88. reference_reset_symbol(href,
  89. current_asmdata.RefAsmSymbol(tobjectdef(tclassrefdef(resultdef).pointeddef).vmt_mangledname),0,
  90. sizeof(pint));
  91. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
  92. end
  93. else
  94. begin
  95. pool:=current_asmdata.ConstPools[sp_objcclassnamerefs];
  96. entry:=pool.FindOrAdd(@tobjectdef(left.resultdef).objextname^[1],length(tobjectdef(left.resultdef).objextname^));
  97. if (target_info.system in systems_objc_nfabi) then
  98. begin
  99. { find/add necessary classref/classname pool entries }
  100. objcfinishclassrefnfpoolentry(entry,tobjectdef(left.resultdef));
  101. end
  102. else
  103. begin
  104. { find/add necessary classref/classname pool entries }
  105. objcfinishstringrefpoolentry(entry,sp_objcclassnames,sec_objc_cls_refs,sec_objc_class_names);
  106. end;
  107. reference_reset_symbol(href,tasmlabel(entry^.Data),0,sizeof(pint));
  108. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,location.register);
  109. end;
  110. end
  111. else
  112. begin
  113. { left contains self, load vmt from self }
  114. secondpass(left);
  115. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(left.resultdef),left.location,location.register);
  116. end;
  117. end;
  118. {*****************************************************************************
  119. TCGLOADPARENTFPNODE
  120. *****************************************************************************}
  121. procedure tcgloadparentfpnode.pass_generate_code;
  122. var
  123. currpi : tprocinfo;
  124. hsym : tparavarsym;
  125. href : treference;
  126. begin
  127. if (current_procinfo.procdef.parast.symtablelevel=parentpd.parast.symtablelevel) then
  128. begin
  129. location_reset(location,LOC_REGISTER,OS_ADDR);
  130. location.register:=current_procinfo.framepointer;
  131. end
  132. else
  133. begin
  134. currpi:=current_procinfo;
  135. location_reset(location,LOC_REGISTER,OS_ADDR);
  136. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  137. { load framepointer of current proc }
  138. hsym:=tparavarsym(currpi.procdef.parast.Find('parentfp'));
  139. if not assigned(hsym) then
  140. internalerror(200309281);
  141. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,voidpointertype,voidpointertype,hsym.localloc,location.register);
  142. { walk parents }
  143. while (currpi.procdef.owner.symtablelevel>parentpd.parast.symtablelevel) do
  144. begin
  145. currpi:=currpi.parent;
  146. if not assigned(currpi) then
  147. internalerror(200311201);
  148. hsym:=tparavarsym(currpi.procdef.parast.Find('parentfp'));
  149. if not assigned(hsym) then
  150. internalerror(200309282);
  151. if hsym.localloc.loc<>LOC_REFERENCE then
  152. internalerror(200309283);
  153. reference_reset_base(href,location.register,hsym.localloc.reference.offset,sizeof(pint));
  154. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,location.register);
  155. end;
  156. end;
  157. end;
  158. {*****************************************************************************
  159. TCGADDRNODE
  160. *****************************************************************************}
  161. procedure tcgaddrnode.pass_generate_code;
  162. begin
  163. secondpass(left);
  164. location_reset(location,LOC_REGISTER,OS_ADDR);
  165. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  166. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  167. { on x86_64-win64, array of chars can be returned in registers, however,
  168. when passing these arrays to other functions, the compiler wants to take
  169. the address of the array so when the addrnode has been created internally,
  170. we have to force the data into memory, see also tw14388.pp
  171. }
  172. if nf_internal in flags then
  173. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef)
  174. else
  175. internalerror(2006111510);
  176. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,location.register);
  177. end;
  178. {*****************************************************************************
  179. TCGDEREFNODE
  180. *****************************************************************************}
  181. procedure tcgderefnode.pass_generate_code;
  182. var
  183. paraloc1 : tcgpara;
  184. pd : tprocdef;
  185. sym : tsym;
  186. st : tsymtable;
  187. begin
  188. secondpass(left);
  189. { assume natural alignment, except for packed records }
  190. if not(resultdef.typ in [recorddef,objectdef]) or
  191. (tabstractrecordsymtable(tabstractrecorddef(resultdef).symtable).usefieldalignment<>1) then
  192. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),resultdef.alignment)
  193. else
  194. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),1);
  195. if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE,LOC_CONSTANT]) then
  196. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  197. case left.location.loc of
  198. LOC_CREGISTER,
  199. LOC_REGISTER:
  200. begin
  201. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
  202. {$ifdef cpu_uses_separate_address_registers}
  203. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  204. begin
  205. location.reference.base := cg.getaddressregister(current_asmdata.CurrAsmList);
  206. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,
  207. location.reference.base);
  208. end
  209. else
  210. {$endif}
  211. location.reference.base := left.location.register;
  212. end;
  213. LOC_CREFERENCE,
  214. LOC_REFERENCE:
  215. begin
  216. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  217. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,location.reference.base);
  218. end;
  219. LOC_CONSTANT:
  220. begin
  221. location.reference.offset:=left.location.value;
  222. end;
  223. else
  224. internalerror(200507031);
  225. end;
  226. if (cs_use_heaptrc in current_settings.globalswitches) and
  227. (cs_checkpointer in current_settings.localswitches) and
  228. not(cs_compilesystem in current_settings.moduleswitches) and
  229. not(tpointerdef(left.resultdef).is_far) and
  230. not(nf_no_checkpointer in flags) and
  231. { can be NR_NO in case of LOC_CONSTANT }
  232. (location.reference.base<>NR_NO) then
  233. begin
  234. if not searchsym_in_named_module('HEAPTRC','CHECKPOINTER',sym,st) or
  235. (sym.typ<>procsym) then
  236. internalerror(2012010601);
  237. pd:=tprocdef(tprocsym(sym).ProcdefList[0]);
  238. paraloc1.init;
  239. paramanager.getintparaloc(pd,1,paraloc1);
  240. hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,resultdef,location.reference.base,paraloc1);
  241. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  242. paraloc1.done;
  243. hlcg.allocallcpuregisters(current_asmdata.CurrAsmList);
  244. hlcg.a_call_name(current_asmdata.CurrAsmList,pd,'FPC_CHECKPOINTER',nil,false);
  245. hlcg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  246. end;
  247. end;
  248. {*****************************************************************************
  249. TCGSUBSCRIPTNODE
  250. *****************************************************************************}
  251. procedure tcgsubscriptnode.pass_generate_code;
  252. var
  253. sym: tasmsymbol;
  254. paraloc1 : tcgpara;
  255. tmpref: treference;
  256. sref: tsubsetreference;
  257. offsetcorrection : aint;
  258. pd : tprocdef;
  259. srym : tsym;
  260. st : tsymtable;
  261. begin
  262. secondpass(left);
  263. if codegenerror then
  264. exit;
  265. paraloc1.init;
  266. { several object types must be dereferenced implicitly }
  267. if is_implicit_pointer_object_type(left.resultdef) then
  268. begin
  269. if (not is_managed_type(left.resultdef)) or
  270. (target_info.system in systems_garbage_collected_managed_types) then
  271. begin
  272. { the contents of a class are aligned to a sizeof(pointer) }
  273. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),sizeof(pint));
  274. case left.location.loc of
  275. LOC_CREGISTER,
  276. LOC_REGISTER:
  277. begin
  278. {$ifdef cpu_uses_separate_address_registers}
  279. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  280. begin
  281. location.reference.base:=rg.getaddressregister(current_asmdata.CurrAsmList);
  282. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,
  283. left.location.register,location.reference.base);
  284. end
  285. else
  286. {$endif}
  287. location.reference.base := left.location.register;
  288. end;
  289. LOC_CREFERENCE,
  290. LOC_REFERENCE:
  291. begin
  292. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  293. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,location.reference.base);
  294. end;
  295. LOC_CONSTANT:
  296. begin
  297. { can happen with @classtype(pointerconst).field }
  298. location.reference.offset:=left.location.value;
  299. end;
  300. else
  301. internalerror(2009092401);
  302. end;
  303. { implicit deferencing }
  304. if (cs_use_heaptrc in current_settings.globalswitches) and
  305. (cs_checkpointer in current_settings.localswitches) and
  306. not(cs_compilesystem in current_settings.moduleswitches) then
  307. begin
  308. if not searchsym_in_named_module('HEAPTRC','CHECKPOINTER',srym,st) or
  309. (srym.typ<>procsym) then
  310. internalerror(2012010602);
  311. pd:=tprocdef(tprocsym(srym).ProcdefList[0]);
  312. paramanager.getintparaloc(pd,1,paraloc1);
  313. hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,resultdef,location.reference.base,paraloc1);
  314. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  315. hlcg.allocallcpuregisters(current_asmdata.CurrAsmList);
  316. hlcg.a_call_name(current_asmdata.CurrAsmList,pd,'FPC_CHECKPOINTER',nil,false);
  317. hlcg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  318. end;
  319. end
  320. else
  321. { reference-counted implicit pointer object types don't have
  322. fields -> cannot be subscripted (calls are handled via call
  323. nodes) }
  324. internalerror(2011011901);
  325. end
  326. else
  327. begin
  328. location_copy(location,left.location);
  329. { some abi's require that functions return (some) records in }
  330. { registers }
  331. case location.loc of
  332. LOC_REFERENCE,
  333. LOC_CREFERENCE:
  334. ;
  335. LOC_REGISTER,
  336. LOC_CREGISTER,
  337. LOC_MMREGISTER,
  338. LOC_FPUREGISTER:
  339. begin
  340. { in case the result is not something that can be put
  341. into an integer register (e.g.
  342. function_returning_record().non_regable_field, or
  343. a function returning a value > sizeof(intreg))
  344. -> force to memory
  345. }
  346. if not tstoreddef(left.resultdef).is_intregable or
  347. not tstoreddef(resultdef).is_intregable or
  348. { if the field spans multiple registers, we must force the record into
  349. memory as well }
  350. ((left.location.size in [OS_PAIR,OS_SPAIR]) and
  351. (vs.fieldoffset div sizeof(aword)<>(vs.fieldoffset+vs.getsize-1) div sizeof(aword))) or
  352. (location.loc in [LOC_MMREGISTER,LOC_FPUREGISTER]) then
  353. hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef)
  354. else
  355. begin
  356. if (left.location.loc = LOC_REGISTER) then
  357. location.loc := LOC_SUBSETREG
  358. else
  359. location.loc := LOC_CSUBSETREG;
  360. location.size:=def_cgsize(resultdef);
  361. offsetcorrection:=0;
  362. if (left.location.size in [OS_PAIR,OS_SPAIR]) then
  363. begin
  364. if (vs.fieldoffset>=sizeof(aword)) then
  365. begin
  366. location.sreg.subsetreg := left.location.registerhi;
  367. offsetcorrection:=sizeof(aword)*8;
  368. end
  369. else
  370. location.sreg.subsetreg := left.location.register;
  371. location.sreg.subsetregsize := OS_INT;
  372. end
  373. else
  374. begin
  375. location.sreg.subsetreg := left.location.register;
  376. location.sreg.subsetregsize := left.location.size;
  377. end;
  378. if not is_packed_record_or_object(left.resultdef) then
  379. begin
  380. if (target_info.endian = ENDIAN_BIG) then
  381. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8+offsetcorrection
  382. else
  383. location.sreg.startbit := (vs.fieldoffset * 8)-offsetcorrection;
  384. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  385. end
  386. else
  387. begin
  388. location.sreg.bitlen := resultdef.packedbitsize;
  389. if (target_info.endian = ENDIAN_BIG) then
  390. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset+offsetcorrection
  391. else
  392. location.sreg.startbit := vs.fieldoffset-offsetcorrection;
  393. end;
  394. end;
  395. end;
  396. LOC_SUBSETREG,
  397. LOC_CSUBSETREG:
  398. begin
  399. location.size:=def_cgsize(resultdef);
  400. if not is_packed_record_or_object(left.resultdef) then
  401. begin
  402. if (target_info.endian = ENDIAN_BIG) then
  403. inc(location.sreg.startbit, (left.resultdef.size - tcgsize2size[location.size] - vs.fieldoffset) * 8)
  404. else
  405. inc(location.sreg.startbit, vs.fieldoffset * 8);
  406. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  407. end
  408. else
  409. begin
  410. location.sreg.bitlen := resultdef.packedbitsize;
  411. if (target_info.endian = ENDIAN_BIG) then
  412. inc(location.sreg.startbit, left.location.sreg.bitlen - location.sreg.bitlen - vs.fieldoffset)
  413. else
  414. inc(location.sreg.startbit, vs.fieldoffset);
  415. end;
  416. end;
  417. else
  418. internalerror(2006031901);
  419. end;
  420. end;
  421. if is_objc_class_or_protocol(left.resultdef) and
  422. (target_info.system in systems_objc_nfabi) then
  423. begin
  424. if (location.loc<>LOC_REFERENCE) or
  425. (location.reference.index<>NR_NO) then
  426. internalerror(2009092402);
  427. { the actual field offset is stored in memory (to solve the
  428. "fragile base class" problem: this way the layout of base
  429. classes can be changed without breaking programs compiled against
  430. earlier versions)
  431. }
  432. sym:=current_asmdata.RefAsmSymbol(vs.mangledname);
  433. reference_reset_symbol(tmpref,sym,0,sizeof(pint));
  434. location.reference.index:=cg.getaddressregister(current_asmdata.CurrAsmList);
  435. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,location.reference.index);
  436. { always packrecords C -> natural alignment }
  437. location.reference.alignment:=vs.vardef.alignment;
  438. end
  439. else if is_java_class_or_interface(left.resultdef) or
  440. ((target_info.system in systems_jvm) and
  441. (left.resultdef.typ=recorddef)) then
  442. begin
  443. if (location.loc<>LOC_REFERENCE) or
  444. (location.reference.index<>NR_NO) or
  445. assigned(location.reference.symbol) then
  446. internalerror(2011011301);
  447. location.reference.symbol:=current_asmdata.RefAsmSymbol(vs.mangledname);
  448. end
  449. else if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  450. begin
  451. if not is_packed_record_or_object(left.resultdef) then
  452. begin
  453. inc(location.reference.offset,vs.fieldoffset);
  454. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset);
  455. end
  456. else if (vs.fieldoffset mod 8 = 0) and
  457. (resultdef.packedbitsize mod 8 = 0) and
  458. { is different in case of e.g. packenum 2 and an enum }
  459. { which fits in 8 bits }
  460. (resultdef.size*8 = resultdef.packedbitsize) then
  461. begin
  462. inc(location.reference.offset,vs.fieldoffset div 8);
  463. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset div 8);
  464. end
  465. else
  466. begin
  467. sref.ref:=location.reference;
  468. sref.ref.alignment:=1;
  469. sref.bitindexreg:=NR_NO;
  470. inc(sref.ref.offset,vs.fieldoffset div 8);
  471. sref.startbit:=vs.fieldoffset mod 8;
  472. sref.bitlen:=resultdef.packedbitsize;
  473. if (left.location.loc=LOC_REFERENCE) then
  474. location.loc:=LOC_SUBSETREF
  475. else
  476. location.loc:=LOC_CSUBSETREF;
  477. location.sref:=sref;
  478. end;
  479. { also update the size of the location }
  480. location.size:=def_cgsize(resultdef);
  481. end;
  482. paraloc1.done;
  483. end;
  484. {*****************************************************************************
  485. TCGWITHNODE
  486. *****************************************************************************}
  487. procedure tcgwithnode.pass_generate_code;
  488. begin
  489. location_reset(location,LOC_VOID,OS_NO);
  490. if assigned(left) then
  491. secondpass(left);
  492. end;
  493. {*****************************************************************************
  494. TCGVECNODE
  495. *****************************************************************************}
  496. function tcgvecnode.get_mul_size : aint;
  497. begin
  498. if nf_memindex in flags then
  499. get_mul_size:=1
  500. else
  501. begin
  502. if (left.resultdef.typ=arraydef) then
  503. if not is_packed_array(left.resultdef) then
  504. get_mul_size:=tarraydef(left.resultdef).elesize
  505. else
  506. get_mul_size:=tarraydef(left.resultdef).elepackedbitsize
  507. else
  508. get_mul_size:=resultdef.size;
  509. end
  510. end;
  511. { this routine must, like any other routine, not change the contents }
  512. { of base/index registers of references, as these may be regvars. }
  513. { The register allocator can coalesce one LOC_REGISTER being moved }
  514. { into another (as their live ranges won't overlap), but not a }
  515. { LOC_CREGISTER moved into a LOC_(C)REGISTER most of the time (as }
  516. { the live range of the LOC_CREGISTER will most likely overlap the }
  517. { the live range of the target LOC_(C)REGISTER) }
  518. { The passed register may be a LOC_CREGISTER as well. }
  519. procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint);
  520. var
  521. hreg: tregister;
  522. begin
  523. if l<>1 then
  524. begin
  525. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  526. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,maybe_const_reg,hreg);
  527. maybe_const_reg:=hreg;
  528. end;
  529. if location.reference.base=NR_NO then
  530. location.reference.base:=maybe_const_reg
  531. else if location.reference.index=NR_NO then
  532. location.reference.index:=maybe_const_reg
  533. else
  534. begin
  535. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  536. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
  537. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  538. { insert new index register }
  539. location.reference.index:=maybe_const_reg;
  540. end;
  541. { update alignment }
  542. if (location.reference.alignment=0) then
  543. internalerror(2009020704);
  544. location.reference.alignment:=newalignment(location.reference.alignment,l);
  545. end;
  546. { see remarks for tcgvecnode.update_reference_reg_mul above }
  547. procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg:tregister;l:aint);
  548. var
  549. sref: tsubsetreference;
  550. offsetreg, hreg: tregister;
  551. alignpower: aint;
  552. temp : longint;
  553. begin
  554. { only orddefs are bitpacked. Even then we only need special code in }
  555. { case the bitpacked *byte size* is not a power of two, otherwise }
  556. { everything can be handled using the the regular array code. }
  557. if ((l mod 8) = 0) and
  558. (ispowerof2(l div 8,temp) or
  559. not is_ordinal(resultdef)
  560. {$ifndef cpu64bitalu}
  561. or is_64bitint(resultdef)
  562. {$endif not cpu64bitalu}
  563. ) then
  564. begin
  565. update_reference_reg_mul(maybe_const_reg,l div 8);
  566. exit;
  567. end;
  568. if (l > 8*sizeof(aint)) then
  569. internalerror(200608051);
  570. sref.ref := location.reference;
  571. hreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  572. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
  573. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg);
  574. { keep alignment for index }
  575. sref.ref.alignment := left.resultdef.alignment;
  576. if not ispowerof2(sref.ref.alignment,temp) then
  577. internalerror(2006081201);
  578. alignpower:=temp;
  579. offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  580. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,hreg,offsetreg);
  581. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
  582. if (sref.ref.base = NR_NO) then
  583. sref.ref.base := offsetreg
  584. else if (sref.ref.index = NR_NO) then
  585. sref.ref.index := offsetreg
  586. else
  587. begin
  588. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
  589. sref.ref.base := offsetreg;
  590. end;
  591. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,hreg);
  592. sref.bitindexreg := hreg;
  593. sref.startbit := 0;
  594. sref.bitlen := resultdef.packedbitsize;
  595. if (left.location.loc = LOC_REFERENCE) then
  596. location.loc := LOC_SUBSETREF
  597. else
  598. location.loc := LOC_CSUBSETREF;
  599. location.sref := sref;
  600. end;
  601. procedure tcgvecnode.second_wideansistring;
  602. begin
  603. end;
  604. procedure tcgvecnode.second_dynamicarray;
  605. begin
  606. end;
  607. procedure tcgvecnode.rangecheck_array;
  608. var
  609. hightree : tnode;
  610. poslabel,
  611. neglabel : tasmlabel;
  612. hreg : tregister;
  613. paraloc1,paraloc2 : tcgpara;
  614. pd : tprocdef;
  615. begin
  616. { omit range checking when this is an array access to a pointer which has been
  617. typecasted from an array }
  618. if (ado_isconvertedpointer in tarraydef(left.resultdef).arrayoptions) then
  619. exit;
  620. paraloc1.init;
  621. paraloc2.init;
  622. if is_open_array(left.resultdef) or
  623. is_array_of_const(left.resultdef) then
  624. begin
  625. { cdecl functions don't have high() so we can not check the range }
  626. { (can't use current_procdef, since it may be a nested procedure) }
  627. if not(tprocdef(tparasymtable(tparavarsym(tloadnode(left).symtableentry).owner).defowner).proccalloption in cdecl_pocalls) then
  628. begin
  629. { Get high value }
  630. hightree:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry));
  631. { it must be available }
  632. if not assigned(hightree) then
  633. internalerror(200212201);
  634. firstpass(hightree);
  635. secondpass(hightree);
  636. { generate compares }
  637. if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  638. hreg:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_INT)
  639. else
  640. begin
  641. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  642. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,hreg);
  643. end;
  644. current_asmdata.getjumplabel(neglabel);
  645. current_asmdata.getjumplabel(poslabel);
  646. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_LT,0,hreg,poslabel);
  647. cg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_BE,hightree.location,hreg,neglabel);
  648. cg.a_label(current_asmdata.CurrAsmList,poslabel);
  649. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_RANGEERROR',false);
  650. cg.a_label(current_asmdata.CurrAsmList,neglabel);
  651. { release hightree }
  652. hightree.free;
  653. end;
  654. end
  655. else
  656. if is_dynamic_array(left.resultdef) then
  657. begin
  658. pd:=search_system_proc('fpc_dynarray_rangecheck');
  659. paramanager.getintparaloc(pd,1,paraloc1);
  660. paramanager.getintparaloc(pd,2,paraloc2);
  661. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  662. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  663. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  664. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  665. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  666. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DYNARRAY_RANGECHECK',false);
  667. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  668. end;
  669. { for regular arrays, we don't have to do anything because the index has been
  670. type converted to the index type, which already inserted a range check if
  671. necessary }
  672. paraloc1.done;
  673. paraloc2.done;
  674. end;
  675. procedure tcgvecnode.rangecheck_string;
  676. var
  677. paraloc1,
  678. paraloc2: tcgpara;
  679. helpername: TIDString;
  680. pd: tprocdef;
  681. begin
  682. paraloc1.init;
  683. paraloc2.init;
  684. case tstringdef(left.resultdef).stringtype of
  685. { it's the same for ansi- and wide strings }
  686. st_unicodestring,
  687. st_widestring,
  688. st_ansistring:
  689. begin
  690. helpername:='fpc_'+tstringdef(left.resultdef).stringtypname+'_rangecheck';
  691. pd:=search_system_proc(helpername);
  692. paramanager.getintparaloc(pd,1,paraloc1);
  693. paramanager.getintparaloc(pd,2,paraloc2);
  694. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  695. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  696. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  697. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  698. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  699. cg.a_call_name(current_asmdata.CurrAsmList,helpername,false);
  700. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  701. end;
  702. st_shortstring:
  703. begin
  704. {!!!!!!!!!!!!!!!!!}
  705. { if this one is implemented making use of the high parameter for openshortstrings, update ncgutils.do_get_used_regvars() too (JM) }
  706. end;
  707. st_longstring:
  708. begin
  709. {!!!!!!!!!!!!!!!!!}
  710. end;
  711. end;
  712. paraloc1.done;
  713. paraloc2.done;
  714. end;
  715. procedure tcgvecnode.pass_generate_code;
  716. var
  717. offsetdec,
  718. extraoffset : aint;
  719. t : tnode;
  720. otl,ofl : tasmlabel;
  721. newsize : tcgsize;
  722. mulsize,
  723. bytemulsize,
  724. alignpow : aint;
  725. isjump : boolean;
  726. paraloc1,
  727. paraloc2 : tcgpara;
  728. subsetref : tsubsetreference;
  729. temp : longint;
  730. begin
  731. paraloc1.init;
  732. paraloc2.init;
  733. mulsize:=get_mul_size;
  734. if not is_packed_array(left.resultdef) then
  735. bytemulsize:=mulsize
  736. else
  737. bytemulsize:=mulsize div 8;
  738. newsize:=def_cgsize(resultdef);
  739. secondpass(left);
  740. if left.location.loc=LOC_CREFERENCE then
  741. location_reset_ref(location,LOC_CREFERENCE,newsize,left.location.reference.alignment)
  742. else
  743. location_reset_ref(location,LOC_REFERENCE,newsize,left.location.reference.alignment);
  744. { an ansistring needs to be dereferenced }
  745. if is_ansistring(left.resultdef) or
  746. is_wide_or_unicode_string(left.resultdef) then
  747. begin
  748. if nf_callunique in flags then
  749. internalerror(200304236);
  750. {DM!!!!!}
  751. case left.location.loc of
  752. LOC_REGISTER,
  753. LOC_CREGISTER :
  754. begin
  755. {$ifdef m68k}
  756. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  757. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,location.reference.base);
  758. {$else m68k}
  759. location.reference.base:=left.location.register;
  760. {$endif m68k}
  761. end;
  762. LOC_CREFERENCE,
  763. LOC_REFERENCE :
  764. begin
  765. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  766. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,location.reference.base);
  767. end;
  768. else
  769. internalerror(2002032218);
  770. end;
  771. if is_ansistring(left.resultdef) then
  772. offsetdec:=1
  773. else
  774. offsetdec:=2;
  775. location.reference.alignment:=offsetdec;
  776. { in ansistrings/widestrings S[1] is p<w>char(S)[0] }
  777. if not(cs_zerobasedstrings in current_settings.localswitches) then
  778. dec(location.reference.offset,offsetdec);
  779. end
  780. else if is_dynamic_array(left.resultdef) then
  781. begin
  782. case left.location.loc of
  783. LOC_REGISTER,
  784. LOC_CREGISTER :
  785. location.reference.base:=left.location.register;
  786. LOC_REFERENCE,
  787. LOC_CREFERENCE :
  788. begin
  789. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  790. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  791. left.location.reference,location.reference.base);
  792. end;
  793. else
  794. internalerror(2002032219);
  795. end;
  796. { a dynarray points to the start of a memory block, which
  797. we assume to be always aligned to a multiple of the
  798. pointer size
  799. }
  800. location.reference.alignment:=sizeof(pint);
  801. end
  802. else
  803. begin
  804. { may happen in case of function results }
  805. case left.location.loc of
  806. LOC_REGISTER,
  807. LOC_MMREGISTER:
  808. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  809. end;
  810. location_copy(location,left.location);
  811. end;
  812. { location must be memory }
  813. if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  814. internalerror(200411013);
  815. { offset can only differ from 0 if arraydef }
  816. if (left.resultdef.typ=arraydef) and
  817. not(is_dynamic_array(left.resultdef)) and
  818. (not(is_packed_array(left.resultdef)) or
  819. ((mulsize mod 8 = 0) and
  820. ispowerof2(mulsize div 8,temp)) or
  821. { only orddefs are bitpacked }
  822. not is_ordinal(resultdef)
  823. {$ifndef cpu64bitalu}
  824. or is_64bitint(resultdef)
  825. {$endif not cpu64bitalu}
  826. ) then
  827. dec(location.reference.offset,bytemulsize*tarraydef(left.resultdef).lowrange);
  828. if right.nodetype=ordconstn then
  829. begin
  830. { offset can only differ from 0 if arraydef }
  831. if cs_check_range in current_settings.localswitches then
  832. begin
  833. secondpass(right);
  834. case left.resultdef.typ of
  835. arraydef :
  836. rangecheck_array;
  837. stringdef :
  838. rangecheck_string;
  839. end;
  840. end;
  841. if not(is_packed_array(left.resultdef)) or
  842. ((mulsize mod 8 = 0) and
  843. (ispowerof2(mulsize div 8,temp) or
  844. { only orddefs are bitpacked }
  845. not is_ordinal(resultdef))) then
  846. begin
  847. extraoffset:=bytemulsize*tordconstnode(right).value.svalue;
  848. inc(location.reference.offset,extraoffset);
  849. { adjust alignment after to this change }
  850. location.reference.alignment:=newalignment(location.reference.alignment,extraoffset);
  851. { don't do this for floats etc.; needed to properly set the }
  852. { size for bitpacked arrays (e.g. a bitpacked array of }
  853. { enums who are size 2 but fit in one byte -> in the array }
  854. { they will be one byte and have to be stored like that) }
  855. if is_packed_array(left.resultdef) and
  856. (tcgsize2size[newsize] <> bytemulsize) then
  857. newsize:=int_cgsize(bytemulsize);
  858. end
  859. else
  860. begin
  861. subsetref.ref := location.reference;
  862. subsetref.ref.alignment := left.resultdef.alignment;
  863. if not ispowerof2(subsetref.ref.alignment,temp) then
  864. internalerror(2006081212);
  865. alignpow:=temp;
  866. inc(subsetref.ref.offset,((mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow)) shl alignpow);
  867. subsetref.bitindexreg := NR_NO;
  868. subsetref.startbit := (mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) and ((1 shl (3+alignpow))-1);
  869. subsetref.bitlen := resultdef.packedbitsize;
  870. if (left.location.loc = LOC_REFERENCE) then
  871. location.loc := LOC_SUBSETREF
  872. else
  873. location.loc := LOC_CSUBSETREF;
  874. location.sref := subsetref;
  875. end;
  876. end
  877. else
  878. { not nodetype=ordconstn }
  879. begin
  880. if (cs_opt_level1 in current_settings.optimizerswitches) and
  881. { if we do range checking, we don't }
  882. { need that fancy code (it would be }
  883. { buggy) }
  884. not(cs_check_range in current_settings.localswitches) and
  885. (left.resultdef.typ=arraydef) and
  886. not is_packed_array(left.resultdef) then
  887. begin
  888. extraoffset:=0;
  889. if (right.nodetype=addn) then
  890. begin
  891. if taddnode(right).right.nodetype=ordconstn then
  892. begin
  893. extraoffset:=tordconstnode(taddnode(right).right).value.svalue;
  894. t:=taddnode(right).left;
  895. taddnode(right).left:=nil;
  896. right.free;
  897. right:=t;
  898. end
  899. else if taddnode(right).left.nodetype=ordconstn then
  900. begin
  901. extraoffset:=tordconstnode(taddnode(right).left).value.svalue;
  902. t:=taddnode(right).right;
  903. taddnode(right).right:=nil;
  904. right.free;
  905. right:=t;
  906. end;
  907. end
  908. else if (right.nodetype=subn) then
  909. begin
  910. if taddnode(right).right.nodetype=ordconstn then
  911. begin
  912. extraoffset:=-tordconstnode(taddnode(right).right).value.svalue;
  913. t:=taddnode(right).left;
  914. taddnode(right).left:=nil;
  915. right.free;
  916. right:=t;
  917. end;
  918. end;
  919. inc(location.reference.offset,
  920. mulsize*extraoffset);
  921. end;
  922. { calculate from left to right }
  923. if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  924. internalerror(200304237);
  925. isjump:=(right.expectloc=LOC_JUMP);
  926. if isjump then
  927. begin
  928. otl:=current_procinfo.CurrTrueLabel;
  929. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  930. ofl:=current_procinfo.CurrFalseLabel;
  931. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  932. end;
  933. secondpass(right);
  934. { if mulsize = 1, we won't have to modify the index }
  935. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,ptruinttype,true);
  936. if isjump then
  937. begin
  938. current_procinfo.CurrTrueLabel:=otl;
  939. current_procinfo.CurrFalseLabel:=ofl;
  940. end
  941. else if (right.location.loc = LOC_JUMP) then
  942. internalerror(2006010801);
  943. { produce possible range check code: }
  944. if cs_check_range in current_settings.localswitches then
  945. begin
  946. if left.resultdef.typ=arraydef then
  947. rangecheck_array
  948. else if (left.resultdef.typ=stringdef) then
  949. rangecheck_string;
  950. end;
  951. { insert the register and the multiplication factor in the
  952. reference }
  953. if not is_packed_array(left.resultdef) then
  954. update_reference_reg_mul(right.location.register,mulsize)
  955. else
  956. update_reference_reg_packed(right.location.register,mulsize);
  957. end;
  958. location.size:=newsize;
  959. paraloc1.done;
  960. paraloc2.done;
  961. end;
  962. begin
  963. cloadvmtaddrnode:=tcgloadvmtaddrnode;
  964. cloadparentfpnode:=tcgloadparentfpnode;
  965. caddrnode:=tcgaddrnode;
  966. cderefnode:=tcgderefnode;
  967. csubscriptnode:=tcgsubscriptnode;
  968. cwithnode:=tcgwithnode;
  969. cvecnode:=tcgvecnode;
  970. end.