ncgmem.pas 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  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. { classes and interfaces must be dereferenced implicitly }
  258. if is_class_or_interface_or_dispinterface_or_objc(left.resultdef) then
  259. begin
  260. { the contents of a class are aligned to a sizeof(pointer) }
  261. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),sizeof(pint));
  262. case left.location.loc of
  263. LOC_CREGISTER,
  264. LOC_REGISTER:
  265. begin
  266. {$ifdef cpu_uses_separate_address_registers}
  267. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  268. begin
  269. location.reference.base:=rg.getaddressregister(current_asmdata.CurrAsmList);
  270. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  271. left.location.register,location.reference.base);
  272. end
  273. else
  274. {$endif}
  275. location.reference.base := left.location.register;
  276. end;
  277. LOC_CREFERENCE,
  278. LOC_REFERENCE:
  279. begin
  280. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  281. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference.base);
  282. end;
  283. LOC_CONSTANT:
  284. begin
  285. { can happen with @classtype(pointerconst).field }
  286. location.reference.offset:=left.location.value;
  287. end;
  288. else
  289. internalerror(2009092401);
  290. end;
  291. { implicit deferencing }
  292. if (cs_use_heaptrc in current_settings.globalswitches) and
  293. (cs_checkpointer in current_settings.localswitches) and
  294. not(cs_compilesystem in current_settings.moduleswitches) then
  295. begin
  296. paramanager.getintparaloc(pocall_default,1,paraloc1);
  297. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  298. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  299. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  300. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER',false);
  301. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  302. end;
  303. end
  304. else if is_interfacecom(left.resultdef) then
  305. begin
  306. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),sizeof(pint));
  307. tg.GetTempTyped(current_asmdata.CurrAsmList,left.resultdef,tt_normal,location.reference);
  308. cg.a_load_loc_ref(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference);
  309. { implicit deferencing also for interfaces }
  310. if (cs_use_heaptrc in current_settings.globalswitches) and
  311. (cs_checkpointer in current_settings.localswitches) and
  312. not(cs_compilesystem in current_settings.moduleswitches) then
  313. begin
  314. paramanager.getintparaloc(pocall_default,1,paraloc1);
  315. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  316. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  317. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  318. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER',false);
  319. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  320. end;
  321. end
  322. else
  323. begin
  324. location_copy(location,left.location);
  325. { some abi's require that functions return (some) records in }
  326. { registers }
  327. case location.loc of
  328. LOC_REFERENCE,
  329. LOC_CREFERENCE:
  330. ;
  331. LOC_REGISTER,
  332. LOC_CREGISTER:
  333. begin
  334. // in case the result is not something that can be put
  335. // into an integer register (e.g.
  336. // function_returning_record().non_regable_field, or
  337. // a function returning a value > sizeof(intreg))
  338. // -> force to memory
  339. if not tstoreddef(left.resultdef).is_intregable or
  340. not tstoreddef(resultdef).is_intregable then
  341. location_force_mem(current_asmdata.CurrAsmList,location)
  342. else
  343. begin
  344. if (left.location.loc = LOC_REGISTER) then
  345. location.loc := LOC_SUBSETREG
  346. else
  347. location.loc := LOC_CSUBSETREG;
  348. location.size:=def_cgsize(resultdef);
  349. location.sreg.subsetreg := left.location.register;
  350. location.sreg.subsetregsize := left.location.size;
  351. if not is_packed_record_or_object(left.resultdef) then
  352. begin
  353. if (target_info.endian = ENDIAN_BIG) then
  354. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8
  355. else
  356. location.sreg.startbit := (vs.fieldoffset * 8);
  357. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  358. end
  359. else
  360. begin
  361. location.sreg.bitlen := resultdef.packedbitsize;
  362. if (target_info.endian = ENDIAN_BIG) then
  363. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset
  364. else
  365. location.sreg.startbit := vs.fieldoffset;
  366. end;
  367. end;
  368. end;
  369. LOC_SUBSETREG,
  370. LOC_CSUBSETREG:
  371. begin
  372. location.size:=def_cgsize(resultdef);
  373. if not is_packed_record_or_object(left.resultdef) then
  374. begin
  375. if (target_info.endian = ENDIAN_BIG) then
  376. inc(location.sreg.startbit, (left.resultdef.size - tcgsize2size[location.size] - vs.fieldoffset) * 8)
  377. else
  378. inc(location.sreg.startbit, vs.fieldoffset * 8);
  379. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  380. end
  381. else
  382. begin
  383. location.sreg.bitlen := resultdef.packedbitsize;
  384. if (target_info.endian = ENDIAN_BIG) then
  385. inc(location.sreg.startbit, left.location.sreg.bitlen - location.sreg.bitlen - vs.fieldoffset)
  386. else
  387. inc(location.sreg.startbit, vs.fieldoffset);
  388. end;
  389. end;
  390. else
  391. internalerror(2006031901);
  392. end;
  393. end;
  394. if is_objc_class_or_protocol(left.resultdef) and
  395. (target_info.system in systems_objc_nfabi) then
  396. begin
  397. if (location.loc<>LOC_REFERENCE) or
  398. (location.reference.index<>NR_NO) then
  399. internalerror(2009092402);
  400. { the actual field offset is stored in memory (to solve the
  401. "fragile base class" problem: this way the layout of base
  402. classes can be changed without breaking programs compiled against
  403. earlier versions)
  404. }
  405. hreg:=cg.g_indirect_sym_load(current_asmdata.CurrAsmList,vs.mangledname,false);
  406. { TODO: clean up. g_indirect_sym_load cannot perform
  407. a plain load for targets that don't need an indirect load
  408. because it's also used in ncgld, but this is not very nice...
  409. }
  410. if (hreg=NR_NO) then
  411. begin
  412. sym:=current_asmdata.RefAsmSymbol(vs.mangledname);
  413. reference_reset_symbol(tmpref,sym,0,sizeof(pint));
  414. location.reference.index:=cg.getaddressregister(current_asmdata.CurrAsmList);
  415. end
  416. else
  417. begin
  418. reference_reset_base(tmpref,hreg,0,sizeof(pint));
  419. location.reference.index:=hreg;
  420. end;
  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 (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  426. begin
  427. if not is_packed_record_or_object(left.resultdef) then
  428. begin
  429. inc(location.reference.offset,vs.fieldoffset);
  430. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset);
  431. end
  432. else if (vs.fieldoffset mod 8 = 0) and
  433. (resultdef.packedbitsize mod 8 = 0) and
  434. { is different in case of e.g. packenum 2 and an enum }
  435. { which fits in 8 bits }
  436. (resultdef.size*8 = resultdef.packedbitsize) then
  437. begin
  438. inc(location.reference.offset,vs.fieldoffset div 8);
  439. location.reference.alignment:=newalignment(location.reference.alignment,vs.fieldoffset div 8);
  440. end
  441. else
  442. begin
  443. sref.ref:=location.reference;
  444. sref.ref.alignment:=1;
  445. sref.bitindexreg:=NR_NO;
  446. inc(sref.ref.offset,vs.fieldoffset div 8);
  447. sref.startbit:=vs.fieldoffset mod 8;
  448. sref.bitlen:=resultdef.packedbitsize;
  449. if (left.location.loc=LOC_REFERENCE) then
  450. location.loc:=LOC_SUBSETREF
  451. else
  452. location.loc:=LOC_CSUBSETREF;
  453. location.sref:=sref;
  454. end;
  455. { also update the size of the location }
  456. location.size:=def_cgsize(resultdef);
  457. end;
  458. paraloc1.done;
  459. end;
  460. {*****************************************************************************
  461. TCGWITHNODE
  462. *****************************************************************************}
  463. procedure tcgwithnode.pass_generate_code;
  464. begin
  465. location_reset(location,LOC_VOID,OS_NO);
  466. if assigned(left) then
  467. secondpass(left);
  468. end;
  469. {*****************************************************************************
  470. TCGVECNODE
  471. *****************************************************************************}
  472. function tcgvecnode.get_mul_size : aint;
  473. begin
  474. if nf_memindex in flags then
  475. get_mul_size:=1
  476. else
  477. begin
  478. if (left.resultdef.typ=arraydef) then
  479. if not is_packed_array(left.resultdef) then
  480. get_mul_size:=tarraydef(left.resultdef).elesize
  481. else
  482. get_mul_size:=tarraydef(left.resultdef).elepackedbitsize
  483. else
  484. get_mul_size:=resultdef.size;
  485. end
  486. end;
  487. { this routine must, like any other routine, not change the contents }
  488. { of base/index registers of references, as these may be regvars. }
  489. { The register allocator can coalesce one LOC_REGISTER being moved }
  490. { into another (as their live ranges won't overlap), but not a }
  491. { LOC_CREGISTER moved into a LOC_(C)REGISTER most of the time (as }
  492. { the live range of the LOC_CREGISTER will most likely overlap the }
  493. { the live range of the target LOC_(C)REGISTER) }
  494. { The passed register may be a LOC_CREGISTER as well. }
  495. procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint);
  496. var
  497. hreg: tregister;
  498. begin
  499. if l<>1 then
  500. begin
  501. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  502. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,maybe_const_reg,hreg);
  503. maybe_const_reg:=hreg;
  504. end;
  505. if location.reference.base=NR_NO then
  506. location.reference.base:=maybe_const_reg
  507. else if location.reference.index=NR_NO then
  508. location.reference.index:=maybe_const_reg
  509. else
  510. begin
  511. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  512. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
  513. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  514. { insert new index register }
  515. location.reference.index:=maybe_const_reg;
  516. end;
  517. { update alignment }
  518. if (location.reference.alignment=0) then
  519. internalerror(2009020704);
  520. location.reference.alignment:=newalignment(location.reference.alignment,l);
  521. end;
  522. { see remarks for tcgvecnode.update_reference_reg_mul above }
  523. procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg:tregister;l:aint);
  524. var
  525. sref: tsubsetreference;
  526. offsetreg, hreg: tregister;
  527. alignpower: aint;
  528. temp : longint;
  529. begin
  530. { only orddefs are bitpacked. Even then we only need special code in }
  531. { case the bitpacked *byte size* is not a power of two, otherwise }
  532. { everything can be handled using the the regular array code. }
  533. if ((l mod 8) = 0) and
  534. (ispowerof2(l div 8,temp) or
  535. not is_ordinal(resultdef)
  536. {$ifndef cpu64bitalu}
  537. or is_64bitint(resultdef)
  538. {$endif not cpu64bitalu}
  539. ) then
  540. begin
  541. update_reference_reg_mul(maybe_const_reg,l div 8);
  542. exit;
  543. end;
  544. if (l > 8*sizeof(aint)) then
  545. internalerror(200608051);
  546. sref.ref := location.reference;
  547. hreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  548. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
  549. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg);
  550. { keep alignment for index }
  551. sref.ref.alignment := left.resultdef.alignment;
  552. if not ispowerof2(sref.ref.alignment,temp) then
  553. internalerror(2006081201);
  554. alignpower:=temp;
  555. offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  556. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,hreg,offsetreg);
  557. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
  558. if (sref.ref.base = NR_NO) then
  559. sref.ref.base := offsetreg
  560. else if (sref.ref.index = NR_NO) then
  561. sref.ref.index := offsetreg
  562. else
  563. begin
  564. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
  565. sref.ref.base := offsetreg;
  566. end;
  567. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,hreg);
  568. sref.bitindexreg := hreg;
  569. sref.startbit := 0;
  570. sref.bitlen := resultdef.packedbitsize;
  571. if (left.location.loc = LOC_REFERENCE) then
  572. location.loc := LOC_SUBSETREF
  573. else
  574. location.loc := LOC_CSUBSETREF;
  575. location.sref := sref;
  576. end;
  577. procedure tcgvecnode.second_wideansistring;
  578. begin
  579. end;
  580. procedure tcgvecnode.second_dynamicarray;
  581. begin
  582. end;
  583. procedure tcgvecnode.rangecheck_array;
  584. var
  585. hightree : tnode;
  586. poslabel,
  587. neglabel : tasmlabel;
  588. hreg : tregister;
  589. paraloc1,paraloc2 : tcgpara;
  590. begin
  591. paraloc1.init;
  592. paraloc2.init;
  593. if is_open_array(left.resultdef) or
  594. is_array_of_const(left.resultdef) then
  595. begin
  596. { cdecl functions don't have high() so we can not check the range }
  597. { (can't use current_procdef, since it may be a nested procedure) }
  598. if not(tprocdef(tparasymtable(tparavarsym(tloadnode(left).symtableentry).owner).defowner).proccalloption in [pocall_cdecl,pocall_cppdecl]) then
  599. begin
  600. { Get high value }
  601. hightree:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry));
  602. { it must be available }
  603. if not assigned(hightree) then
  604. internalerror(200212201);
  605. firstpass(hightree);
  606. secondpass(hightree);
  607. { generate compares }
  608. if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  609. hreg:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_INT)
  610. else
  611. begin
  612. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  613. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_INT,right.location,hreg);
  614. end;
  615. current_asmdata.getjumplabel(neglabel);
  616. current_asmdata.getjumplabel(poslabel);
  617. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_LT,0,hreg,poslabel);
  618. cg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_BE,hightree.location,hreg,neglabel);
  619. cg.a_label(current_asmdata.CurrAsmList,poslabel);
  620. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_RANGEERROR',false);
  621. cg.a_label(current_asmdata.CurrAsmList,neglabel);
  622. { release hightree }
  623. hightree.free;
  624. end;
  625. end
  626. else
  627. if is_dynamic_array(left.resultdef) then
  628. begin
  629. paramanager.getintparaloc(pocall_default,1,paraloc1);
  630. paramanager.getintparaloc(pocall_default,2,paraloc2);
  631. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,right.location,paraloc2);
  632. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,paraloc1);
  633. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  634. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  635. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  636. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DYNARRAY_RANGECHECK',false);
  637. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  638. end;
  639. { for regular arrays, we don't have to do anything because the index has been
  640. type converted to the index type, which already inserted a range check if
  641. necessary }
  642. paraloc1.done;
  643. paraloc2.done;
  644. end;
  645. procedure tcgvecnode.pass_generate_code;
  646. var
  647. offsetdec,
  648. extraoffset : aint;
  649. t : tnode;
  650. href : treference;
  651. otl,ofl : tasmlabel;
  652. newsize : tcgsize;
  653. mulsize,
  654. bytemulsize,
  655. alignpow : aint;
  656. isjump : boolean;
  657. paraloc1,
  658. paraloc2 : tcgpara;
  659. subsetref : tsubsetreference;
  660. temp : longint;
  661. begin
  662. paraloc1.init;
  663. paraloc2.init;
  664. mulsize:=get_mul_size;
  665. if not is_packed_array(left.resultdef) then
  666. bytemulsize:=mulsize
  667. else
  668. bytemulsize:=mulsize div 8;
  669. newsize:=def_cgsize(resultdef);
  670. secondpass(left);
  671. if left.location.loc=LOC_CREFERENCE then
  672. location_reset_ref(location,LOC_CREFERENCE,newsize,left.location.reference.alignment)
  673. else
  674. location_reset_ref(location,LOC_REFERENCE,newsize,left.location.reference.alignment);
  675. { an ansistring needs to be dereferenced }
  676. if is_ansistring(left.resultdef) or
  677. is_widestring(left.resultdef) or
  678. is_unicodestring(left.resultdef) then
  679. begin
  680. if nf_callunique in flags then
  681. internalerror(200304236);
  682. {DM!!!!!}
  683. case left.location.loc of
  684. LOC_REGISTER,
  685. LOC_CREGISTER :
  686. begin
  687. {$ifdef m68k}
  688. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  689. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,location.reference.base);
  690. {$else m68k}
  691. location.reference.base:=left.location.register;
  692. {$endif m68k}
  693. end;
  694. LOC_CREFERENCE,
  695. LOC_REFERENCE :
  696. begin
  697. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  698. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,location.reference.base);
  699. end;
  700. else
  701. internalerror(2002032218);
  702. end;
  703. { check for a zero length string,
  704. we can use the ansistring routine here }
  705. if (cs_check_range in current_settings.localswitches) then
  706. begin
  707. paramanager.getintparaloc(pocall_default,1,paraloc1);
  708. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_ADDR,location.reference.base,paraloc1);
  709. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  710. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  711. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resultdef).stringtypname)+'_CHECKZERO',false);
  712. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  713. end;
  714. { in ansistrings/widestrings S[1] is p<w>char(S)[0] !! }
  715. if is_ansistring(left.resultdef) then
  716. offsetdec:=1
  717. else
  718. offsetdec:=2;
  719. location.reference.alignment:=offsetdec;
  720. dec(location.reference.offset,offsetdec);
  721. end
  722. else if is_dynamic_array(left.resultdef) then
  723. begin
  724. case left.location.loc of
  725. LOC_REGISTER,
  726. LOC_CREGISTER :
  727. location.reference.base:=left.location.register;
  728. LOC_REFERENCE,
  729. LOC_CREFERENCE :
  730. begin
  731. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  732. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  733. left.location.reference,location.reference.base);
  734. end;
  735. else
  736. internalerror(2002032219);
  737. end;
  738. { a dynarray points to the start of a memory block, which
  739. we assume to be always aligned to a multiple of the
  740. pointer size
  741. }
  742. location.reference.alignment:=sizeof(pint);
  743. end
  744. else
  745. location_copy(location,left.location);
  746. { location must be memory }
  747. if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  748. internalerror(200411013);
  749. { offset can only differ from 0 if arraydef }
  750. if (left.resultdef.typ=arraydef) and
  751. not(is_dynamic_array(left.resultdef)) and
  752. (not(is_packed_array(left.resultdef)) or
  753. ((mulsize mod 8 = 0) and
  754. ispowerof2(mulsize div 8,temp)) or
  755. { only orddefs are bitpacked }
  756. not is_ordinal(resultdef)
  757. {$ifndef cpu64bitalu}
  758. or is_64bitint(resultdef)
  759. {$endif not cpu64bitalu}
  760. ) then
  761. dec(location.reference.offset,bytemulsize*tarraydef(left.resultdef).lowrange);
  762. if right.nodetype=ordconstn then
  763. begin
  764. { offset can only differ from 0 if arraydef }
  765. case left.resultdef.typ of
  766. arraydef :
  767. begin
  768. { do not do any range checking when this is an array access to a pointer which has been
  769. typecasted from an array }
  770. if (not (ado_isconvertedpointer in tarraydef(left.resultdef).arrayoptions)) then
  771. begin
  772. if not(is_open_array(left.resultdef)) and
  773. not(is_array_of_const(left.resultdef)) and
  774. not(is_dynamic_array(left.resultdef)) then
  775. begin
  776. if (tordconstnode(right).value.svalue>tarraydef(left.resultdef).highrange) or
  777. (tordconstnode(right).value.svalue<tarraydef(left.resultdef).lowrange) then
  778. begin
  779. { this should be caught in the typecheckpass! (JM) }
  780. if (cs_check_range in current_settings.localswitches) then
  781. CGMessage(parser_e_range_check_error)
  782. else
  783. CGMessage(parser_w_range_check_error);
  784. end;
  785. end
  786. else
  787. begin
  788. { range checking for open and dynamic arrays needs
  789. runtime code }
  790. secondpass(right);
  791. if (cs_check_range in current_settings.localswitches) then
  792. rangecheck_array;
  793. end;
  794. end;
  795. end;
  796. stringdef :
  797. begin
  798. if (cs_check_range in current_settings.localswitches) then
  799. begin
  800. case tstringdef(left.resultdef).stringtype of
  801. { it's the same for ansi- and wide strings }
  802. st_unicodestring,
  803. st_widestring,
  804. st_ansistring:
  805. begin
  806. paramanager.getintparaloc(pocall_default,1,paraloc1);
  807. paramanager.getintparaloc(pocall_default,2,paraloc2);
  808. cg.a_load_const_cgpara(current_asmdata.CurrAsmList,OS_INT,tordconstnode(right).value.svalue,paraloc2);
  809. href:=location.reference;
  810. if not(tf_winlikewidestring in target_info.flags) or
  811. (tstringdef(left.resultdef).stringtype<>st_widestring) then
  812. begin
  813. dec(href.offset,sizeof(pint)-offsetdec);
  814. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_ADDR,href,paraloc1);
  815. end
  816. else
  817. begin
  818. { winlike widestrings have a 4 byte length }
  819. dec(href.offset,4-offsetdec);
  820. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
  821. end;
  822. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  823. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  824. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  825. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resultdef).stringtypname)+'_RANGECHECK',false);
  826. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  827. end;
  828. st_shortstring:
  829. begin
  830. {!!!!!!!!!!!!!!!!!}
  831. { if this one is implemented making use of the high parameter for openshortstrings, update ncgutils.do_get_used_regvars() too (JM) }
  832. end;
  833. st_longstring:
  834. begin
  835. {!!!!!!!!!!!!!!!!!}
  836. end;
  837. end;
  838. end;
  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. location_force_reg(current_asmdata.CurrAsmList,right.location,OS_ADDR,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. begin
  948. { do not do any range checking when this is an array access to a pointer which has been
  949. typecasted from an array }
  950. if (not (ado_isconvertedpointer in tarraydef(left.resultdef).arrayoptions)) then
  951. rangecheck_array
  952. end
  953. else if (left.resultdef.typ=stringdef) then
  954. begin
  955. case tstringdef(left.resultdef).stringtype of
  956. { it's the same for ansi- and wide strings }
  957. st_unicodestring,
  958. st_widestring,
  959. st_ansistring:
  960. begin
  961. paramanager.getintparaloc(pocall_default,1,paraloc1);
  962. paramanager.getintparaloc(pocall_default,2,paraloc2);
  963. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_INT,right.location.register,paraloc2);
  964. href:=location.reference;
  965. dec(href.offset,sizeof(pint)-offsetdec);
  966. href:=location.reference;
  967. if not(tf_winlikewidestring in target_info.flags) or
  968. (tstringdef(left.resultdef).stringtype<>st_widestring) then
  969. begin
  970. dec(href.offset,sizeof(pint)-offsetdec);
  971. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_ADDR,href,paraloc1);
  972. end
  973. else
  974. begin
  975. { winlike widestrings have a 4 byte length }
  976. dec(href.offset,4-offsetdec);
  977. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
  978. end;
  979. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  980. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc2);
  981. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  982. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resultdef).stringtypname)+'_RANGECHECK',false);
  983. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  984. end;
  985. st_shortstring:
  986. begin
  987. {!!!!!!!!!!!!!!!!!}
  988. end;
  989. st_longstring:
  990. begin
  991. {!!!!!!!!!!!!!!!!!}
  992. end;
  993. end;
  994. end;
  995. end;
  996. { insert the register and the multiplication factor in the
  997. reference }
  998. if not is_packed_array(left.resultdef) then
  999. update_reference_reg_mul(right.location.register,mulsize)
  1000. else
  1001. update_reference_reg_packed(right.location.register,mulsize);
  1002. end;
  1003. location.size:=newsize;
  1004. paraloc1.done;
  1005. paraloc2.done;
  1006. end;
  1007. begin
  1008. cloadvmtaddrnode:=tcgloadvmtaddrnode;
  1009. cloadparentfpnode:=tcgloadparentfpnode;
  1010. caddrnode:=tcgaddrnode;
  1011. cderefnode:=tcgderefnode;
  1012. csubscriptnode:=tcgsubscriptnode;
  1013. cwithnode:=tcgwithnode;
  1014. cvecnode:=tcgvecnode;
  1015. end.